mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			1464 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			1464 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			Java
		
	
	
	
/* CopyOnWriteArrayList.java
 | 
						|
   Copyright (C) 2006 Free Software Foundation
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
package java.util.concurrent;
 | 
						|
 | 
						|
import java.io.IOException;
 | 
						|
import java.io.ObjectInputStream;
 | 
						|
import java.io.ObjectOutputStream;
 | 
						|
import java.io.Serializable;
 | 
						|
 | 
						|
import java.lang.reflect.Array;
 | 
						|
 | 
						|
import java.util.AbstractList;
 | 
						|
import java.util.Arrays;
 | 
						|
import java.util.Collection;
 | 
						|
import java.util.ConcurrentModificationException;
 | 
						|
import java.util.Iterator;
 | 
						|
import java.util.List;
 | 
						|
import java.util.ListIterator;
 | 
						|
import java.util.NoSuchElementException;
 | 
						|
import java.util.RandomAccess;
 | 
						|
 | 
						|
/**
 | 
						|
 * A thread-safe implementation of an ArrayList. A CopyOnWriteArrayList is
 | 
						|
 * as special ArrayList which performs copies of the underlying storage
 | 
						|
 * each time a write (<code>remove</code>, <code>add</code> etc..) operation
 | 
						|
 * is performed.<br />
 | 
						|
 * <br />
 | 
						|
 * The update operation in this class run usually in <code>O(n)</code> or worse,
 | 
						|
 * but traversal operations are fast and efficient, especially when running in
 | 
						|
 * a multi-thread environment without the need to design complex synchronize
 | 
						|
 * mechanisms.<br />
 | 
						|
 * <br />
 | 
						|
 * <code>Iterator</code>s in this class work on a snapshot of the backing store
 | 
						|
 * at the moment the iterator itself was created, hence the iterator will not
 | 
						|
 * reflect changes in the underlying storage. Thus, update operation on the
 | 
						|
 * <code>Iterator</code>s are not supported, but as interferences from other
 | 
						|
 * threads are impossible, no <code>ConcurrentModificationException</code>
 | 
						|
 * will be ever thrown from within the <code>Iterator</code>.
 | 
						|
 * <br /><br />
 | 
						|
 * This class is especially useful when used with event handling, like the
 | 
						|
 * following code demonstrates:<br />
 | 
						|
 * <code><pre>
 | 
						|
 *
 | 
						|
 * CopyOnWriteArrayList<EventListener> listeners =
 | 
						|
 *   new CopyOnWriteArrayList<EventListener>();
 | 
						|
 *
 | 
						|
 * [...]
 | 
						|
 *
 | 
						|
 * for (final EventListener listener : listeners)
 | 
						|
 *   {
 | 
						|
 *     Runnable dispatcher = new Runnable() {
 | 
						|
 *       public void run()
 | 
						|
 *       {
 | 
						|
 *         listener.preferenceChange(event);
 | 
						|
 *       }
 | 
						|
 *     };
 | 
						|
 *
 | 
						|
 *     Executor executor = Executors.newSingleThreadExecutor();
 | 
						|
 *     executor.execute(dispatcher);
 | 
						|
 *   }
 | 
						|
 * </pre></code>
 | 
						|
 *
 | 
						|
 * @since 1.5
 | 
						|
 */
 | 
						|
