/* * @(#)AbstractList.java 1.50 05/12/06 * * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.util; /** * This class provides a skeletal implementation of the List * interface to minimize the effort required to implement this interface * backed by a "random access" data store (such as an array). For sequential * access data (such as a linked list), AbstractSequentialList should * be used in preference to this class.

* * To implement an unmodifiable list, the programmer needs only to extend this * class and provide implementations for the get(int index) and * size() methods.

* * To implement a modifiable list, the programmer must additionally override * the set(int index, Object element) method (which otherwise throws * an UnsupportedOperationException. If the list is variable-size * the programmer must additionally override the add(int index, Object * element) and remove(int index) methods.

* * The programmer should generally provide a void (no argument) and collection * constructor, as per the recommendation in the Collection interface * specification.

* * Unlike the other abstract collection implementations, the programmer does * not have to provide an iterator implementation; the iterator and * list iterator are implemented by this class, on top of the "random access" * methods: get(int index), set(int index, E element), * add(int index, E element) and remove(int index).

* * The documentation for each non-abstract methods in this class describes its * implementation in detail. Each of these methods may be overridden if the * collection being implemented admits a more efficient implementation.

* * This class is a member of the * * Java Collections Framework. * * @author Josh Bloch * @author Neal Gafter * @version %I%, %G% * @see Collection * @see List * @see AbstractSequentialList * @see AbstractCollection * @since 1.2 */ public abstract class AbstractList extends AbstractCollection implements List { /** * Sole constructor. (For invocation by subclass constructors, typically * implicit.) */ protected AbstractList() { } /** * Appends the specified element to the end of this list (optional * operation). * *

Lists that support this operation may place limitations on what * elements may be added to this list. In particular, some * lists will refuse to add null elements, and others will impose * restrictions on the type of elements that may be added. List * classes should clearly specify in their documentation any restrictions * on what elements may be added. * *

This implementation calls add(size(), e). * *

Note that this implementation throws an * UnsupportedOperationException unless add(int, Object) * is overridden. * * @param e element to be appended to this list * @return true (as specified by {@link Collection#add}) * @throws UnsupportedOperationException if the add operation * is not supported by this list * @throws ClassCastException if the class of the specified element * prevents it from being added to this list * @throws NullPointerException if the specified element is null and this * list does not permit null elements * @throws IllegalArgumentException if some property of this element * prevents it from being added to this list */ public boolean add(E e) { add(size(), e); return true; } /** * {@inheritDoc} * * @throws IndexOutOfBoundsException {@inheritDoc} */ abstract public E get(int index); /** * {@inheritDoc} * *

This implementation always throws an * UnsupportedOperationException. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ public E set(int index, E element) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} * *

This implementation always throws an * UnsupportedOperationException. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ public void add(int index, E element) { throw new UnsupportedOperationException(); } /** * {@inheritDoc} * *

This implementation always throws an * UnsupportedOperationException. * * @throws UnsupportedOperationException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ public E remove(int index) { throw new UnsupportedOperationException(); } // Search Operations /** * {@inheritDoc} * *

This implementation first gets a list iterator (with * listIterator()). Then, it iterates over the list until the * specified element is found or the end of the list is reached. * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public int indexOf(Object o) { ListIterator e = listIterator(); if (o==null) { while (e.hasNext()) if (e.next()==null) return e.previousIndex(); } else { while (e.hasNext()) if (o.equals(e.next())) return e.previousIndex(); } return -1; } /** * {@inheritDoc} * *

This implementation first gets a list iterator that points to the end * of the list (with listIterator(size())). Then, it iterates * backwards over the list until the specified element is found, or the * beginning of the list is reached. * * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} */ public int lastIndexOf(Object o) { ListIterator e = listIterator(size()); if (o==null) { while (e.hasPrevious()) if (e.previous()==null) return e.nextIndex(); } else { while (e.hasPrevious()) if (o.equals(e.previous())) return e.nextIndex(); } return -1; } // Bulk Operations /** * Removes all of the elements from this list (optional operation). * The list will be empty after this call returns. * *

This implementation calls removeRange(0, size()). * *

Note that this implementation throws an * UnsupportedOperationException unless remove(int * index) or removeRange(int fromIndex, int toIndex) is * overridden. * * @throws UnsupportedOperationException if the clear operation * is not supported by this list */ public void clear() { removeRange(0, size()); } /** * {@inheritDoc} * *

This implementation gets an iterator over the specified collection and * iterates over it, inserting the elements obtained from the iterator * into this list at the appropriate position, one at a time, using * add(int, Object). Many implementations will override this * method for efficiency. * *

Note that this implementation throws an * UnsupportedOperationException unless add(int, Object) * is overridden. * * @throws UnsupportedOperationException {@inheritDoc} * @throws ClassCastException {@inheritDoc} * @throws NullPointerException {@inheritDoc} * @throws IllegalArgumentException {@inheritDoc} * @throws IndexOutOfBoundsException {@inheritDoc} */ public boolean addAll(int index, Collection c) { boolean modified = false; Iterator e = c.iterator(); while (e.hasNext()) { add(index++, e.next()); modified = true; } return modified; } // Iterators /** * Returns an iterator over the elements in this list in proper * sequence.

* * This implementation returns a straightforward implementation of the * iterator interface, relying on the backing list's size(), * get(int), and remove(int) methods.

* * Note that the iterator returned by this method will throw an * UnsupportedOperationException in response to its * remove method unless the list's remove(int) method is * overridden.

* * This implementation can be made to throw runtime exceptions in the face * of concurrent modification, as described in the specification for the * (protected) modCount field. * * @return an iterator over the elements in this list in proper sequence * * @see #modCount */ public Iterator iterator() { return new Itr(); } /** * {@inheritDoc} * *

This implementation returns listIterator(0). * * @see #listIterator(int) */ public ListIterator listIterator() { return listIterator(0); } /** * {@inheritDoc} * *

This implementation returns a straightforward implementation of the * ListIterator interface that extends the implementation of the * Iterator interface returned by the iterator() method. * The ListIterator implementation relies on the backing list's * get(int), set(int, Object), add(int, Object) * and remove(int) methods. * *

Note that the list iterator returned by this implementation will * throw an UnsupportedOperationException in response to its * remove, set and add methods unless the * list's remove(int), set(int, Object), and * add(int, Object) methods are overridden. * *

This implementation can be made to throw runtime exceptions in the * face of concurrent modification, as described in the specification for * the (protected) modCount field. * * @throws IndexOutOfBoundsException {@inheritDoc} * * @see #modCount */ public ListIterator listIterator(final int index) { if (index<0 || index>size()) throw new IndexOutOfBoundsException("Index: "+index); return new ListItr(index); } private class Itr implements Iterator { /** * Index of element to be returned by subsequent call to next. */ int cursor = 0; /** * Index of element returned by most recent call to next or * previous. Reset to -1 if this element is deleted by a call * to remove. */ int lastRet = -1; /** * The modCount value that the iterator believes that the backing * List should have. If this expectation is violated, the iterator * has detected concurrent modification. */ int expectedModCount = modCount; public boolean hasNext() { return cursor != size(); } public E next() { checkForComodification(); try { E next = get(cursor); lastRet = cursor++; return next; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } public void remove() { if (lastRet == -1) throw new IllegalStateException(); checkForComodification(); try { AbstractList.this.remove(lastRet); if (lastRet < cursor) cursor--; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException e) { throw new ConcurrentModificationException(); } } final void checkForComodification() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); } } private class ListItr extends Itr implements ListIterator { ListItr(int index) { cursor = index; } public boolean hasPrevious() { return cursor != 0; } public E previous() { checkForComodification(); try { int i = cursor - 1; E previous = get(i); lastRet = cursor = i; return previous; } catch (IndexOutOfBoundsException e) { checkForComodification(); throw new NoSuchElementException(); } } public int nextIndex() { return cursor; } public int previousIndex() { return cursor-1; } public void set(E e) { if (lastRet == -1) throw new IllegalStateException(); checkForComodification(); try { AbstractList.this.set(lastRet, e); expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } public void add(E e) { checkForComodification(); try { int i = cursor; AbstractList.this.add(i, e); cursor = i + 1; lastRet = -1; expectedModCount = modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } } /** * {@inheritDoc} * *

This implementation returns a list that subclasses * AbstractList. The subclass stores, in private fields, the * offset of the subList within the backing list, the size of the subList * (which can change over its lifetime), and the expected * modCount value of the backing list. There are two variants * of the subclass, one of which implements RandomAccess. * If this list implements RandomAccess the returned list will * be an instance of the subclass that implements RandomAccess. * *

The subclass's set(int, Object), get(int), * add(int, Object), remove(int), addAll(int, * Collection) and removeRange(int, int) methods all * delegate to the corresponding methods on the backing abstract list, * after bounds-checking the index and adjusting for the offset. The * addAll(Collection c) method merely returns addAll(size, * c). * *

The listIterator(int) 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 iterator method * merely returns listIterator(), and the size method * merely returns the subclass's size field. * *

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. * * @throws IndexOutOfBoundsException endpoint index value out of range * (fromIndex < 0 || toIndex > size) * @throws IllegalArgumentException if the endpoint indices are out of order * (fromIndex > toIndex) */ public List subList(int fromIndex, int toIndex) { return (this instanceof RandomAccess ? new RandomAccessSubList(this, this, fromIndex, fromIndex, toIndex) : new SubList(this, this, fromIndex, fromIndex, toIndex)); } // Comparison and hashing /** * Compares the specified object with this list for equality. Returns * true if and only if the specified object is also a list, both * lists have the same size, and all corresponding pairs of elements in * the two lists are equal. (Two elements e1 and * e2 are equal if (e1==null ? e2==null : * e1.equals(e2)).) In other words, two lists are defined to be * equal if they contain the same elements in the same order.

* * This implementation first checks if the specified object is this * list. If so, it returns true; if not, it checks if the * specified object is a list. If not, it returns false; if so, * it iterates over both lists, comparing corresponding pairs of elements. * If any comparison returns false, this method returns * false. If either iterator runs out of elements before the * other it returns false (as the lists are of unequal length); * otherwise it returns true when the iterations complete. * * @param o the object to be compared for equality with this list * @return true if the specified object is equal to this list */ public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof List)) return false; ListIterator e1 = listIterator(); ListIterator e2 = ((List) o).listIterator(); while(e1.hasNext() && e2.hasNext()) { E o1 = e1.next(); Object o2 = e2.next(); if (!(o1==null ? o2==null : o1.equals(o2))) return false; } return !(e1.hasNext() || e2.hasNext()); } /** * Returns the hash code value for this list.

* * This implementation uses exactly the code that is used to define the * list hash function in the documentation for the {@link List#hashCode} * method. * * @return the hash code value for this list */ public int hashCode() { int hashCode = 1; Iterator i = iterator(); while (i.hasNext()) { E obj = i.next(); hashCode = 31*hashCode + (obj==null ? 0 : obj.hashCode()); } return hashCode; } /** * Removes from this list all of the elements whose index is between * fromIndex, inclusive, and toIndex, exclusive. * Shifts any succeeding elements to the left (reduces their index). * This call shortens the ArrayList by (toIndex - fromIndex) * elements. (If toIndex==fromIndex, this operation has no * effect.)

* * This method is called by the clear operation on this list * and its subLists. Overriding this method to take advantage of * the internals of the list implementation can substantially * improve the performance of the clear operation on this list * and its subLists.

* * This implementation gets a list iterator positioned before * fromIndex, and repeatedly calls ListIterator.next * followed by ListIterator.remove until the entire range has * been removed. Note: if ListIterator.remove requires linear * time, this implementation requires quadratic time. * * @param fromIndex index of first element to be removed * @param toIndex index after last element to be removed */ protected void removeRange(int fromIndex, int toIndex) { ListIterator it = listIterator(fromIndex); for (int i=0, n=toIndex-fromIndex; istructurally modified. * Structural modifications are those that change the size of the * list, or otherwise perturb it in such a fashion that iterations in * progress may yield incorrect results.

* * This field is used by the iterator and list iterator implementation * returned by the iterator and listIterator methods. * If the value of this field changes unexpectedly, the iterator (or list * iterator) will throw a ConcurrentModificationException in * response to the next, remove, previous, * set or add operations. This provides * fail-fast behavior, rather than non-deterministic behavior in * the face of concurrent modification during iteration.

* * Use of this field by subclasses is optional. If a subclass * wishes to provide fail-fast iterators (and list iterators), then it * merely has to increment this field in its add(int, Object) and * remove(int) methods (and any other methods that it overrides * that result in structural modifications to the list). A single call to * add(int, Object) or remove(int) must add no more than * one to this field, or the iterators (and list iterators) will throw * bogus ConcurrentModificationExceptions. If an implementation * does not wish to provide fail-fast iterators, this field may be * ignored. */ protected transient int modCount = 0; } /** * Generic sublists. Non-nested to enable construction by other * classes in this package. */ class SubList extends AbstractList { /* * A SubList has both a "base", the ultimate backing list, as well * as a "parent", which is the list or sublist creating this * sublist. All methods that may cause structural modifications * must propagate through the parent link, with O(k) performance * where k is sublist depth. For example in the case of a * sub-sub-list, invoking remove(x) will result in a chain of * three remove calls. However, all other non-structurally * modifying methods can bypass this chain, and relay directly to * the base list. In particular, doing so signficantly speeds up * the performance of iterators for deeply-nested sublists. */ final AbstractList base; // Backing list final AbstractList parent; // Parent list final int baseOffset; // index wrt base final int parentOffset; // index wrt parent int length; // Number of elements in this sublist SubList(AbstractList base, AbstractList parent, int baseIndex, int fromIndex, int toIndex) { if (fromIndex < 0) throw new IndexOutOfBoundsException("fromIndex = " + fromIndex); if (toIndex > parent.size()) throw new IndexOutOfBoundsException("toIndex = " + toIndex); if (fromIndex > toIndex) throw new IllegalArgumentException("fromIndex(" + fromIndex + ") > toIndex(" + toIndex + ")"); this.base = base; this.parent = parent; this.baseOffset = baseIndex; this.parentOffset = fromIndex; this.length = toIndex - fromIndex; this.modCount = base.modCount; } /** * Returns an IndexOutOfBoundsException with nicer message */ private IndexOutOfBoundsException indexError(int index) { return new IndexOutOfBoundsException("Index: " + index + ", Size: " + length); } public E set(int index, E element) { if (index < 0 || index >= length) throw indexError(index); if (base.modCount != modCount) throw new ConcurrentModificationException(); return base.set(index + baseOffset, element); } public E get(int index) { if (index < 0 || index >= length) throw indexError(index); if (base.modCount != modCount) throw new ConcurrentModificationException(); return base.get(index + baseOffset); } public int size() { if (base.modCount != modCount) throw new ConcurrentModificationException(); return length; } public void add(int index, E element) { if (index < 0 || index>length) throw indexError(index); if (base.modCount != modCount) throw new ConcurrentModificationException(); parent.add(index + parentOffset, element); length++; modCount = base.modCount; } public E remove(int index) { if (index < 0 || index >= length) throw indexError(index); if (base.modCount != modCount) throw new ConcurrentModificationException(); E result = parent.remove(index + parentOffset); length--; modCount = base.modCount; return result; } protected void removeRange(int fromIndex, int toIndex) { if (base.modCount != modCount) throw new ConcurrentModificationException(); parent.removeRange(fromIndex + parentOffset, toIndex + parentOffset); length -= (toIndex-fromIndex); modCount = base.modCount; } public boolean addAll(Collection c) { return addAll(length, c); } public boolean addAll(int index, Collection c) { if (index < 0 || index > length) throw indexError(index); int cSize = c.size(); if (cSize==0) return false; if (base.modCount != modCount) throw new ConcurrentModificationException(); parent.addAll(parentOffset + index, c); length += cSize; modCount = base.modCount; return true; } public List subList(int fromIndex, int toIndex) { return new SubList(base, this, fromIndex + baseOffset, fromIndex, toIndex); } public Iterator iterator() { return new SubListIterator(this, 0); } public ListIterator listIterator() { return new SubListIterator(this, 0); } public ListIterator listIterator(int index) { if (index < 0 || index>length) throw indexError(index); return new SubListIterator(this, index); } /** * Generic sublist iterator obeying fastfail semantics via * modCount. The hasNext and next methods locally check for * in-range indices before relaying to backing list to get * element. If this either encounters an unexpected modCount or * fails, the backing list must have been concurrently modified, * and is so reported. The add and remove methods performing * structural modifications instead relay them through the * sublist. */ private static final class SubListIterator implements ListIterator { final SubList outer; // Sublist creating this iteraor final AbstractList base; // base list final int offset; // Cursor offset wrt base int cursor; // Current index int fence; // Upper bound on cursor int lastRet; // Index of returned element, or -1 int expectedModCount; // Expected modCount of base SubListIterator(SubList list, int index) { this.lastRet = -1; this.cursor = index; this.outer = list; this.offset = list.baseOffset; this.fence = list.length; this.base = list.base; this.expectedModCount = base.modCount; } public boolean hasNext() { return cursor < fence; } public boolean hasPrevious() { return cursor > 0; } public int nextIndex() { return cursor; } public int previousIndex() { return cursor - 1; } public E next() { int i = cursor; if (cursor >= fence) throw new NoSuchElementException(); if (expectedModCount == base.modCount) { try { Object next = base.get(i + offset); lastRet = i; cursor = i + 1; return (E)next; } catch (IndexOutOfBoundsException fallThrough) { } } throw new ConcurrentModificationException(); } public E previous() { int i = cursor - 1; if (i < 0) throw new NoSuchElementException(); if (expectedModCount == base.modCount) { try { Object prev = base.get(i + offset); lastRet = i; cursor = i; return (E)prev; } catch (IndexOutOfBoundsException fallThrough) { } } throw new ConcurrentModificationException(); } public void set(E e) { if (lastRet < 0) throw new IllegalStateException(); if (expectedModCount != base.modCount) throw new ConcurrentModificationException(); try { outer.set(lastRet, e); expectedModCount = base.modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } public void remove() { int i = lastRet; if (i < 0) throw new IllegalStateException(); if (expectedModCount != base.modCount) throw new ConcurrentModificationException(); try { outer.remove(i); if (i < cursor) cursor--; lastRet = -1; fence = outer.length; expectedModCount = base.modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } public void add(E e) { if (expectedModCount != base.modCount) throw new ConcurrentModificationException(); try { int i = cursor; outer.add(i, e); cursor = i + 1; lastRet = -1; fence = outer.length; expectedModCount = base.modCount; } catch (IndexOutOfBoundsException ex) { throw new ConcurrentModificationException(); } } } } class RandomAccessSubList extends SubList implements RandomAccess { RandomAccessSubList(AbstractList base, AbstractList parent, int baseIndex, int fromIndex, int toIndex) { super(base, parent, baseIndex, fromIndex, toIndex); } public List subList(int fromIndex, int toIndex) { return new RandomAccessSubList(base, this, fromIndex + baseOffset, fromIndex, toIndex); } }