/* * Written by Doug Lea with assistance from members of JCP JSR-166 * Expert Group and released to the public domain, as explained at * http://creativecommons.org/publicdomain/zero/1.0/ */ package jsr166e.extra; import jsr166e.StampedLock; import java.util.*; /** * A class with the same methods and array-based characteristics as * {@link java.util.Vector} but with reduced contention and improved * throughput when invocations of read-only methods by multiple * threads are most common. * *

The iterators returned by this class's {@link #iterator() * iterator} and {@link #listIterator(int) listIterator} methods are * best-effort in the presence of concurrent modifications, and do * NOT throw {@link ConcurrentModificationException}. An * iterator's {@code next()} method returns consecutive elements as * they appear in the underlying array upon each access. Alternatively, * method {@link #snapshotIterator} may be used for deterministic * traversals, at the expense of making a copy, and unavailability of * method {@code Iterator.remove}. * *

Otherwise, this class supports all methods, under the same * documented specifications, as {@code Vector}. Consult {@link * java.util.Vector} for detailed specifications. Additionally, this * class provides methods {@link #addIfAbsent} and {@link * #addAllAbsent}. * * @author Doug Lea */ public class ReadMostlyVector implements List, RandomAccess, Cloneable, java.io.Serializable { private static final long serialVersionUID = 8673264195747942595L; /* * This class exists mainly as a vehicle to exercise various * constructions using SequenceLocks. Read-only methods * take one of a few forms: * * Short methods,including get(index), continually retry obtaining * a snapshot of array, count, and element, using sequence number * to validate. * * Methods that are potentially O(n) (or worse) try once in * read-only mode, and then lock. When in read-only mode, they * validate only at the end of an array scan unless the element is * actually used (for example, as an argument of method equals). * * We rely on some invariants that are always true, even for field * reads in read-only mode that have not yet been validated: * - array != null * - count >= 0 */ /** * The maximum size of array to allocate. * See CopyOnWriteArrayList for explanation. */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // fields are non-private to simplify nested class access Object[] array; final StampedLock lock; int count; final int capacityIncrement; /** * Creates an empty vector with the given initial capacity and * capacity increment. * * @param initialCapacity the initial capacity of the underlying array * @param capacityIncrement if non-zero, the number to * add when resizing to accommodate additional elements. * If zero, the array size is doubled when resized. * * @throws IllegalArgumentException if initial capacity is negative */ public ReadMostlyVector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.array = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; this.lock = new StampedLock(); } /** * Creates an empty vector with the given initial capacity. * * @param initialCapacity the initial capacity of the underlying array * @throws IllegalArgumentException if initial capacity is negative */ public ReadMostlyVector(int initialCapacity) { this(initialCapacity, 0); } /** * Creates an empty vector. */ public ReadMostlyVector() { this.capacityIncrement = 0; this.lock = new StampedLock(); } /** * Creates a vector containing the elements of the specified * collection, in the order they are returned by the collection's * iterator. * * @param c the collection of initially held elements * @throws NullPointerException if the specified collection is null */ public ReadMostlyVector(Collection c) { Object[] elements = c.toArray(); // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elements.getClass() != Object[].class) elements = Arrays.copyOf(elements, elements.length, Object[].class); this.array = elements; this.count = elements.length; this.capacityIncrement = 0; this.lock = new StampedLock(); } // internal constructor for clone ReadMostlyVector(Object[] array, int count, int capacityIncrement) { this.array = array; this.count = count; this.capacityIncrement = capacityIncrement; this.lock = new StampedLock(); } static final int INITIAL_CAP = 16; // For explanation, see CopyOnWriteArrayList final Object[] grow(int minCapacity) { Object[] items; int newCapacity; if ((items = array) == null) newCapacity = INITIAL_CAP; else { int oldCapacity = array.length; newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); } if (newCapacity - minCapacity < 0) newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) { if (minCapacity < 0) // overflow throw new OutOfMemoryError(); else if (minCapacity > MAX_ARRAY_SIZE) newCapacity = Integer.MAX_VALUE; else newCapacity = MAX_ARRAY_SIZE; } return array = ((items == null) ? new Object[newCapacity] : Arrays.copyOf(items, newCapacity)); } /* * Internal versions of most base functionality, wrapped * in different ways from public methods from this class * as well as sublist and iterator classes. */ static int findFirstIndex(Object[] items, Object x, int index, int fence) { int len; if (items != null && (len = items.length) > 0) { int start = (index < 0) ? 0 : index; int bound = (fence < len) ? fence : len; for (int i = start; i < bound; ++i) { Object e = items[i]; if ((x == null) ? e == null : x.equals(e)) return i; } } return -1; } static int findLastIndex(Object[] items, Object x, int index, int origin) { int len; if (items != null && (len = items.length) > 0) { int last = (index < len) ? index : len - 1; int start = (origin < 0) ? 0 : origin; for (int i = last; i >= start; --i) { Object e = items[i]; if ((x == null) ? e == null : x.equals(e)) return i; } } return -1; } final void rawAdd(E e) { int n = count; Object[] items = array; if (items == null || n >= items.length) items = grow(n + 1); items[n] = e; count = n + 1; } final void rawAddAt(int index, E e) { int n = count; Object[] items = array; if (index > n) throw new ArrayIndexOutOfBoundsException(index); if (items == null || n >= items.length) items = grow(n + 1); if (index < n) System.arraycopy(items, index, items, index + 1, n - index); items[index] = e; count = n + 1; } final boolean rawAddAllAt(int index, Object[] elements) { int n = count; Object[] items = array; if (index < 0 || index > n) throw new ArrayIndexOutOfBoundsException(index); int len = elements.length; if (len == 0) return false; int newCount = n + len; if (items == null || newCount >= items.length) items = grow(newCount); int mv = n - index; if (mv > 0) System.arraycopy(items, index, items, index + len, mv); System.arraycopy(elements, 0, items, index, len); count = newCount; return true; } final boolean rawRemoveAt(int index) { int n = count - 1; Object[] items = array; if (items == null || index < 0 || index > n) return false; int mv = n - index; if (mv > 0) System.arraycopy(items, index + 1, items, index, mv); items[n] = null; count = n; return true; } /** * Internal version of removeAll for lists and sublists. In this * and other similar methods below, the bound argument is, if * non-negative, the purported upper bound of a list/sublist, or * is left negative if the bound should be determined via count * field under lock. */ final boolean lockedRemoveAll(Collection c, int origin, int bound) { boolean removed = false; final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { int n = count; int fence = bound < 0 || bound > n ? n : bound; if (origin >= 0 && origin < fence) { for (Object x : c) { while (rawRemoveAt(findFirstIndex(array, x, origin, fence))) removed = true; } } } finally { lock.unlockWrite(stamp); } return removed; } final boolean lockedRetainAll(Collection c, int origin, int bound) { final StampedLock lock = this.lock; boolean removed = false; if (c != this) { long stamp = lock.writeLock(); try { Object[] items; int i, n; if ((items = array) != null && (n = count) > 0 && n < items.length && (i = origin) >= 0) { int fence = bound < 0 || bound > n ? n : bound; while (i < fence) { if (c.contains(items[i])) ++i; else { --fence; int mv = --n - i; if (mv > 0) System.arraycopy(items, i + 1, items, i, mv); } } if (count != n) { count = n; removed = true; } } } finally { lock.unlockWrite(stamp); } } return removed; } final void internalClear(int origin, int bound) { Object[] items; int n, len; if ((items = array) != null && (len = items.length) > 0) { if (origin < 0) origin = 0; if ((n = count) > len) n = len; int fence = bound < 0 || bound > n ? n : bound; int removed = fence - origin; int newCount = n - removed; int mv = n - (origin + removed); if (mv > 0) System.arraycopy(items, origin + removed, items, origin, mv); for (int i = n; i < newCount; ++i) items[i] = null; count = newCount; } } final boolean internalContainsAll(Collection c, int origin, int bound) { Object[] items; int n, len; if ((items = array) != null && (len = items.length) > 0) { if (origin < 0) origin = 0; if ((n = count) > len) n = len; int fence = bound < 0 || bound > n ? n : bound; for (Object e : c) { if (findFirstIndex(items, e, origin, fence) < 0) return false; } } else if (!c.isEmpty()) return false; return true; } final boolean internalEquals(List list, int origin, int bound) { Object[] items; int n, len; if ((items = array) != null && (len = items.length) > 0) { if (origin < 0) origin = 0; if ((n = count) > len) n = len; int fence = bound < 0 || bound > n ? n : bound; Iterator it = list.iterator(); for (int i = origin; i < fence; ++i) { if (!it.hasNext()) return false; Object y = it.next(); Object x = items[i]; if (x != y && (x == null || !x.equals(y))) return false; } if (it.hasNext()) return false; } else if (!list.isEmpty()) return false; return true; } final int internalHashCode(int origin, int bound) { int hash = 1; Object[] items; int n, len; if ((items = array) != null && (len = items.length) > 0) { if (origin < 0) origin = 0; if ((n = count) > len) n = len; int fence = bound < 0 || bound > n ? n : bound; for (int i = origin; i < fence; ++i) { Object e = items[i]; hash = 31*hash + (e == null ? 0 : e.hashCode()); } } return hash; } final String internalToString(int origin, int bound) { Object[] items; int n, len; if ((items = array) != null && (len = items.length) > 0) { if ((n = count) > len) n = len; int fence = bound < 0 || bound > n ? n : bound; int i = (origin < 0) ? 0 : origin; if (i != fence) { StringBuilder sb = new StringBuilder(); sb.append('['); for (;;) { Object e = items[i]; sb.append((e == this) ? "(this Collection)" : e.toString()); if (++i < fence) sb.append(',').append(' '); else return sb.append(']').toString(); } } } return "[]"; } final Object[] internalToArray(int origin, int bound) { Object[] items; int n, len; if ((items = array) != null && (len = items.length) > 0) { if (origin < 0) origin = 0; if ((n = count) > len) n = len; int fence = bound < 0 || bound > n ? n : bound; int i = (origin < 0) ? 0 : origin; if (i != fence) return Arrays.copyOfRange(items, i, fence, Object[].class); } return new Object[0]; } @SuppressWarnings("unchecked") final T[] internalToArray(T[] a, int origin, int bound) { int alen = a.length; Object[] items; int n, len; if ((items = array) != null && (len = items.length) > 0) { if (origin < 0) origin = 0; if ((n = count) > len) n = len; int fence = bound < 0 || bound > n ? n : bound; int i = (origin < 0) ? 0 : origin; int rlen = fence - origin; if (rlen > 0) { if (alen >= rlen) { System.arraycopy(items, 0, a, origin, rlen); if (alen > rlen) a[rlen] = null; return a; } return (T[]) Arrays.copyOfRange(items, i, fence, a.getClass()); } } if (alen > 0) a[0] = null; return a; } // public List methods public boolean add(E e) { final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { rawAdd(e); } finally { lock.unlockWrite(stamp); } return true; } public void add(int index, E element) { final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { rawAddAt(index, element); } finally { lock.unlockWrite(stamp); } } public boolean addAll(Collection c) { Object[] elements = c.toArray(); int len = elements.length; if (len == 0) return false; final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { Object[] items = array; int n = count; int newCount = n + len; if (items == null || newCount >= items.length) items = grow(newCount); System.arraycopy(elements, 0, items, n, len); count = newCount; } finally { lock.unlockWrite(stamp); } return true; } public boolean addAll(int index, Collection c) { Object[] elements = c.toArray(); boolean ret; final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { ret = rawAddAllAt(index, elements); } finally { lock.unlockWrite(stamp); } return ret; } public void clear() { final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { int n = count; Object[] items = array; if (items != null) { for (int i = 0; i < n; i++) items[i] = null; } count = 0; } finally { lock.unlockWrite(stamp); } } public boolean contains(Object o) { return indexOf(o, 0) >= 0; } public boolean containsAll(Collection c) { boolean ret; final StampedLock lock = this.lock; long stamp = lock.readLock(); try { ret = internalContainsAll(c, 0, -1); } finally { lock.unlockRead(stamp); } return ret; } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof List)) return false; final StampedLock lock = this.lock; long stamp = lock.readLock(); try { return internalEquals((List)o, 0, -1); } finally { lock.unlockRead(stamp); } } public E get(int index) { final StampedLock lock = this.lock; long stamp = lock.tryOptimisticRead(); Object[] items; if (index >= 0 && (items = array) != null && index < count && index < items.length) { @SuppressWarnings("unchecked") E e = (E)items[index]; if (lock.validate(stamp)) return e; } return lockedGet(index); } @SuppressWarnings("unchecked") private E lockedGet(int index) { boolean oobe = false; E e = null; final StampedLock lock = this.lock; long stamp = lock.readLock(); try { Object[] items; if ((items = array) != null && index < items.length && index < count && index >= 0) e = (E)items[index]; else oobe = true; } finally { lock.unlockRead(stamp); } if (oobe) throw new ArrayIndexOutOfBoundsException(index); return e; } public int hashCode() { int h; final StampedLock lock = this.lock; long s = lock.readLock(); try { h = internalHashCode(0, -1); } finally { lock.unlockRead(s); } return h; } public int indexOf(Object o) { int idx; final StampedLock lock = this.lock; long stamp = lock.readLock(); try { idx = findFirstIndex(array, o, 0, count); } finally { lock.unlockRead(stamp); } return idx; } public boolean isEmpty() { final StampedLock lock = this.lock; long stamp = lock.tryOptimisticRead(); return count == 0; // no need for validation } public Iterator iterator() { return new Itr(this, 0); } public int lastIndexOf(Object o) { int idx; final StampedLock lock = this.lock; long stamp = lock.readLock(); try { idx = findLastIndex(array, o, count - 1, 0); } finally { lock.unlockRead(stamp); } return idx; } public ListIterator listIterator() { return new Itr(this, 0); } public ListIterator listIterator(int index) { return new Itr(this, index); } @SuppressWarnings("unchecked") public E remove(int index) { E oldValue = null; boolean oobe = false; final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { if (index < 0 || index >= count) oobe = true; else { oldValue = (E) array[index]; rawRemoveAt(index); } } finally { lock.unlockWrite(stamp); } if (oobe) throw new ArrayIndexOutOfBoundsException(index); return oldValue; } public boolean remove(Object o) { final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { return rawRemoveAt(findFirstIndex(array, o, 0, count)); } finally { lock.unlockWrite(stamp); } } public boolean removeAll(Collection c) { return lockedRemoveAll(c, 0, -1); } public boolean retainAll(Collection c) { return lockedRetainAll(c, 0, -1); } @SuppressWarnings("unchecked") public E set(int index, E element) { E oldValue = null; boolean oobe = false; final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { Object[] items = array; if (items == null || index < 0 || index >= count) oobe = true; else { oldValue = (E) items[index]; items[index] = element; } } finally { lock.unlockWrite(stamp); } if (oobe) throw new ArrayIndexOutOfBoundsException(index); return oldValue; } public int size() { final StampedLock lock = this.lock; long stamp = lock.tryOptimisticRead(); return count; // no need for validation } private int lockedSize() { int n; final StampedLock lock = this.lock; long stamp = lock.readLock(); try { n = count; } finally { lock.unlockRead(stamp); } return n; } public List subList(int fromIndex, int toIndex) { int ssize = toIndex - fromIndex; if (ssize >= 0 && fromIndex >= 0) { ReadMostlyVectorSublist ret = null; final StampedLock lock = this.lock; long stamp = lock.readLock(); try { if (toIndex <= count) ret = new ReadMostlyVectorSublist(this, fromIndex, ssize); } finally { lock.unlockRead(stamp); } if (ret != null) return ret; } throw new ArrayIndexOutOfBoundsException(fromIndex < 0 ? fromIndex : toIndex); } public Object[] toArray() { final StampedLock lock = this.lock; long stamp = lock.readLock(); try { return internalToArray(0, -1); } finally { lock.unlockRead(stamp); } } public T[] toArray(T[] a) { final StampedLock lock = this.lock; long stamp = lock.readLock(); try { return internalToArray(a, 0, -1); } finally { lock.unlockRead(stamp); } } public String toString() { final StampedLock lock = this.lock; long stamp = lock.readLock(); try { return internalToString(0, -1); } finally { lock.unlockRead(stamp); } } // ReadMostlyVector-only methods /** * Appends the element, if not present. * * @param e element to be added to this list, if absent * @return {@code true} if the element was added */ public boolean addIfAbsent(E e) { boolean ret; final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { if (findFirstIndex(array, e, 0, count) < 0) { rawAdd(e); ret = true; } else ret = false; } finally { lock.unlockWrite(stamp); } return ret; } /** * Appends all of the elements in the specified collection that * are not already contained in this list, to the end of * this list, in the order that they are returned by the * specified collection's iterator. * * @param c collection containing elements to be added to this list * @return the number of elements added * @throws NullPointerException if the specified collection is null * @see #addIfAbsent(Object) */ public int addAllAbsent(Collection c) { int added = 0; Object[] cs = c.toArray(); int clen = cs.length; if (clen != 0) { long stamp = lock.writeLock(); try { for (int i = 0; i < clen; ++i) { @SuppressWarnings("unchecked") E e = (E) cs[i]; if (findFirstIndex(array, e, 0, count) < 0) { rawAdd(e); ++added; } } } finally { lock.unlockWrite(stamp); } } return added; } /** * Returns an iterator operating over a snapshot copy of the * elements of this collection created upon construction of the * iterator. The iterator does NOT support the * {@code remove} method. * * @return an iterator over the elements in this list in proper sequence */ public Iterator snapshotIterator() { return new SnapshotIterator(this); } static final class SnapshotIterator implements Iterator { private final Object[] items; private int cursor; SnapshotIterator(ReadMostlyVector v) { items = v.toArray(); } public boolean hasNext() { return cursor < items.length; } @SuppressWarnings("unchecked") public E next() { if (cursor < items.length) return (E) items[cursor++]; throw new NoSuchElementException(); } public void remove() { throw new UnsupportedOperationException() ; } } /** Interface describing a void action of one argument */ public interface Action { void apply(A a); } public void forEachReadOnly(Action action) { final StampedLock lock = this.lock; long stamp = lock.readLock(); try { Object[] items; int len, n; if ((items = array) != null && (len = items.length) > 0 && (n = count) <= len) { for (int i = 0; i < n; ++i) { @SuppressWarnings("unchecked") E e = (E)items[i]; action.apply(e); } } } finally { lock.unlockRead(stamp); } } // Vector-only methods /** See {@link Vector#firstElement} */ public E firstElement() { final StampedLock lock = this.lock; long stamp = lock.tryOptimisticRead(); Object[] items; if ((items = array) != null && count > 0 && items.length > 0) { @SuppressWarnings("unchecked") E e = (E)items[0]; if (lock.validate(stamp)) return e; } return lockedFirstElement(); } @SuppressWarnings("unchecked") private E lockedFirstElement() { Object e = null; boolean oobe = false; final StampedLock lock = this.lock; long stamp = lock.readLock(); try { Object[] items = array; if (items != null && count > 0 && items.length > 0) e = items[0]; else oobe = true; } finally { lock.unlockRead(stamp); } if (oobe) throw new NoSuchElementException(); return (E) e; } /** See {@link Vector#lastElement} */ public E lastElement() { final StampedLock lock = this.lock; long stamp = lock.tryOptimisticRead(); Object[] items; int i; if ((items = array) != null && (i = count - 1) >= 0 && i < items.length) { @SuppressWarnings("unchecked") E e = (E)items[i]; if (lock.validate(stamp)) return e; } return lockedLastElement(); } @SuppressWarnings("unchecked") private E lockedLastElement() { Object e = null; boolean oobe = false; final StampedLock lock = this.lock; long stamp = lock.readLock(); try { Object[] items = array; int i = count - 1; if (items != null && i >= 0 && i < items.length) e = items[i]; else oobe = true; } finally { lock.unlockRead(stamp); } if (oobe) throw new NoSuchElementException(); return (E) e; } /** See {@link Vector#indexOf(Object, int)} */ public int indexOf(Object o, int index) { if (index < 0) throw new ArrayIndexOutOfBoundsException(index); int idx; final StampedLock lock = this.lock; long stamp = lock.readLock(); try { idx = findFirstIndex(array, o, index, count); } finally { lock.unlockRead(stamp); } return idx; } /** See {@link Vector#lastIndexOf(Object, int)} */ public int lastIndexOf(Object o, int index) { boolean oobe = false; int idx = -1; final StampedLock lock = this.lock; long stamp = lock.readLock(); try { if (index < count) idx = findLastIndex(array, o, index, 0); else oobe = true; } finally { lock.unlockRead(stamp); } if (oobe) throw new ArrayIndexOutOfBoundsException(index); return idx; } /** See {@link Vector#setSize} */ public void setSize(int newSize) { if (newSize < 0) throw new ArrayIndexOutOfBoundsException(newSize); final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { Object[] items; int n = count; if (newSize > n) grow(newSize); else if ((items = array) != null) { for (int i = newSize ; i < n ; i++) items[i] = null; } count = newSize; } finally { lock.unlockWrite(stamp); } } /** See {@link Vector#copyInto} */ public void copyInto(Object[] anArray) { final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { Object[] items; if ((items = array) != null) System.arraycopy(items, 0, anArray, 0, count); } finally { lock.unlockWrite(stamp); } } /** See {@link Vector#trimToSize} */ public void trimToSize() { final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { Object[] items = array; int n = count; if (items != null && n < items.length) array = Arrays.copyOf(items, n); } finally { lock.unlockWrite(stamp); } } /** See {@link Vector#ensureCapacity} */ public void ensureCapacity(int minCapacity) { if (minCapacity > 0) { final StampedLock lock = this.lock; long stamp = lock.writeLock(); try { Object[] items = array; int cap = (items == null) ? 0 : items.length; if (minCapacity - cap > 0) grow(minCapacity); } finally { lock.unlockWrite(stamp); } } } /** See {@link Vector#elements} */ public Enumeration elements() { return new Itr(this, 0); } /** See {@link Vector#capacity} */ public int capacity() { return array.length; } /** See {@link Vector#elementAt} */ public E elementAt(int index) { return get(index); } /** See {@link Vector#setElementAt} */ public void setElementAt(E obj, int index) { set(index, obj); } /** See {@link Vector#removeElementAt} */ public void removeElementAt(int index) { remove(index); } /** See {@link Vector#insertElementAt} */ public void insertElementAt(E obj, int index) { add(index, obj); } /** See {@link Vector#addElement} */ public void addElement(E obj) { add(obj); } /** See {@link Vector#removeElement} */ public boolean removeElement(Object obj) { return remove(obj); } /** See {@link Vector#removeAllElements} */ public void removeAllElements() { clear(); } // other methods public ReadMostlyVector clone() { Object[] a = null; int n; final StampedLock lock = this.lock; long stamp = lock.readLock(); try { Object[] items = array; if (items == null) n = 0; else { int len = items.length; if ((n = count) > len) n = len; a = Arrays.copyOf(items, n); } } finally { lock.unlockRead(stamp); } return new ReadMostlyVector(a, n, capacityIncrement); } private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { final StampedLock lock = this.lock; long stamp = lock.readLock(); try { s.defaultWriteObject(); } finally { lock.unlockRead(stamp); } } static final class Itr implements ListIterator, Enumeration { final StampedLock lock; final ReadMostlyVector list; Object[] items; long seq; int cursor; int fence; int lastRet; Itr(ReadMostlyVector list, int index) { final StampedLock lock = list.lock; long stamp = lock.readLock(); try { this.list = list; this.lock = lock; this.items = list.array; this.fence = list.count; this.cursor = index; this.lastRet = -1; } finally { this.seq = lock.tryConvertToOptimisticRead(stamp); } if (index < 0 || index > fence) throw new ArrayIndexOutOfBoundsException(index); } public boolean hasPrevious() { return cursor > 0; } public int nextIndex() { return cursor; } public int previousIndex() { return cursor - 1; } public boolean hasNext() { return cursor < fence; } public E next() { int i = cursor; Object[] es = items; if (es == null || i < 0 || i >= fence || i >= es.length) throw new NoSuchElementException(); @SuppressWarnings("unchecked") E e = (E)es[i]; lastRet = i; cursor = i + 1; if (!lock.validate(seq)) throw new ConcurrentModificationException(); return e; } public E previous() { int i = cursor - 1; Object[] es = items; if (es == null || i < 0 || i >= fence || i >= es.length) throw new NoSuchElementException(); @SuppressWarnings("unchecked") E e = (E)es[i]; lastRet = i; cursor = i; if (!lock.validate(seq)) throw new ConcurrentModificationException(); return e; } public void remove() { int i = lastRet; if (i < 0) throw new IllegalStateException(); if ((seq = lock.tryConvertToWriteLock(seq)) == 0) throw new ConcurrentModificationException(); try { list.rawRemoveAt(i); fence = list.count; cursor = i; lastRet = -1; } finally { seq = lock.tryConvertToOptimisticRead(seq); } } public void set(E e) { int i = lastRet; Object[] es = items; if (es == null || i < 0 | i >= fence) throw new IllegalStateException(); if ((seq = lock.tryConvertToWriteLock(seq)) == 0) throw new ConcurrentModificationException(); try { es[i] = e; } finally { seq = lock.tryConvertToOptimisticRead(seq); } } public void add(E e) { int i = cursor; if (i < 0) throw new IllegalStateException(); if ((seq = lock.tryConvertToWriteLock(seq)) == 0) throw new ConcurrentModificationException(); try { list.rawAddAt(i, e); items = list.array; fence = list.count; cursor = i + 1; lastRet = -1; } finally { seq = lock.tryConvertToOptimisticRead(seq); } } public boolean hasMoreElements() { return hasNext(); } public E nextElement() { return next(); } } static final class ReadMostlyVectorSublist implements List, RandomAccess, java.io.Serializable { private static final long serialVersionUID = 3041673470172026059L; final ReadMostlyVector list; final int offset; volatile int size; ReadMostlyVectorSublist(ReadMostlyVector list, int offset, int size) { this.list = list; this.offset = offset; this.size = size; } private void rangeCheck(int index) { if (index < 0 || index >= size) throw new ArrayIndexOutOfBoundsException(index); } public boolean add(E element) { final StampedLock lock = list.lock; long stamp = lock.writeLock(); try { int c = size; list.rawAddAt(c + offset, element); size = c + 1; } finally { lock.unlockWrite(stamp); } return true; } public void add(int index, E element) { final StampedLock lock = list.lock; long stamp = lock.writeLock(); try { if (index < 0 || index > size) throw new ArrayIndexOutOfBoundsException(index); list.rawAddAt(index + offset, element); ++size; } finally { lock.unlockWrite(stamp); } } public boolean addAll(Collection c) { Object[] elements = c.toArray(); final StampedLock lock = list.lock; long stamp = lock.writeLock(); try { int s = size; int pc = list.count; list.rawAddAllAt(offset + s, elements); int added = list.count - pc; size = s + added; return added != 0; } finally { lock.unlockWrite(stamp); } } public boolean addAll(int index, Collection c) { Object[] elements = c.toArray(); final StampedLock lock = list.lock; long stamp = lock.writeLock(); try { int s = size; if (index < 0 || index > s) throw new ArrayIndexOutOfBoundsException(index); int pc = list.count; list.rawAddAllAt(index + offset, elements); int added = list.count - pc; size = s + added; return added != 0; } finally { lock.unlockWrite(stamp); } } public void clear() { final StampedLock lock = list.lock; long stamp = lock.writeLock(); try { list.internalClear(offset, offset + size); size = 0; } finally { lock.unlockWrite(stamp); } } public boolean contains(Object o) { return indexOf(o) >= 0; } public boolean containsAll(Collection c) { final StampedLock lock = list.lock; long stamp = lock.readLock(); try { return list.internalContainsAll(c, offset, offset + size); } finally { lock.unlockRead(stamp); } } public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof List)) return false; final StampedLock lock = list.lock; long stamp = lock.readLock(); try { return list.internalEquals((List)(o), offset, offset + size); } finally { lock.unlockRead(stamp); } } public E get(int index) { if (index < 0 || index >= size) throw new ArrayIndexOutOfBoundsException(index); return list.get(index + offset); } public int hashCode() { final StampedLock lock = list.lock; long stamp = lock.readLock(); try { return list.internalHashCode(offset, offset + size); } finally { lock.unlockRead(stamp); } } public int indexOf(Object o) { final StampedLock lock = list.lock; long stamp = lock.readLock(); try { int idx = findFirstIndex(list.array, o, offset, offset + size); return idx < 0 ? -1 : idx - offset; } finally { lock.unlockRead(stamp); } } public boolean isEmpty() { return size() == 0; } public Iterator iterator() { return new SubItr(this, offset); } public int lastIndexOf(Object o) { final StampedLock lock = list.lock; long stamp = lock.readLock(); try { int idx = findLastIndex(list.array, o, offset + size - 1, offset); return idx < 0 ? -1 : idx - offset; } finally { lock.unlockRead(stamp); } } public ListIterator listIterator() { return new SubItr(this, offset); } public ListIterator listIterator(int index) { return new SubItr(this, index + offset); } public E remove(int index) { final StampedLock lock = list.lock; long stamp = lock.writeLock(); try { Object[] items = list.array; int i = index + offset; if (items == null || index < 0 || index >= size || i >= items.length) throw new ArrayIndexOutOfBoundsException(index); @SuppressWarnings("unchecked") E result = (E)items[i]; list.rawRemoveAt(i); size--; return result; } finally { lock.unlockWrite(stamp); } } public boolean remove(Object o) { final StampedLock lock = list.lock; long stamp = lock.writeLock(); try { if (list.rawRemoveAt(findFirstIndex(list.array, o, offset, offset + size))) { --size; return true; } else return false; } finally { lock.unlockWrite(stamp); } } public boolean removeAll(Collection c) { return list.lockedRemoveAll(c, offset, offset + size); } public boolean retainAll(Collection c) { return list.lockedRetainAll(c, offset, offset + size); } public E set(int index, E element) { if (index < 0 || index >= size) throw new ArrayIndexOutOfBoundsException(index); return list.set(index+offset, element); } public int size() { return size; } public List subList(int fromIndex, int toIndex) { int c = size; int ssize = toIndex - fromIndex; if (fromIndex < 0) throw new ArrayIndexOutOfBoundsException(fromIndex); if (toIndex > c || ssize < 0) throw new ArrayIndexOutOfBoundsException(toIndex); return new ReadMostlyVectorSublist(list, offset+fromIndex, ssize); } public Object[] toArray() { final StampedLock lock = list.lock; long stamp = lock.readLock(); try { return list.internalToArray(offset, offset + size); } finally { lock.unlockRead(stamp); } } public T[] toArray(T[] a) { final StampedLock lock = list.lock; long stamp = lock.readLock(); try { return list.internalToArray(a, offset, offset + size); } finally { lock.unlockRead(stamp); } } public String toString() { final StampedLock lock = list.lock; long stamp = lock.readLock(); try { return list.internalToString(offset, offset + size); } finally { lock.unlockRead(stamp); } } } static final class SubItr implements ListIterator { final ReadMostlyVectorSublist sublist; final ReadMostlyVector list; final StampedLock lock; Object[] items; long seq; int cursor; int origin; int fence; int lastRet; SubItr(ReadMostlyVectorSublist sublist, int index) { final StampedLock lock = sublist.list.lock; long stamp = lock.readLock(); try { this.sublist = sublist; this.list = sublist.list; this.lock = lock; this.cursor = index; this.origin = sublist.offset; this.fence = origin + sublist.size; this.lastRet = -1; } finally { this.seq = lock.tryConvertToOptimisticRead(stamp); } if (index < 0 || cursor > fence) throw new ArrayIndexOutOfBoundsException(index); } public int nextIndex() { return cursor - origin; } public int previousIndex() { return cursor - origin - 1; } public boolean hasNext() { return cursor < fence; } public boolean hasPrevious() { return cursor > origin; } public E next() { int i = cursor; Object[] es = items; if (es == null || i < origin || i >= fence || i >= es.length) throw new NoSuchElementException(); @SuppressWarnings("unchecked") E e = (E)es[i]; lastRet = i; cursor = i + 1; if (!lock.validate(seq)) throw new ConcurrentModificationException(); return e; } public E previous() { int i = cursor - 1; Object[] es = items; if (es == null || i < 0 || i >= fence || i >= es.length) throw new NoSuchElementException(); @SuppressWarnings("unchecked") E e = (E)es[i]; lastRet = i; cursor = i; if (!lock.validate(seq)) throw new ConcurrentModificationException(); return e; } public void remove() { int i = lastRet; if (i < 0) throw new IllegalStateException(); if ((seq = lock.tryConvertToWriteLock(seq)) == 0) throw new ConcurrentModificationException(); try { list.rawRemoveAt(i); fence = origin + sublist.size; cursor = i; lastRet = -1; } finally { seq = lock.tryConvertToOptimisticRead(seq); } } public void set(E e) { int i = lastRet; if (i < origin || i >= fence) throw new IllegalStateException(); if ((seq = lock.tryConvertToWriteLock(seq)) == 0) throw new ConcurrentModificationException(); try { list.set(i, e); } finally { seq = lock.tryConvertToOptimisticRead(seq); } } public void add(E e) { int i = cursor; if (i < origin || i >= fence) throw new IllegalStateException(); if ((seq = lock.tryConvertToWriteLock(seq)) == 0) throw new ConcurrentModificationException(); try { list.rawAddAt(i, e); items = list.array; fence = origin + sublist.size; cursor = i + 1; lastRet = -1; } finally { seq = lock.tryConvertToOptimisticRead(seq); } } } }