public class CopyOnWriteArrayList<E>
 | 
						|
  implements List<E>, RandomAccess, Cloneable, Serializable
 | 
						|
{
 | 
						|
  /**
 | 
						|
   *
 | 
						|
   */
 | 
						|
  private static final long serialVersionUID = 8673264195747942595L;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Where the data is stored.
 | 
						|
   */
 | 
						|
  private transient E[] data;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Construct a new ArrayList with the default capacity (16).
 | 
						|
   */
 | 
						|
  public CopyOnWriteArrayList()
 | 
						|
  {
 | 
						|
    data = (E[]) new Object[0];
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Construct a new ArrayList, and initialize it with the elements in the
 | 
						|
   * supplied Collection. The initial capacity is 110% of the Collection's size.
 | 
						|
   *
 | 
						|
   * @param c
 | 
						|
   *          the collection whose elements will initialize this list
 | 
						|
   * @throws NullPointerException
 | 
						|
   *           if c is null
 | 
						|
   */
 | 
						|
  public CopyOnWriteArrayList(Collection< ? extends E> c)
 | 
						|
  {
 | 
						|
    // FIXME ... correct?  use c.toArray()
 | 
						|
    data = (E[]) new Object[c.size()];
 | 
						|
    int index = 0;
 | 
						|
    for (E value : c)
 | 
						|
      data[index++] = value;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Construct a new ArrayList, and initialize it with the elements in the
 | 
						|
   * supplied array.
 | 
						|
   *
 | 
						|
   * @param array
 | 
						|
   *          the array used to initialize this list
 | 
						|
   * @throws NullPointerException
 | 
						|
   *           if array is null
 | 
						|
   */
 | 
						|
  public CopyOnWriteArrayList(E[] array)
 | 
						|
  {
 | 
						|
    data = (E[]) array.clone();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the number of elements in this list.
 | 
						|
   *
 | 
						|
   * @return the list size
 | 
						|
   */
 | 
						|
  public int size()
 | 
						|
  {
 | 
						|
    return data.length;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Checks if the list is empty.
 | 
						|
   *
 | 
						|
   * @return true if there are no elements
 | 
						|
   */
 | 
						|
  public boolean isEmpty()
 | 
						|
  {
 | 
						|
    return data.length == 0;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns true if element is in this ArrayList.
 | 
						|
   *
 | 
						|
   * @param e
 | 
						|
   *          the element whose inclusion in the List is being tested
 | 
						|
   * @return true if the list contains e
 | 
						|
   */
 | 
						|
  public boolean contains(Object e)
 | 
						|
  {
 | 
						|
    return indexOf(e) != -1;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Tests whether this collection contains all the elements in a given
 | 
						|
   * collection. This implementation iterates over the given collection,
 | 
						|
   * testing whether each element is contained in this collection. If any one
 | 
						|
   * is not, false is returned. Otherwise true is returned.
 | 
						|
   *
 | 
						|
   * @param c the collection to test against
 | 
						|
   * @return true if this collection contains all the elements in the given
 | 
						|
   *         collection
 | 
						|
   * @throws NullPointerException if the given collection is null
 | 
						|
   * @see #contains(Object)
 | 
						|
   */
 | 
						|
  public boolean containsAll(Collection<?> c)
 | 
						|
  {
 | 
						|
    Iterator<?> itr = c.iterator();
 | 
						|
    int pos = c.size();
 | 
						|
    while (--pos >= 0)
 | 
						|
      if (!contains(itr.next()))
 | 
						|
        return false;
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the lowest index at which element appears in this List, or -1 if it
 | 
						|
   * does not appear.
 | 
						|
   *
 | 
						|
   * @param e
 | 
						|
   *          the element whose inclusion in the List is being tested
 | 
						|
   * @return the index where e was found
 | 
						|
   */
 | 
						|
  public int indexOf(Object e)
 | 
						|
  {
 | 
						|
    E[] data = this.data;
 | 
						|
    for (int i = 0; i < data.length; i++)
 | 
						|
      if (equals(e, data[i]))
 | 
						|
        return i;
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Return the lowest index greater equal <code>index</code> at which
 | 
						|
   * <code>e</code> appears in this List, or -1 if it does not
 | 
						|
   * appear.
 | 
						|
   *
 | 
						|
   * @param e the element whose inclusion in the list is being tested
 | 
						|
   * @param index the index at which the search begins
 | 
						|
   * @return the index where <code>e</code> was found
 | 
						|
   */
 | 
						|
  public int indexOf(E e, int index)
 | 
						|
  {
 | 
						|
    E[] data = this.data;
 | 
						|
 | 
						|
    for (int i = index; i < data.length; i++)
 | 
						|
      if (equals(e, data[i]))
 | 
						|
        return i;
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the highest index at which element appears in this List, or -1 if
 | 
						|
   * it does not appear.
 | 
						|
   *
 | 
						|
   * @param e
 | 
						|
   *          the element whose inclusion in the List is being tested
 | 
						|
   * @return the index where e was found
 | 
						|
   */
 | 
						|
  public int lastIndexOf(Object e)
 | 
						|
  {
 | 
						|
    E[] data = this.data;
 | 
						|
    for (int i = data.length - 1; i >= 0; i--)
 | 
						|
      if (equals(e, data[i]))
 | 
						|
        return i;
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns the highest index lesser equal <code>index</code> at
 | 
						|
   * which <code>e</code> appears in this List, or -1 if it does not
 | 
						|
   * appear.
 | 
						|
   *
 | 
						|
   * @param e the element whose inclusion in the list is being tested
 | 
						|
   * @param index the index at which the search begins
 | 
						|
   * @return the index where <code>e</code> was found
 | 
						|
   */
 | 
						|
  public int lastIndexOf(E e, int index)
 | 
						|
  {
 | 
						|
    E[] data = this.data;
 | 
						|
 | 
						|
    for (int i = index; i >= 0; i--)
 | 
						|
      if (equals(e, data[i]))
 | 
						|
        return i;
 | 
						|
    return -1;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Creates a shallow copy of this ArrayList (elements are not cloned).
 | 
						|
   *
 | 
						|
   * @return the cloned object
 | 
						|
   */
 | 
						|
  public Object clone()
 | 
						|
  {
 | 
						|
    CopyOnWriteArrayList<E> clone = null;
 | 
						|
    try
 | 
						|
      {
 | 
						|
        clone = (CopyOnWriteArrayList<E>) super.clone();
 | 
						|
      }
 | 
						|
    catch (CloneNotSupportedException e)
 | 
						|
      {
 | 
						|
        // Impossible to get here.
 | 
						|
      }
 | 
						|
    return clone;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns an Object array containing all of the elements in this ArrayList.
 | 
						|
   * The array is independent of this list.
 | 
						|
   *
 | 
						|
   * @return an array representation of this list
 | 
						|
   */
 | 
						|
  public Object[] toArray()
 | 
						|
  {
 | 
						|
    E[] data = this.data;
 | 
						|
    E[] array = (E[]) new Object[data.length];
 | 
						|
    System.arraycopy(data, 0, array, 0, data.length);
 | 
						|
    return array;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Returns an Array whose component type is the runtime component type of the
 | 
						|
   * passed-in Array. The returned Array is populated with all of the elements
 | 
						|
   * in this ArrayList. If the passed-in Array is not large enough to store all
 | 
						|
   * of the elements in this List, a new Array will be created and returned; if
 | 
						|
   * the passed-in Array is <i>larger</i> than the size of this List, then
 | 
						|
   * size() index will be set to null.
 | 
						|
   *
 | 
						|
   * @param a
 | 
						|
   *          the passed-in Array
 | 
						|
   * @return an array representation of this list
 | 
						|
   * @throws ArrayStoreException
 | 
						|
   *           if the runtime type of a does not allow an element in this list
 | 
						|
   * @throws NullPointerException
 | 
						|
   *           if a is null
 | 
						|
   */
 | 
						|
  public <T> T[] toArray(T[] a)
 | 
						|
  {
 | 
						|
    E[] data = this.data;
 | 
						|
    if (a.length < data.length)
 | 
						|
      a = (T[]) Array.newInstance(a.getClass().getComponentType(), data.length);
 | 
						|
    else if (a.length > data.length)
 | 
						|
      a[data.length] = null;
 | 
						|
    System.arraycopy(data, 0, a, 0, data.length);
 | 
						|
    return a;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Retrieves the element at the user-supplied index.
 | 
						|
   *
 | 
						|
   * @param index
 | 
						|
   *          the index of the element we are fetching
 | 
						|
   * @throws IndexOutOfBoundsException
 | 
						|
   *           if index < 0 || index >= size()
 | 
						|
   */
 | 
						|
  public E get(int index)
 | 
						|
  {
 | 
						|
    return data[index];
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Sets the element at the specified index. The new element, e, can be an
 | 
						|
   * object of any type or null.
 | 
						|
   *
 | 
						|
   * @param index
 | 
						|
   *          the index at which the element is being set
 | 
						|
   * @param e
 | 
						|
   *          the element to be set
 | 
						|
   * @return the element previously at the specified index
 | 
						|
   * @throws IndexOutOfBoundsException
 | 
						|
   *           if index < 0 || index >= 0
 | 
						|
   */
 | 
						|
  public synchronized E set(int index, E e)
 | 
						|
  {
 | 
						|
    E result = data[index];
 | 
						|
    E[] newData = (E[]) data.clone();
 | 
						|
    newData[index] = e;
 | 
						|
    data = newData;
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Appends the supplied element to the end of this list. The element, e, can
 | 
						|
   * be an object of any type or null.
 | 
						|
   *
 | 
						|
   * @param e
 | 
						|
   *          the element to be appended to this list
 | 
						|
   * @return true, the add will always succeed
 | 
						|
   */
 | 
						|
  public synchronized boolean add(E e)
 | 
						|
  {
 | 
						|
    E[] data = this.data;
 | 
						|
    E[] newData = (E[]) new Object[data.length + 1];
 | 
						|
    System.arraycopy(data, 0, newData, 0, data.length);
 | 
						|
    newData[data.length] = e;
 | 
						|
    this.data = newData;
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Adds the supplied element at the specified index, shifting all elements
 | 
						|
   * currently at that index or higher one to the right. The element, e, can be
 | 
						|
   * an object of any type or null.
 | 
						|
   *
 | 
						|
   * @param index
 | 
						|
   *          the index at which the element is being added
 | 
						|
   * @param e
 | 
						|
   *          the item being added
 | 
						|
   * @throws IndexOutOfBoundsException
 | 
						|
   *           if index < 0 || index > size()
 | 
						|
   */
 | 
						|
  public synchronized void add(int index, E e)
 | 
						|
  {
 | 
						|
    E[] data = this.data;
 | 
						|
    E[] newData = (E[]) new Object[data.length + 1];
 | 
						|
    System.arraycopy(data, 0, newData, 0, index);
 | 
						|
    newData[index] = e;
 | 
						|
    System.arraycopy(data, index, newData, index + 1, data.length - index);
 | 
						|
    this.data = newData;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Removes the element at the user-supplied index.
 | 
						|
   *
 | 
						|
   * @param index
 | 
						|
   *          the index of the element to be removed
 | 
						|
   * @return the removed Object
 | 
						|
   * @throws IndexOutOfBoundsException
 | 
						|
   *           if index < 0 || index >= size()
 | 
						|
   */
 | 
						|
  public synchronized E remove(int index)
 | 
						|
  {
 | 
						|
    if (index < 0 || index >= this.size())
 | 
						|
      throw new IndexOutOfBoundsException("index = " +  index);
 | 
						|
 | 
						|
    E[] snapshot = this.data;
 | 
						|
    E[] newData = (E[]) new Object[snapshot.length - 1];
 | 
						|
 | 
						|
    E result = snapshot[index];
 | 
						|
 | 
						|
    if (index > 0)
 | 
						|
      System.arraycopy(snapshot, 0, newData, 0, index);
 | 
						|
 | 
						|
    System.arraycopy(snapshot, index + 1, newData, index,
 | 
						|
                     snapshot.length - index - 1);
 | 
						|
 | 
						|
    this.data = newData;
 | 
						|
 | 
						|
    return result;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Remove the first occurrence, if any, of the given object from this list,
 | 
						|
   * returning <code>true</code> if the object was removed, <code>false</code>
 | 
						|
   * otherwise.
 | 
						|
   *
 | 
						|
   * @param element the object to be removed.
 | 
						|
   * @return true if element was removed, false otherwise. false means also that
 | 
						|
   * the underlying storage was unchanged after this operation concluded.
 | 
						|
   */
 | 
						|
  public synchronized boolean remove(Object element)
 | 
						|
  {
 | 
						|
    E[] snapshot = this.data;
 | 
						|
    int len = snapshot.length;
 | 
						|
 | 
						|
    if (len == 0)
 | 
						|
      return false;
 | 
						|
 | 
						|
    E[] newData = (E[]) new Object[len - 1];
 | 
						|
 | 
						|
    // search the element to remove while filling the backup array
 | 
						|
    // this way we can run this method in O(n)
 | 
						|
    int elementIndex = -1;
 | 
						|
    for (int i = 0; i < snapshot.length; i++)
 | 
						|
      {
 | 
						|
        if (equals(element, snapshot[i]))
 | 
						|
          {
 | 
						|
            elementIndex = i;
 | 
						|
            break;
 | 
						|
          }
 | 
						|
 | 
						|
        if (i < newData.length)
 | 
						|
          newData[i] = snapshot[i];
 | 
						|
      }
 | 
						|
 | 
						|
    if (elementIndex < 0)
 | 
						|
      return false;
 | 
						|
 | 
						|
    System.arraycopy(snapshot, elementIndex + 1, newData, elementIndex,
 | 
						|
                     snapshot.length - elementIndex - 1);
 | 
						|
    this.data = newData;
 | 
						|
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Removes all the elements contained in the given collection.
 | 
						|
   * This method removes the elements that are contained in both
 | 
						|
   * this list and in the given collection.
 | 
						|
   *
 | 
						|
   * @param c the collection containing the elements to be removed from this
 | 
						|
   * list.
 | 
						|
   * @return true if at least one element was removed, indicating that
 | 
						|
   * the list internal storage changed as a result, false otherwise.
 | 
						|
   */
 | 
						|
  public synchronized boolean removeAll(Collection<?> c)
 | 
						|
  {
 | 
						|
    if (c.size() == 0)
 | 
						|
      return false;
 | 
						|
 | 
						|
    E [] snapshot = this.data;
 | 
						|
    E [] storage = (E[]) new Object[this.data.length];
 | 
						|
    boolean changed = false;
 | 
						|
 | 
						|
    int length = 0;
 | 
						|
    for (E element : snapshot)
 | 
						|
      {
 | 
						|
        // copy all the elements, including null values
 | 
						|
        // if the collection can hold it
 | 
						|
        // FIXME: slow operation
 | 
						|
        if (c.contains(element))
 | 
						|
          changed = true;
 | 
						|
        else
 | 
						|
          storage[length++] = element;
 | 
						|
      }
 | 
						|
 | 
						|
    if (!changed)
 | 
						|
      return false;
 | 
						|
 | 
						|
    E[] newData = (E[]) new Object[length];
 | 
						|
    System.arraycopy(storage, 0, newData, 0, length);
 | 
						|
 | 
						|
    this.data = newData;
 | 
						|
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Removes all the elements that are not in the passed collection.
 | 
						|
   * If the collection is void, this method has the same effect of
 | 
						|
   * <code>clear()</code>.
 | 
						|
   * Please, note that this method is extremely slow (unless the argument has
 | 
						|
   * <code>size == 0</code>) and has bad performance is both space and time
 | 
						|
   * usage.
 | 
						|
   *
 | 
						|
   * @param c the collection containing the elements to be retained by this
 | 
						|
   * list.
 | 
						|
   * @return true the list internal storage changed as a result of this
 | 
						|
   * operation, false otherwise.
 | 
						|
   */
 | 
						|
  public synchronized boolean retainAll(Collection<?> c)
 | 
						|
  {
 | 
						|
    // if the given collection does not contain elements
 | 
						|
    // we remove all the elements from our storage
 | 
						|
    if (c.size() == 0)
 | 
						|
      {
 | 
						|
        this.clear();
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
 | 
						|
    E [] snapshot = this.data;
 | 
						|
    E [] storage = (E[]) new Object[this.data.length];
 | 
						|
 | 
						|
    int length = 0;
 | 
						|
    for (E element : snapshot)
 | 
						|
      {
 | 
						|
        if (c.contains(element))
 | 
						|
          storage[length++] = element;
 | 
						|
      }
 | 
						|
 | 
						|
    // means we retained all the elements previously in our storage
 | 
						|
    // we are running already slow here, but at least we avoid copying
 | 
						|
    // another array and changing the internal storage
 | 
						|
    if (length == snapshot.length)
 | 
						|
      return false;
 | 
						|
 | 
						|
    E[] newData = (E[]) new Object[length];
 | 
						|
    System.arraycopy(storage, 0, newData, 0, length);
 | 
						|
 | 
						|
    this.data = newData;
 | 
						|
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Removes all elements from this List
 | 
						|
   */
 | 
						|
  public synchronized void clear()
 | 
						|
  {
 | 
						|
    data = (E[]) new Object[0];
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Add each element in the supplied Collection to this List. It is undefined
 | 
						|
   * what happens if you modify the list while this is taking place; for
 | 
						|
   * example, if the collection contains this list. c can contain objects of any
 | 
						|
   * type, as well as null values.
 | 
						|
   *
 | 
						|
   * @param c
 | 
						|
   *          a Collection containing elements to be added to this List
 | 
						|
   * @return true if the list was modified, in other words c is not empty
 | 
						|
   * @throws NullPointerException
 | 
						|
   *           if c is null
 | 
						|
   */
 | 
						|
  public synchronized boolean addAll(Collection< ? extends E> c)
 | 
						|
  {
 | 
						|
    return addAll(data.length, c);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Add all elements in the supplied collection, inserting them beginning at
 | 
						|
   * the specified index. c can contain objects of any type, as well as null
 | 
						|
   * values.
 | 
						|
   *
 | 
						|
   * @param index
 | 
						|
   *          the index at which the elements will be inserted
 | 
						|
   * @param c
 | 
						|
   *          the Collection containing the elements to be inserted
 | 
						|
   * @throws IndexOutOfBoundsException
 | 
						|
   *           if index < 0 || index > 0
 | 
						|
   * @throws NullPointerException
 | 
						|
   *           if c is null
 | 
						|
   */
 | 
						|
  public synchronized boolean addAll(int index, Collection< ? extends E> c)
 | 
						|
  {
 | 
						|
    if (index < 0 || index > this.size())
 | 
						|
      throw new IndexOutOfBoundsException("index = " +  index);
 | 
						|
 | 
						|
    int csize = c.size();
 | 
						|
    if (csize == 0)
 | 
						|
      return false;
 | 
						|
 | 
						|
    E[] data = this.data;
 | 
						|
    Iterator<? extends E> itr = c.iterator();
 | 
						|
 | 
						|
    E[] newData = (E[]) new Object[data.length + csize];
 | 
						|
 | 
						|
    // avoid this call at all if we were asked to put the elements at the
 | 
						|
    // beginning of our storage
 | 
						|
    if (index != 0)
 | 
						|
      System.arraycopy(data, 0, newData, 0, index);
 | 
						|
 | 
						|
    int itemsLeft = index;
 | 
						|
 | 
						|
    for (E value : c)
 | 
						|
      newData[index++] = value;
 | 
						|
 | 
						|
    // now copy the remaining elements
 | 
						|
    System.arraycopy(data, itemsLeft, newData, 0, data.length - itemsLeft);
 | 
						|
 | 
						|
    this.data = newData;
 | 
						|
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Adds an element if the list does not contains it already.
 | 
						|
   *
 | 
						|
   * @param val the element to add to the list.
 | 
						|
   * @return true if the element was added, false otherwise.
 | 
						|
   */
 | 
						|
  public synchronized boolean addIfAbsent(E val)
 | 
						|
  {
 | 
						|
    if (contains(val))
 | 
						|
      return false;
 | 
						|
    add(val);
 | 
						|
    return true;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Adds all the element from the given collection that are not already
 | 
						|
   * in this list.
 | 
						|
   *
 | 
						|
   * @param c the Collection containing the elements to be inserted
 | 
						|
   * @return true the list internal storage changed as a result of this
 | 
						|
   * operation, false otherwise.
 | 
						|
   */
 | 
						|
  public synchronized int addAllAbsent(Collection<? extends E> c)
 | 
						|
  {
 | 
						|
    int size = c.size();
 | 
						|
    if (size == 0)
 | 
						|
      return 0;
 | 
						|
 | 
						|
    E [] snapshot = this.data;
 | 
						|
    E [] storage = (E[]) new Object[size];
 | 
						|
 | 
						|
    size = 0;
 | 
						|
    for (E val : c)
 | 
						|
      {
 | 
						|
        if (!this.contains(val))
 | 
						|
          storage[size++] = val;
 | 
						|
      }
 | 
						|
 | 
						|
    if (size == 0)
 | 
						|
      return 0;
 | 
						|
 | 
						|
    // append storage to data
 | 
						|
    E [] newData = (E[]) new Object[snapshot.length + size];
 | 
						|
 | 
						|
    System.arraycopy(snapshot, 0, newData, 0, snapshot.length);
 | 
						|
    System.arraycopy(storage, 0, newData, snapshot.length, size);
 | 
						|
 | 
						|
    this.data = newData;
 | 
						|
 | 
						|
    return size;
 | 
						|
  }
 | 
						|
 | 
						|
  public String toString()
 | 
						|
  {
 | 
						|
    return Arrays.toString(this.data);
 | 
						|
  }
 | 
						|
 | 
						|
  public boolean equals(Object o)
 | 
						|
  {
 | 
						|
    if (o == null)
 | 
						|
      return false;
 | 
						|
 | 
						|
    if (this == o)
 | 
						|
      return true;
 | 
						|
 | 
						|
    // let's see if 'o' is a list, if so, we need to compare the elements
 | 
						|
    // as returned by the iterator
 | 
						|
    if (o instanceof List)
 | 
						|
      {
 | 
						|
        List<?> source = (List<?>) o;
 | 
						|
 | 
						|
        if (source.size() != this.size())
 | 
						|
          return false;
 | 
						|
 | 
						|
        Iterator<?> sourceIterator = source.iterator();
 | 
						|
        for (E element : this)
 | 
						|
          {
 | 
						|
            if (!element.equals(sourceIterator.next()))
 | 
						|
              return false;
 | 
						|
          }
 | 
						|
 | 
						|
        return true;
 | 
						|
      }
 | 
						|
 | 
						|
    return false;
 | 
						|
  }
 | 
						|
 | 
						|
  public int hashCode()
 | 
						|
  {
 | 
						|
    // see http://java.sun.com/6/docs/api/java/util/List.html#hashcode()
 | 
						|
    int hashcode = 1;
 | 
						|
    for (E element : this)
 | 
						|
      {
 | 
						|
        hashcode = 31 * hashcode + (element == null ? 0 : element.hashCode());
 | 
						|
      }
 | 
						|
    return hashcode;
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Return an Iterator containing the elements of this list.
 | 
						|
   * The Iterator uses a snapshot of the state of the internal storage
 | 
						|
   * at the moment this method is called and does <strong>not</strong> support
 | 
						|
   * update operations, so no synchronization is needed to traverse the
 | 
						|
   * iterator.
 | 
						|
   *
 | 
						|
   * @return an Iterator containing the elements of this list in sequence.
 | 
						|
   */
 | 
						|
  public Iterator<E> iterator()
 | 
						|
  {
 | 
						|
    return new Iterator<E>()
 | 
						|
    {
 | 
						|
      E [] iteratorData = CopyOnWriteArrayList.this.data;
 | 
						|
      int currentElement = 0;
 | 
						|
 | 
						|
      public boolean hasNext()
 | 
						|
      {
 | 
						|
        return (currentElement < iteratorData.length);
 | 
						|
      }
 | 
						|
 | 
						|
      public E next()
 | 
						|
      {
 | 
						|
        return iteratorData[currentElement++];
 | 
						|
      }
 | 
						|
 | 
						|
      public void remove()
 | 
						|
      {
 | 
						|
        throw new UnsupportedOperationException("updating of elements in " +
 | 
						|
                                                "iterators is not supported " +
 | 
						|
                                                "by this class");
 | 
						|
      }
 | 
						|
    };
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Return a ListIterator containing the elements of this list.
 | 
						|
   * The Iterator uses a snapshot of the state of the internal storage
 | 
						|
   * at the moment this method is called and does <strong>not</strong> support
 | 
						|
   * update operations, so no synchronization is needed to traverse the
 | 
						|
   * iterator.
 | 
						|
   *
 | 
						|
   * @return a ListIterator containing the elements of this list in sequence.
 | 
						|
   */
 | 
						|
  public ListIterator<E> listIterator()
 | 
						|
  {
 | 
						|
    return listIterator(0);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Return a ListIterator over the elements of this list starting at
 | 
						|
   * the specified index.  An initial call to {@code next()} will thus
 | 
						|
   * return the element at {@code index}, while an initial call to
 | 
						|
   * {@code previous()} will return the element at {@code index-1}.  The
 | 
						|
   * Iterator uses a snapshot of the state of the internal storage
 | 
						|
   * at the moment this method is called and does <strong>not</strong> support
 | 
						|
   * update operations, so no synchronization is needed to traverse the
 | 
						|
   * iterator.
 | 
						|
   *
 | 
						|
   * @param index the index at which to start iterating.
 | 
						|
   * @return a ListIterator containing the elements of this list in sequence.
 | 
						|
   */
 | 
						|
  public ListIterator<E> listIterator(final int index)
 | 
						|
  {
 | 
						|
    if (index < 0 || index > size())
 | 
						|
      throw new IndexOutOfBoundsException("Index: " + index + ", Size:"
 | 
						|
                                          + size());
 | 
						|
 | 
						|
    return new ListIterator<E>()
 | 
						|
    {
 | 
						|
      E [] iteratorData = CopyOnWriteArrayList.this.data;
 | 
						|
      int currentElement = index;
 | 
						|
 | 
						|
      public void add(E o)
 | 
						|
      {
 | 
						|
        throw new UnsupportedOperationException("updating of elements in " +
 | 
						|
                                                "iterators is not supported " +
 | 
						|
                                                "by this class");
 | 
						|
      }
 | 
						|
 | 
						|
      public boolean hasNext()
 | 
						|
      {
 | 
						|
        return (currentElement < iteratorData.length);
 | 
						|
      }
 | 
						|
 | 
						|
      public boolean hasPrevious()
 | 
						|
      {
 | 
						|
        return (currentElement > 0);
 | 
						|
      }
 | 
						|
 | 
						|
      public E next()
 | 
						|
      {
 | 
						|
        if (hasNext() == false)
 | 
						|
          throw new java.util.NoSuchElementException();
 | 
						|
 | 
						|
        return iteratorData[currentElement++];
 | 
						|
      }
 | 
						|
 | 
						|
      public int nextIndex()
 | 
						|
      {
 | 
						|
        return (currentElement + 1);
 | 
						|
      }
 | 
						|
 | 
						|
      public E previous()
 | 
						|
      {
 | 
						|
        if (hasPrevious() == false)
 | 
						|
          throw new java.util.NoSuchElementException();
 | 
						|
 | 
						|
        return iteratorData[--currentElement];
 | 
						|
      }
 | 
						|
 | 
						|
      public int previousIndex()
 | 
						|
      {
 | 
						|
        return (currentElement - 1);
 | 
						|
      }
 | 
						|
 | 
						|
      public void remove()
 | 
						|
      {
 | 
						|
        throw new UnsupportedOperationException("updating of elements in " +
 | 
						|
                                                "iterators is not supported " +
 | 
						|
                                                "by this class");
 | 
						|
      }
 | 
						|
 | 
						|
      public void set(E o)
 | 
						|
      {
 | 
						|
        throw new UnsupportedOperationException("updating of elements in " +
 | 
						|
                                                "iterators is not supported " +
 | 
						|
                                                "by this class");
 | 
						|
      }
 | 
						|
 | 
						|
    };
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Obtain a List view of a subsection of this list, from fromIndex
 | 
						|
   * (inclusive) to toIndex (exclusive). If the two indices are equal, the
 | 
						|
   * sublist is empty. The returned list should be modifiable if and only
 | 
						|
   * if this list is modifiable. Changes to the returned list should be
 | 
						|
   * reflected in this list. If this list is structurally modified in
 | 
						|
   * any way other than through the returned list, the result of any subsequent
 | 
						|
   * operations on the returned list is undefined.
 | 
						|
   * <p>
 | 
						|
   *
 | 
						|
   * This implementation returns a subclass of AbstractList. It stores, in
 | 
						|
   * private fields, the offset and size of the sublist, and the expected
 | 
						|
   * modCount of the backing list. If the backing list implements RandomAccess,
 | 
						|
   * the sublist will also.
 | 
						|
   * <p>
 | 
						|
   *
 | 
						|
   * The subclass's <code>set(int, Object)</code>, <code>get(int)</code>,
 | 
						|
   * <code>add(int, Object)</code>, <code>remove(int)</code>,
 | 
						|
   * <code>addAll(int, Collection)</code> and
 | 
						|
   * <code>removeRange(int, int)</code> methods all delegate to the
 | 
						|
   * corresponding methods on the backing abstract list, after
 | 
						|
   * bounds-checking the index and adjusting for the offset. The
 | 
						|
   * <code>addAll(Collection c)</code> method merely returns addAll(size, c).
 | 
						|
   * The <code>listIterator(int)</code> method returns a "wrapper object"
 | 
						|
   * over a list iterator on the backing list, which is created with the
 | 
						|
   * corresponding method on the backing list. The <code>iterator()</code>
 | 
						|
   * method merely returns listIterator(), and the <code>size()</code> method
 | 
						|
   * merely returns the subclass's size field.
 | 
						|
   * <p>
 | 
						|
   *
 | 
						|
   * All methods first check to see if the actual modCount of the backing
 | 
						|
   * list is equal to its expected value, and throw a
 | 
						|
   * ConcurrentModificationException if it is not.
 | 
						|
   *
 | 
						|
   * @param fromIndex the index that the returned list should start from
 | 
						|
   *        (inclusive)
 | 
						|
   * @param toIndex the index that the returned list should go to (exclusive)
 | 
						|
   * @return a List backed by a subsection of this list
 | 
						|
   * @throws IndexOutOfBoundsException if fromIndex < 0
 | 
						|
   *         || toIndex > size()
 | 
						|
   * @throws IndexOutOfBoundsException if fromIndex > toIndex
 | 
						|
   * @see ConcurrentModificationException
 | 
						|
   * @see RandomAccess
 | 
						|
   */
 | 
						|
  public synchronized List<E> subList(int fromIndex, int toIndex)
 | 
						|
  {
 | 
						|
    // This follows the specification of AbstractList, but is inconsistent
 | 
						|
    // with the one in List. Don't you love Sun's inconsistencies?
 | 
						|
    if (fromIndex > toIndex)
 | 
						|
      throw new IndexOutOfBoundsException(fromIndex + " > " + toIndex);
 | 
						|
    if (fromIndex < 0 || toIndex > size())
 | 
						|
      throw new IndexOutOfBoundsException();
 | 
						|
 | 
						|
    if (this instanceof RandomAccess)
 | 
						|
      return new RandomAccessSubList<E>(this, fromIndex, toIndex);
 | 
						|
    return new SubList<E>(this, fromIndex, toIndex);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * This class follows the implementation requirements set forth in
 | 
						|
   * {@link AbstractList#subList(int, int)}. It matches Sun's implementation
 | 
						|
   * by using a non-public top-level class in the same package.
 | 
						|
   *
 | 
						|
   * @author Original author unknown
 | 
						|
   * @author Eric Blake (ebb9@email.byu.edu)
 | 
						|
   */
 | 
						|
  private static class SubList<E>
 | 
						|
    extends AbstractList<E>
 | 
						|
  {
 | 
						|
    // Package visible, for use by iterator.
 | 
						|
    /** The original list. */
 | 
						|
    final CopyOnWriteArrayList<E> backingList;
 | 
						|
    /** The index of the first element of the sublist. */
 | 
						|
    final int offset;
 | 
						|
    /** The size of the sublist. */
 | 
						|
    int size;
 | 
						|
    /** The backing data */
 | 
						|
    E[] data;
 | 
						|
 | 
						|
    /**
 | 
						|
     * Construct the sublist.
 | 
						|
     *
 | 
						|
     * @param backing the list this comes from
 | 
						|
     * @param fromIndex the lower bound, inclusive
 | 
						|
     * @param toIndex the upper bound, exclusive
 | 
						|
     */
 | 
						|
    SubList(CopyOnWriteArrayList<E> backing, int fromIndex, int toIndex)
 | 
						|
    {
 | 
						|
      backingList = backing;
 | 
						|
      data = backing.data;
 | 
						|
      offset = fromIndex;
 | 
						|
      size = toIndex - fromIndex;
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * This method checks the two modCount fields to ensure that there has
 | 
						|
     * not been a concurrent modification, returning if all is okay.
 | 
						|
     *
 | 
						|
     * @throws ConcurrentModificationException if the backing list has been
 | 
						|
     *         modified externally to this sublist
 | 
						|
     */
 | 
						|
    // This can be inlined. Package visible, for use by iterator.
 | 
						|
    void checkMod()
 | 
						|
    {
 | 
						|
      if (data != backingList.data)
 | 
						|
        throw new ConcurrentModificationException();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * This method checks that a value is between 0 and size (inclusive). If
 | 
						|
     * it is not, an exception is thrown.
 | 
						|
     *
 | 
						|
     * @param index the value to check
 | 
						|
     * @throws IndexOutOfBoundsException if index < 0 || index > size()
 | 
						|
     */
 | 
						|
    // This will get inlined, since it is private.
 | 
						|
    private void checkBoundsInclusive(int index)
 | 
						|
    {
 | 
						|
      if (index < 0 || index > size)
 | 
						|
        throw new IndexOutOfBoundsException("Index: " + index +
 | 
						|
                                            ", Size:" + size);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * This method checks that a value is between 0 (inclusive) and size
 | 
						|
     * (exclusive). If it is not, an exception is thrown.
 | 
						|
     *
 | 
						|
     * @param index the value to check
 | 
						|
     * @throws IndexOutOfBoundsException if index < 0 || index >= size()
 | 
						|
     */
 | 
						|
    // This will get inlined, since it is private.
 | 
						|
    private void checkBoundsExclusive(int index)
 | 
						|
    {
 | 
						|
      if (index < 0 || index >= size)
 | 
						|
        throw new IndexOutOfBoundsException("Index: " + index +
 | 
						|
                                            ", Size:" + size);
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Specified by AbstractList.subList to return the private field size.
 | 
						|
     *
 | 
						|
     * @return the sublist size
 | 
						|
     * @throws ConcurrentModificationException if the backing list has been
 | 
						|
     *         modified externally to this sublist
 | 
						|
     */
 | 
						|
    public int size()
 | 
						|
    {
 | 
						|
      synchronized (backingList)
 | 
						|
        {
 | 
						|
          checkMod();
 | 
						|
          return size;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public void clear()
 | 
						|
    {
 | 
						|
      synchronized (backingList)
 | 
						|
        {
 | 
						|
          E[] snapshot = backingList.data;
 | 
						|
          E[] newData = (E[]) new Object[snapshot.length - size];
 | 
						|
 | 
						|
          int toIndex = size + offset;
 | 
						|
 | 
						|
          System.arraycopy(snapshot, 0, newData, 0, offset);
 | 
						|
          System.arraycopy(snapshot, toIndex, newData, offset,
 | 
						|
                           snapshot.length - toIndex);
 | 
						|
 | 
						|
          backingList.data = newData;
 | 
						|
          this.data = backingList.data;
 | 
						|
          this.size = 0;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Specified by AbstractList.subList to delegate to the backing list.
 | 
						|
     *
 | 
						|
     * @param index the location to modify
 | 
						|
     * @param o the new value
 | 
						|
     * @return the old value
 | 
						|
     * @throws ConcurrentModificationException if the backing list has been
 | 
						|
     *         modified externally to this sublist
 | 
						|
     * @throws UnsupportedOperationException if the backing list does not
 | 
						|
     *         support the set operation
 | 
						|
     * @throws IndexOutOfBoundsException if index < 0 || index >= size()
 | 
						|
     * @throws ClassCastException if o cannot be added to the backing list due
 | 
						|
     *         to its type
 | 
						|
     * @throws IllegalArgumentException if o cannot be added to the backing list
 | 
						|
     *         for some other reason
 | 
						|
     */
 | 
						|
    public E set(int index, E o)
 | 
						|
    {
 | 
						|
      synchronized (backingList)
 | 
						|
        {
 | 
						|
          checkMod();
 | 
						|
          checkBoundsExclusive(index);
 | 
						|
 | 
						|
          E el =  backingList.set(index + offset, o);
 | 
						|
          this.data = backingList.data;
 | 
						|
 | 
						|
          return el;
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Specified by AbstractList.subList to delegate to the backing list.
 | 
						|
     *
 | 
						|
     * @param index the location to get from
 | 
						|
     * @return the object at that location
 | 
						|
     * @throws ConcurrentModificationException if the backing list has been
 | 
						|
     *         modified externally to this sublist
 | 
						|
     * @throws IndexOutOfBoundsException if index < 0 || index >= size()
 | 
						|
     */
 | 
						|
    public E get(int index)
 | 
						|
    {
 | 
						|
      synchronized (backingList)
 | 
						|
      {
 | 
						|
        checkMod();
 | 
						|
        checkBoundsExclusive(index);
 | 
						|
 | 
						|
        return backingList.get(index + offset);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Specified by AbstractList.subList to delegate to the backing list.
 | 
						|
     *
 | 
						|
     * @param index the index to insert at
 | 
						|
     * @param o the object to add
 | 
						|
     * @throws ConcurrentModificationException if the backing list has been
 | 
						|
     *         modified externally to this sublist
 | 
						|
     * @throws IndexOutOfBoundsException if index < 0 || index > size()
 | 
						|
     * @throws UnsupportedOperationException if the backing list does not
 | 
						|
     *         support the add operation.
 | 
						|
     * @throws ClassCastException if o cannot be added to the backing list due
 | 
						|
     *         to its type.
 | 
						|
     * @throws IllegalArgumentException if o cannot be added to the backing
 | 
						|
     *         list for some other reason.
 | 
						|
     */
 | 
						|
    public void add(int index, E o)
 | 
						|
    {
 | 
						|
      synchronized (backingList)
 | 
						|
      {
 | 
						|
        checkMod();
 | 
						|
        checkBoundsInclusive(index);
 | 
						|
 | 
						|
        backingList.add(index + offset, o);
 | 
						|
 | 
						|
        this.data = backingList.data;
 | 
						|
        size++;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Specified by AbstractList.subList to delegate to the backing list.
 | 
						|
     *
 | 
						|
     * @param index the index to remove
 | 
						|
     * @return the removed object
 | 
						|
     * @throws ConcurrentModificationException if the backing list has been
 | 
						|
     *         modified externally to this sublist
 | 
						|
     * @throws IndexOutOfBoundsException if index < 0 || index >= size()
 | 
						|
     * @throws UnsupportedOperationException if the backing list does not
 | 
						|
     *         support the remove operation
 | 
						|
     */
 | 
						|
    public E remove(int index)
 | 
						|
    {
 | 
						|
      synchronized (backingList)
 | 
						|
      {
 | 
						|
        checkMod();
 | 
						|
        checkBoundsExclusive(index);
 | 
						|
        E o = backingList.remove(index + offset);
 | 
						|
 | 
						|
        this.data = backingList.data;
 | 
						|
        size--;
 | 
						|
 | 
						|
        return o;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Specified by AbstractList.subList to delegate to the backing list.
 | 
						|
     *
 | 
						|
     * @param index the location to insert at
 | 
						|
     * @param c the collection to insert
 | 
						|
     * @return true if this list was modified, in other words, c is non-empty
 | 
						|
     * @throws ConcurrentModificationException if the backing list has been
 | 
						|
     *         modified externally to this sublist
 | 
						|
     * @throws IndexOutOfBoundsException if index < 0 || index > size()
 | 
						|
     * @throws UnsupportedOperationException if this list does not support the
 | 
						|
     *         addAll operation
 | 
						|
     * @throws ClassCastException if some element of c cannot be added to this
 | 
						|
     *         list due to its type
 | 
						|
     * @throws IllegalArgumentException if some element of c cannot be added
 | 
						|
     *         to this list for some other reason
 | 
						|
     * @throws NullPointerException if the specified collection is null
 | 
						|
     */
 | 
						|
    public boolean addAll(int index, Collection<? extends E> c)
 | 
						|
    {
 | 
						|
      synchronized (backingList)
 | 
						|
      {
 | 
						|
        checkMod();
 | 
						|
        checkBoundsInclusive(index);
 | 
						|
        int csize = c.size();
 | 
						|
        boolean result = backingList.addAll(offset + index, c);
 | 
						|
 | 
						|
        this.data = backingList.data;
 | 
						|
        size += csize;
 | 
						|
 | 
						|
        return result;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Specified by AbstractList.subList to return addAll(size, c).
 | 
						|
     *
 | 
						|
     * @param c the collection to insert
 | 
						|
     * @return true if this list was modified, in other words, c is non-empty
 | 
						|
     * @throws ConcurrentModificationException if the backing list has been
 | 
						|
     *         modified externally to this sublist
 | 
						|
     * @throws UnsupportedOperationException if this list does not support the
 | 
						|
     *         addAll operation
 | 
						|
     * @throws ClassCastException if some element of c cannot be added to this
 | 
						|
     *         list due to its type
 | 
						|
     * @throws IllegalArgumentException if some element of c cannot be added
 | 
						|
     *         to this list for some other reason
 | 
						|
     * @throws NullPointerException if the specified collection is null
 | 
						|
     */
 | 
						|
    public boolean addAll(Collection<? extends E> c)
 | 
						|
    {
 | 
						|
      synchronized (backingList)
 | 
						|
      {
 | 
						|
        return addAll(size, c);
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Specified by AbstractList.subList to return listIterator().
 | 
						|
     *
 | 
						|
     * @return an iterator over the sublist
 | 
						|
     */
 | 
						|
    public Iterator<E> iterator()
 | 
						|
    {
 | 
						|
      return listIterator();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Specified by AbstractList.subList to return a wrapper around the
 | 
						|
     * backing list's iterator.
 | 
						|
     *
 | 
						|
     * @param index the start location of the iterator
 | 
						|
     * @return a list iterator over the sublist
 | 
						|
     * @throws ConcurrentModificationException if the backing list has been
 | 
						|
     *         modified externally to this sublist
 | 
						|
     * @throws IndexOutOfBoundsException if the value is out of range
 | 
						|
     */
 | 
						|
    public ListIterator<E> listIterator(final int index)
 | 
						|
    {
 | 
						|
      checkMod();
 | 
						|
      checkBoundsInclusive(index);
 | 
						|
 | 
						|
      return new ListIterator<E>()
 | 
						|
      {
 | 
						|
        private final ListIterator<E> i =
 | 
						|
          backingList.listIterator(index + offset);
 | 
						|
        private int position = index;
 | 
						|
 | 
						|
        /**
 | 
						|
         * Tests to see if there are any more objects to
 | 
						|
         * return.
 | 
						|
         *
 | 
						|
         * @return True if the end of the list has not yet been
 | 
						|
         *         reached.
 | 
						|
         */
 | 
						|
        public boolean hasNext()
 | 
						|
        {
 | 
						|
          return position < size;
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Tests to see if there are objects prior to the
 | 
						|
         * current position in the list.
 | 
						|
         *
 | 
						|
         * @return True if objects exist prior to the current
 | 
						|
         *         position of the iterator.
 | 
						|
         */
 | 
						|
        public boolean hasPrevious()
 | 
						|
        {
 | 
						|
          return position > 0;
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Retrieves the next object from the list.
 | 
						|
         *
 | 
						|
         * @return The next object.
 | 
						|
         * @throws NoSuchElementException if there are no
 | 
						|
         *         more objects to retrieve.
 | 
						|
         * @throws ConcurrentModificationException if the
 | 
						|
         *         list has been modified elsewhere.
 | 
						|
         */
 | 
						|
        public E next()
 | 
						|
        {
 | 
						|
          if (position == size)
 | 
						|
            throw new NoSuchElementException();
 | 
						|
          position++;
 | 
						|
          return i.next();
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Retrieves the previous object from the list.
 | 
						|
         *
 | 
						|
         * @return The next object.
 | 
						|
         * @throws NoSuchElementException if there are no
 | 
						|
         *         previous objects to retrieve.
 | 
						|
         * @throws ConcurrentModificationException if the
 | 
						|
         *         list has been modified elsewhere.
 | 
						|
         */
 | 
						|
        public E previous()
 | 
						|
        {
 | 
						|
          if (position == 0)
 | 
						|
            throw new NoSuchElementException();
 | 
						|
          position--;
 | 
						|
          return i.previous();
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Returns the index of the next element in the
 | 
						|
         * list, which will be retrieved by <code>next()</code>
 | 
						|
         *
 | 
						|
         * @return The index of the next element.
 | 
						|
         */
 | 
						|
        public int nextIndex()
 | 
						|
        {
 | 
						|
          return i.nextIndex() - offset;
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Returns the index of the previous element in the
 | 
						|
         * list, which will be retrieved by <code>previous()</code>
 | 
						|
         *
 | 
						|
         * @return The index of the previous element.
 | 
						|
         */
 | 
						|
        public int previousIndex()
 | 
						|
        {
 | 
						|
          return i.previousIndex() - offset;
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Removes the last object retrieved by <code>next()</code>
 | 
						|
         * from the list, if the list supports object removal.
 | 
						|
         *
 | 
						|
         * @throws IllegalStateException if the iterator is positioned
 | 
						|
         *         before the start of the list or the last object has already
 | 
						|
         *         been removed.
 | 
						|
         * @throws UnsupportedOperationException if the list does
 | 
						|
         *         not support removing elements.
 | 
						|
         */
 | 
						|
        public void remove()
 | 
						|
        {
 | 
						|
          throw new UnsupportedOperationException("Modification not supported " +
 | 
						|
              "on CopyOnWriteArrayList iterators");
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Replaces the last object retrieved by <code>next()</code>
 | 
						|
         * or <code>previous</code> with o, if the list supports object
 | 
						|
         * replacement and an add or remove operation has not already
 | 
						|
         * been performed.
 | 
						|
         *
 | 
						|
         * @throws IllegalStateException if the iterator is positioned
 | 
						|
         *         before the start of the list or the last object has already
 | 
						|
         *         been removed.
 | 
						|
         * @throws UnsupportedOperationException if the list doesn't support
 | 
						|
         *         the addition or removal of elements.
 | 
						|
         * @throws ClassCastException if the type of o is not a valid type
 | 
						|
         *         for this list.
 | 
						|
         * @throws IllegalArgumentException if something else related to o
 | 
						|
         *         prevents its addition.
 | 
						|
         * @throws ConcurrentModificationException if the list
 | 
						|
         *         has been modified elsewhere.
 | 
						|
         */
 | 
						|
        public void set(E o)
 | 
						|
        {
 | 
						|
          throw new UnsupportedOperationException("Modification not supported " +
 | 
						|
              "on CopyOnWriteArrayList iterators");
 | 
						|
        }
 | 
						|
 | 
						|
        /**
 | 
						|
         * Adds the supplied object before the element that would be returned
 | 
						|
         * by a call to <code>next()</code>, if the list supports addition.
 | 
						|
         *
 | 
						|
         * @param o The object to add to the list.
 | 
						|
         * @throws UnsupportedOperationException if the list doesn't support
 | 
						|
         *         the addition of new elements.
 | 
						|
         * @throws ClassCastException if the type of o is not a valid type
 | 
						|
         *         for this list.
 | 
						|
         * @throws IllegalArgumentException if something else related to o
 | 
						|
         *         prevents its addition.
 | 
						|
         * @throws ConcurrentModificationException if the list
 | 
						|
         *         has been modified elsewhere.
 | 
						|
         */
 | 
						|
        public void add(E o)
 | 
						|
        {
 | 
						|
          throw new UnsupportedOperationException("Modification not supported " +
 | 
						|
              "on CopyOnWriteArrayList iterators");
 | 
						|
        }
 | 
						|
      };
 | 
						|
    }
 | 
						|
  } // class SubList
 | 
						|
 | 
						|
  /**
 | 
						|
   * This class is a RandomAccess version of SubList, as required by
 | 
						|
   * {@link AbstractList#subList(int, int)}.
 | 
						|
   *
 | 
						|
   * @author Eric Blake (ebb9@email.byu.edu)
 | 
						|
   */
 | 
						|
  private static final class RandomAccessSubList<E> extends SubList<E>
 | 
						|
    implements RandomAccess
 | 
						|
  {
 | 
						|
    /**
 | 
						|
     * Construct the sublist.
 | 
						|
     *
 | 
						|
     * @param backing the list this comes from
 | 
						|
     * @param fromIndex the lower bound, inclusive
 | 
						|
     * @param toIndex the upper bound, exclusive
 | 
						|
     */
 | 
						|
    RandomAccessSubList(CopyOnWriteArrayList<E> backing, int fromIndex, int toIndex)
 | 
						|
    {
 | 
						|
      super(backing, fromIndex, toIndex);
 | 
						|
    }
 | 
						|
  } // class RandomAccessSubList
 | 
						|
 | 
						|
  /**
 | 
						|
   * Serializes this object to the given stream.
 | 
						|
   *
 | 
						|
   * @param s
 | 
						|
   *          the stream to write to
 | 
						|
   * @throws IOException
 | 
						|
   *           if the underlying stream fails
 | 
						|
   * @serialData the size field (int), the length of the backing array (int),
 | 
						|
   *             followed by its elements (Objects) in proper order.
 | 
						|
   */
 | 
						|
  private void writeObject(ObjectOutputStream s) throws IOException
 | 
						|
  {
 | 
						|
    // The 'size' field.
 | 
						|
    s.defaultWriteObject();
 | 
						|
    // We serialize unused list entries to preserve capacity.
 | 
						|
    int len = data.length;
 | 
						|
    s.writeInt(len);
 | 
						|
    // it would be more efficient to just write "size" items,
 | 
						|
    // this need readObject read "size" items too.
 | 
						|
    for (int i = 0; i < data.length; i++)
 | 
						|
      s.writeObject(data[i]);
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Deserializes this object from the given stream.
 | 
						|
   *
 | 
						|
   * @param s
 | 
						|
   *          the stream to read from
 | 
						|
   * @throws ClassNotFoundException
 | 
						|
   *           if the underlying stream fails
 | 
						|
   * @throws IOException
 | 
						|
   *           if the underlying stream fails
 | 
						|
   * @serialData the size field (int), the length of the backing array (int),
 | 
						|
   *             followed by its elements (Objects) in proper order.
 | 
						|
   */
 | 
						|
  private void readObject(ObjectInputStream s) throws IOException,
 | 
						|
      ClassNotFoundException
 | 
						|
  {
 | 
						|
    // the `size' field.
 | 
						|
    s.defaultReadObject();
 | 
						|
    int capacity = s.readInt();
 | 
						|
    data = (E[]) new Object[capacity];
 | 
						|
    for (int i = 0; i < capacity; i++)
 | 
						|
      data[i] = (E) s.readObject();
 | 
						|
  }
 | 
						|
 | 
						|
  static final boolean equals(Object o1, Object o2)
 | 
						|
  {
 | 
						|
    return o1 == null ? o2 == null : o1.equals(o2);
 | 
						|
  }
 | 
						|
 | 
						|
  Object[] getArray()
 | 
						|
  {
 | 
						|
    return data;
 | 
						|
  }
 | 
						|
}
 |