--- jsr166/src/jsr166e/extra/ReadMostlyVector.java 2011/07/15 23:56:18 1.1 +++ jsr166/src/jsr166e/extra/ReadMostlyVector.java 2012/08/13 11:20:39 1.27 @@ -9,18 +9,20 @@ import jsr166e.*; import java.util.*; /** - * A class with the same API and array-based characteristics as {@link - * java.util.Vector} but with reduced contention and improved + * 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. Instances of this class may have - * relatively poorer performance in other contexts. + * 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. + * 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 @@ -30,13 +32,28 @@ import java.util.*; * * @author Doug Lea */ -public class ReadMostlyVector implements List, RandomAccess, Cloneable, java.io.Serializable { +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, which are not yet explained - * well here. + * 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 */ /** @@ -45,10 +62,10 @@ public class ReadMostlyVector impleme */ private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; - // fields are non-private to simpify nested class access - Object[] array; + // fields are non-private to simplify nested class access + volatile Object[] array; final SequenceLock lock; - int count; + volatile int count; final int capacityIncrement; /** @@ -118,7 +135,7 @@ public class ReadMostlyVector impleme } // For explanation, see CopyOnWriteArrayList - final void grow(int minCapacity) { + final Object[] grow(int minCapacity) { int oldCapacity = array.length; int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity); @@ -126,7 +143,7 @@ public class ReadMostlyVector impleme newCapacity = minCapacity; if (newCapacity - MAX_ARRAY_SIZE > 0) newCapacity = hugeCapacity(minCapacity); - array = Arrays.copyOf(array, newCapacity); + return array = Arrays.copyOf(array, newCapacity); } static int hugeCapacity(int minCapacity) { @@ -143,94 +160,129 @@ public class ReadMostlyVector impleme * as well as sublist and iterator classes. */ - static int internalIndexOf(Object o, Object[] items, - int index, int fence) { + /** + * Version of indexOf that returns -1 if either not present or invalid. + * + * @throws ArrayIndexOutOfBoundsException if index is negative + */ + final int validatedIndexOf(Object x, Object[] items, int index, int fence, + long seq) { + for (int i = index; i < fence; ++i) { + Object e = items[i]; + if (lock.getSequence() != seq) + break; + if ((x == null) ? e == null : x.equals(e)) + return i; + } + return -1; + } + + /** + * @throws ArrayIndexOutOfBoundsException if index is negative + */ + final int rawIndexOf(Object x, int index, int fence) { + Object[] items = array; for (int i = index; i < fence; ++i) { - Object x = items[i]; - if (o == null? x == null : (x != null && o.equals(x))) + Object e = items[i]; + if ((x == null) ? e == null : x.equals(e)) return i; } return -1; } - static int internalLastIndexOf(Object o, Object[] items, - int index, int origin) { + final int validatedLastIndexOf(Object x, Object[] items, + int index, int origin, long seq) { for (int i = index; i >= origin; --i) { - Object x = items[i]; - if (o == null? x == null : (x != null && o.equals(x))) + Object e = items[i]; + if (lock.getSequence() != seq) + break; + if ((x == null) ? e == null : x.equals(e)) return i; } return -1; } - final void internalAdd(E e) { - int c = count; - if (c >= array.length) - grow(c + 1); - array[c] = e; - count = c + 1; + final int rawLastIndexOf(Object x, int index, int origin) { + Object[] items = array; + for (int i = index; i >= origin; --i) { + Object e = items[i]; + if ((x == null) ? e == null : x.equals(e)) + return i; + } + return -1; } - final void internalAddAt(int index, E e) { - int c = count; - if (index > c) + final void rawAdd(E e) { + int n = count; + Object[] items = array; + if (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 (c >= array.length) - grow(c + 1); - System.arraycopy(array, index, array, index + 1, c - index); - array[index] = e; - count = c + 1; + if (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 internalAddAllAt(int index, Object[] elements) { - int c = count; - if (index < 0 || index > c) + 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 = c + len; - if (newCount >= array.length) - grow(newCount); - int mv = count - index; + int newCount = n + len; + if (newCount >= items.length) + items = grow(newCount); + int mv = n - index; if (mv > 0) - System.arraycopy(array, index, array, index + len, mv); - System.arraycopy(elements, 0, array, index, len); + System.arraycopy(items, index, items, index + len, mv); + System.arraycopy(elements, 0, items, index, len); count = newCount; return true; } - final boolean internalRemoveAt(int index) { - int c = count - 1; - if (index < 0 || index > c) + final boolean rawRemoveAt(int index) { + int n = count - 1; + Object[] items = array; + if (index < 0 || index > n) return false; - int mv = c - index; + int mv = n - index; if (mv > 0) - System.arraycopy(array, index + 1, array, index, mv); - array[c] = null; - count = c; + 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 span argument is, if - * non-negative, the purported size of a list/sublist, or is left - * negative if the size should be determined via count field under - * lock. + * 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 internalRemoveAll(Collection c, int origin, int span) { - SequenceLock lock = this.lock; + final boolean internalRemoveAll(Collection c, int origin, int bound) { + final SequenceLock lock = this.lock; boolean removed = false; lock.lock(); try { - int fence = count; - if (span >= 0 && origin + span < fence) - fence = origin + span; + int n = count; + int fence = bound < 0 || bound > n ? n : bound; if (origin >= 0 && origin < fence) { for (Object x : c) { - while (internalRemoveAt(internalIndexOf(x, array, - origin, fence))) + while (rawRemoveAt(rawIndexOf(x, origin, fence))) removed = true; } } @@ -240,27 +292,30 @@ public class ReadMostlyVector impleme return removed; } - final boolean internalRetainAll(Collection c, int origin, int span) { - SequenceLock lock = this.lock; + final boolean internalRetainAll(Collection c, int origin, int bound) { + final SequenceLock lock = this.lock; boolean removed = false; if (c != this) { lock.lock(); try { + Object[] items = array; int i = origin; - int fence = count; - if (span >= 0 && origin + span < fence) - fence = origin + span; - while (i < fence) { - if (c.contains(array[i])) + int n = count; + int fence = bound < 0 || bound > n ? n : bound; + while (i >= 0 && i < fence) { + if (c.contains(items[i])) ++i; else { --fence; - int mv = --count - i; + int mv = --n - i; if (mv > 0) - System.arraycopy(array, i + 1, array, i, mv); - removed = true; + System.arraycopy(items, i + 1, items, i, mv); } } + if (count != n) { + count = n; + removed = true; + } } finally { lock.unlock(); } @@ -268,44 +323,45 @@ public class ReadMostlyVector impleme return removed; } - final void internalClear(int origin, int span) { - int c = count; - int fence = c; - if (span >= 0 && origin + span < fence) - fence = origin + span; + final void internalClear(int origin, int bound) { + int n = count; + int fence = bound < 0 || bound > n ? n : bound; if (origin >= 0 && origin < fence) { + Object[] items = array; int removed = fence - origin; - int newCount = c - removed; - int mv = c - (origin + removed); + int newCount = n - removed; + int mv = n - (origin + removed); if (mv > 0) - System.arraycopy(array, origin + removed, array, origin, mv); - for (int i = c; i < newCount; ++i) - array[i] = null; + System.arraycopy(items, origin + removed, items, origin, mv); + for (int i = n; i < newCount; ++i) + items[i] = null; count = newCount; } } - final boolean internalContainsAll(Collection coll, int origin, int span) { - SequenceLock lock = this.lock; + final boolean internalContainsAll(Collection c, int origin, int bound) { + final SequenceLock lock = this.lock; boolean contained; boolean locked = false; try { for (;;) { long seq = lock.awaitAvailability(); + int n = count; Object[] items = array; int len = items.length; - int c = count; - if (c > len) + if (n > len) continue; - int fence = c; - if (span >= 0 && origin + span < fence) - fence = origin + span; - if (origin < 0 || fence > c) + int fence = bound < 0 || bound > n ? n : bound; + if (origin < 0) contained = false; else { contained = true; - for (Object e : coll) { - if (internalIndexOf(e, items, origin, fence) < 0) { + for (Object e : c) { + int idx = (locked ? + rawIndexOf(e, origin, fence) : + validatedIndexOf(e, items, origin, + fence, seq)); + if (idx < 0) { contained = false; break; } @@ -323,34 +379,28 @@ public class ReadMostlyVector impleme return contained; } - final boolean internalEquals(List list, int origin, int span) { - SequenceLock lock = this.lock; - boolean equal; + final boolean internalEquals(List list, int origin, int bound) { + final SequenceLock lock = this.lock; boolean locked = false; + boolean equal; try { for (;;) { - equal = true; long seq = lock.awaitAvailability(); Object[] items = array; - int len = items.length; - int c = count; - if (c > len) - continue; - int fence = c; - if (span >= 0 && origin + span < fence) - fence = origin + span; - if (origin < 0 || fence > c) + int n = count; + if (n > items.length || origin < 0) equal = false; else { + equal = true; + int fence = bound < 0 || bound > n ? n : bound; Iterator it = list.iterator(); for (int i = origin; i < fence; ++i) { - if (!it.hasNext()) { - equal = false; - break; - } - Object x = it.next(); - Object y = items[i]; - if (x == null? y != null : (y == null || !x.equals(y))) { + Object x = items[i]; + Object y; + if ((!locked && lock.getSequence() != seq) || + !it.hasNext() || + (y = it.next()) == null ? + x != null : !y.equals(x)) { equal = false; break; } @@ -370,8 +420,8 @@ public class ReadMostlyVector impleme return equal; } - final int internalHashCode(int origin, int span) { - SequenceLock lock = this.lock; + final int internalHashCode(int origin, int bound) { + final SequenceLock lock = this.lock; int hash; boolean locked = false; try { @@ -379,14 +429,12 @@ public class ReadMostlyVector impleme hash = 1; long seq = lock.awaitAvailability(); Object[] items = array; + int n = count; int len = items.length; - int c = count; - if (c > len) + if (n > len) continue; - int fence = c; - if (span >= 0 && origin + span < fence) - fence = origin + span; - if (origin >= 0 && fence <= c) { + int fence = bound < 0 || bound > n ? n : bound; + if (origin >= 0) { for (int i = origin; i < fence; ++i) { Object e = items[i]; hash = 31*hash + (e == null ? 0 : e.hashCode()); @@ -404,41 +452,42 @@ public class ReadMostlyVector impleme return hash; } - final String internalToString(int origin, int span) { - SequenceLock lock = this.lock; + final String internalToString(int origin, int bound) { + final SequenceLock lock = this.lock; String ret; boolean locked = false; try { - for (;;) { + outer:for (;;) { long seq = lock.awaitAvailability(); Object[] items = array; + int n = count; int len = items.length; - int c = count; - if (c > len) + if (n > len) continue; - int fence = c; - if (span >= 0 && origin + span < fence) - fence = origin + span; - if (origin >= 0 && fence <= c) { - if (origin == fence) - ret = "[]"; - else { - StringBuilder sb = new StringBuilder(); - sb.append('['); - for (int i = origin;;) { - Object e = items[i]; - sb.append(e == this ? "(this Collection)" : e); - if (++i < fence) - sb.append(',').append(' '); - else { - ret = sb.append(']').toString(); - break; - } + int fence = bound < 0 || bound > n ? n : bound; + if (origin < 0 || origin == fence) + ret = "[]"; + else { + StringBuilder sb = new StringBuilder(); + sb.append('['); + for (int i = origin;;) { + Object e = items[i]; + if (e == this) + sb.append("(this Collection)"); + else if (!locked && lock.getSequence() != seq) + continue outer; + else + sb.append(e.toString()); + if (++i < fence) + sb.append(',').append(' '); + else { + ret = sb.append(']').toString(); + break; } } - if (lock.getSequence() == seq) - break; } + if (lock.getSequence() == seq) + break; lock.lock(); locked = true; } @@ -449,26 +498,25 @@ public class ReadMostlyVector impleme return ret; } - final Object[] internalToArray(int origin, int span) { + final Object[] internalToArray(int origin, int bound) { Object[] result; - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; boolean locked = false; try { for (;;) { result = null; long seq = lock.awaitAvailability(); Object[] items = array; + int n = count; int len = items.length; - int c = count; - int fence = c; - if (span >= 0 && origin + span < fence) - fence = origin + span; - if (c <= len && fence <= len) { + if (n > len) + continue; + int fence = bound < 0 || bound > n ? n : bound; + if (origin >= 0) result = Arrays.copyOfRange(items, origin, fence, Object[].class); - if (lock.getSequence() == seq) - break; - } + if (lock.getSequence() == seq) + break; lock.lock(); locked = true; } @@ -479,33 +527,36 @@ public class ReadMostlyVector impleme return result; } - final T[] internalToArray(T[] a, int origin, int span) { + @SuppressWarnings("unchecked") + final T[] internalToArray(T[] a, int origin, int bound) { + int alen = a.length; T[] result; - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; boolean locked = false; try { for (;;) { long seq = lock.awaitAvailability(); Object[] items = array; + int n = count; int len = items.length; - int c = count; - int fence = c; - if (span >= 0 && origin + span < fence) - fence = origin + span; - if (c <= len && fence <= len) { - if (a.length < count) - result = (T[]) Arrays.copyOfRange(array, origin, - fence, a.getClass()); - else { - int n = fence - origin; - System.arraycopy(array, 0, a, origin, fence - origin); - if (a.length > n) - a[n] = null; - result = a; - } - if (lock.getSequence() == seq) - break; + if (n > len) + continue; + int fence = bound < 0 || bound > n ? n : bound; + int rlen = fence - origin; + if (rlen < 0) + rlen = 0; + if (origin < 0 || alen >= rlen) { + if (rlen > 0) + System.arraycopy(items, 0, a, origin, rlen); + if (alen > rlen) + a[rlen] = null; + result = a; } + else + result = (T[]) Arrays.copyOfRange(items, origin, + fence, a.getClass()); + if (lock.getSequence() == seq) + break; lock.lock(); locked = true; } @@ -519,10 +570,10 @@ public class ReadMostlyVector impleme // public List methods public boolean add(E e) { - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; lock.lock(); try { - internalAdd(e); + rawAdd(e); } finally { lock.unlock(); } @@ -530,10 +581,10 @@ public class ReadMostlyVector impleme } public void add(int index, E element) { - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; lock.lock(); try { - internalAddAt(index, element); + rawAddAt(index, element); } finally { lock.unlock(); } @@ -544,13 +595,15 @@ public class ReadMostlyVector impleme int len = elements.length; if (len == 0) return false; - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; lock.lock(); try { - int newCount = count + len; - if (newCount >= array.length) - grow(newCount); - System.arraycopy(elements, 0, array, count, len); + Object[] items = array; + int n = count; + int newCount = n + len; + if (newCount >= items.length) + items = grow(newCount); + System.arraycopy(elements, 0, items, n, len); count = newCount; } finally { lock.unlock(); @@ -559,12 +612,12 @@ public class ReadMostlyVector impleme } public boolean addAll(int index, Collection c) { - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; boolean ret; Object[] elements = c.toArray(); lock.lock(); try { - ret = internalAddAllAt(index, elements); + ret = rawAddAllAt(index, elements); } finally { lock.unlock(); } @@ -572,11 +625,13 @@ public class ReadMostlyVector impleme } public void clear() { - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; lock.lock(); try { - for (int i = 0; i < count; i++) - array[i] = null; + int n = count; + Object[] items = array; + for (int i = 0; i < n; i++) + items[i] = null; count = 0; } finally { lock.unlock(); @@ -596,32 +651,21 @@ public class ReadMostlyVector impleme return true; if (!(o instanceof List)) return false; - return internalEquals((List)(o), 0, -1); + return internalEquals((List)o, 0, -1); } public E get(int index) { - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; for (;;) { long seq = lock.awaitAvailability(); + int n = count; Object[] items = array; - int len = items.length; - int c = count; - if (c > len) - continue; - E e; boolean ex; - if (index < 0 || index >= c) { - e = null; - ex = true; - } - else { - e = (E)items[index]; - ex = false; - } + @SuppressWarnings("unchecked") + E e = (index < items.length) ? (E) items[index] : null; if (lock.getSequence() == seq) { - if (ex) + if (index >= n) throw new ArrayIndexOutOfBoundsException(index); - else - return e; + return e; } } } @@ -631,83 +675,73 @@ public class ReadMostlyVector impleme } public int indexOf(Object o) { - SequenceLock lock = this.lock; - long seq = lock.awaitAvailability(); - Object[] items = array; - int c = count; - if (c <= items.length) { - int idx = internalIndexOf(o, items, 0, c); - if (lock.getSequence() == seq) - return idx; - } - lock.lock(); - try { - return internalIndexOf(o, array, 0, count); - } finally { - lock.unlock(); - } + return indexOf(o, 0); } public boolean isEmpty() { - long ignore = lock.getSequence(); return count == 0; } public Iterator iterator() { - return new Itr(this, 0); + return new Itr(this, 0); } public int lastIndexOf(Object o) { - SequenceLock lock = this.lock; - long seq = lock.awaitAvailability(); - Object[] items = array; - int c = count; - if (c <= items.length) { - int idx = internalLastIndexOf(o, items, c - 1, 0); - if (lock.getSequence() == seq) - return idx; - } - lock.lock(); - try { - return internalLastIndexOf(o, array, count-1, 0); - } finally { - lock.unlock(); + final SequenceLock lock = this.lock; + for (;;) { + long seq = lock.awaitAvailability(); + Object[] items = array; + int n = count; + if (n <= items.length) { + for (int i = n - 1; i >= 0; --i) { + Object e = items[i]; + if (lock.getSequence() != seq) { + lock.lock(); + try { + return rawLastIndexOf(o, count - 1, 0); + } finally { + lock.unlock(); + } + } + else if ((o == null) ? e == null : o.equals(e)) + return i; + } + return -1; + } } } public ListIterator listIterator() { - return new Itr(this, 0); + return new Itr(this, 0); } public ListIterator listIterator(int index) { - return new Itr(this, index); + return new Itr(this, index); } public E remove(int index) { - SequenceLock lock = this.lock; - E oldValue; + final SequenceLock lock = this.lock; lock.lock(); try { if (index < 0 || index >= count) throw new ArrayIndexOutOfBoundsException(index); - oldValue = (E)array[index]; - internalRemoveAt(index); + @SuppressWarnings("unchecked") + E oldValue = (E) array[index]; + rawRemoveAt(index); + return oldValue; } finally { lock.unlock(); } - return oldValue; } public boolean remove(Object o) { - SequenceLock lock = this.lock; - boolean removed; + final SequenceLock lock = this.lock; lock.lock(); try { - removed = internalRemoveAt(internalIndexOf(o, array, 0, count)); + return rawRemoveAt(rawIndexOf(o, 0, count)); } finally { lock.unlock(); } - return removed; } public boolean removeAll(Collection c) { @@ -719,22 +753,22 @@ public class ReadMostlyVector impleme } public E set(int index, E element) { - E oldValue; - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; lock.lock(); try { + Object[] items = array; if (index < 0 || index >= count) throw new ArrayIndexOutOfBoundsException(index); - oldValue = (E)array[index]; - array[index] = element; + @SuppressWarnings("unchecked") + E oldValue = (E) items[index]; + items[index] = element; + return oldValue; } finally { lock.unlock(); } - return oldValue; } public int size() { - long ignore = lock.getSequence(); return count; } @@ -743,7 +777,7 @@ public class ReadMostlyVector impleme int ssize = toIndex - fromIndex; if (fromIndex < 0 || toIndex > c || ssize < 0) throw new IndexOutOfBoundsException(); - return new ReadMostlyVectorSublist(this, fromIndex, ssize); + return new ReadMostlyVectorSublist(this, fromIndex, ssize); } public Object[] toArray() { @@ -761,26 +795,24 @@ public class ReadMostlyVector impleme // ReadMostlyVector-only methods /** - * Append the element if not present. + * Appends the element, if not present. * * @param e element to be added to this list, if absent - * @return true if the element was added + * @return {@code true} if the element was added */ public boolean addIfAbsent(E e) { - boolean added; - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; lock.lock(); try { - if (internalIndexOf(e, array, 0, count) < 0) { - internalAdd(e); - added = true; + if (rawIndexOf(e, 0, count) < 0) { + rawAdd(e); + return true; } else - added = false; + return false; } finally { lock.unlock(); } - return added; } /** @@ -802,9 +834,10 @@ public class ReadMostlyVector impleme lock.lock(); try { for (int i = 0; i < clen; ++i) { - Object e = cs[i]; - if (internalIndexOf(e, array, 0, count) < 0) { - internalAdd((E)e); + @SuppressWarnings("unchecked") + E e = (E) cs[i]; + if (rawIndexOf(e, 0, count) < 0) { + rawAdd(e); ++added; } } @@ -815,123 +848,110 @@ public class ReadMostlyVector impleme 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() ; } + } + // Vector-only methods /** See {@link Vector#firstElement} */ public E firstElement() { - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; for (;;) { long seq = lock.awaitAvailability(); Object[] items = array; - int len = items.length; - int c = count; - if (c > len || c < 0) - continue; - E e; boolean ex; - if (c == 0) { - e = null; - ex = true; - } - else { - e = (E)items[0]; - ex = false; - } + int n = count; + @SuppressWarnings("unchecked") + E e = (items.length > 0) ? (E) items[0] : null; if (lock.getSequence() == seq) { - if (ex) + if (n <= 0) throw new NoSuchElementException(); - else - return e; + return e; } } } /** See {@link Vector#lastElement} */ public E lastElement() { - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; for (;;) { long seq = lock.awaitAvailability(); Object[] items = array; - int len = items.length; - int c = count; - if (c > len || c < 0) - continue; - E e; boolean ex; - if (c == 0) { - e = null; - ex = true; - } - else { - e = (E)items[c - 1]; - ex = false; - } + int n = count; + @SuppressWarnings("unchecked") + E e = (n > 0 && items.length >= n) ? (E) items[n - 1] : null; if (lock.getSequence() == seq) { - if (ex) + if (n <= 0) throw new NoSuchElementException(); - else - return e; + return e; } } } /** See {@link Vector#indexOf(Object, int)} */ public int indexOf(Object o, int index) { - SequenceLock lock = this.lock; - int idx = 0; - boolean ex = false; + final SequenceLock lock = this.lock; long seq = lock.awaitAvailability(); Object[] items = array; - int c = count; - boolean retry = false; - if (c > items.length) - retry = true; - else if (index < 0) - ex = true; - else - idx = internalIndexOf(o, items, index, c); - if (retry || lock.getSequence() != seq) { + int n = count; + int idx = -1; + if (n <= items.length) + idx = validatedIndexOf(o, items, index, n, seq); + if (lock.getSequence() != seq) { lock.lock(); try { - if (index < 0) - ex = true; - else - idx = internalIndexOf(o, array, 0, count); + idx = rawIndexOf(o, index, count); } finally { lock.unlock(); } } - if (ex) - throw new ArrayIndexOutOfBoundsException(index); + // Above code will throw AIOOBE when index < 0 return idx; } /** See {@link Vector#lastIndexOf(Object, int)} */ public int lastIndexOf(Object o, int index) { - SequenceLock lock = this.lock; - int idx = 0; - boolean ex = false; + final SequenceLock lock = this.lock; long seq = lock.awaitAvailability(); Object[] items = array; - int c = count; - boolean retry = false; - if (c > items.length) - retry = true; - else if (index >= c) - ex = true; - else - idx = internalLastIndexOf(o, items, index, 0); - if (retry || lock.getSequence() != seq) { + int n = count; + int idx = -1; + if (index < Math.min(n, items.length)) + idx = validatedLastIndexOf(o, items, index, 0, seq); + if (lock.getSequence() != seq) { lock.lock(); try { - if (index >= count) - ex = true; - else - idx = internalLastIndexOf(o, array, index, 0); + n = count; + if (index < n) + idx = rawLastIndexOf(o, index, 0); } finally { lock.unlock(); } } - if (ex) - throw new ArrayIndexOutOfBoundsException(index); + if (index >= n) + throw new IndexOutOfBoundsException(index + " >= " + n); return idx; } @@ -939,15 +959,16 @@ public class ReadMostlyVector impleme public void setSize(int newSize) { if (newSize < 0) throw new ArrayIndexOutOfBoundsException(newSize); - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; lock.lock(); try { - int c = count; - if (newSize > c) + int n = count; + if (newSize > n) grow(newSize); else { - for (int i = newSize ; i < c ; i++) - array[i] = null; + Object[] items = array; + for (int i = newSize ; i < n ; i++) + items[i] = null; } count = newSize; } finally { @@ -957,7 +978,7 @@ public class ReadMostlyVector impleme /** See {@link Vector#copyInto} */ public void copyInto(Object[] anArray) { - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; lock.lock(); try { System.arraycopy(array, 0, anArray, 0, count); @@ -968,11 +989,13 @@ public class ReadMostlyVector impleme /** See {@link Vector#trimToSize} */ public void trimToSize() { - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; lock.lock(); try { - if (count < array.length) - array = Arrays.copyOf(array, count); + Object[] items = array; + int n = count; + if (n < items.length) + array = Arrays.copyOf(items, n); } finally { lock.unlock(); } @@ -981,7 +1004,7 @@ public class ReadMostlyVector impleme /** See {@link Vector#ensureCapacity} */ public void ensureCapacity(int minCapacity) { if (minCapacity > 0) { - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; lock.lock(); try { if (minCapacity - array.length > 0) @@ -994,12 +1017,11 @@ public class ReadMostlyVector impleme /** See {@link Vector#elements} */ public Enumeration elements() { - return new Itr(this, 0); + return new Itr(this, 0); } /** See {@link Vector#capacity} */ public int capacity() { - long ignore = lock.getSequence(); return array.length; } @@ -1040,33 +1062,32 @@ public class ReadMostlyVector impleme // other methods - public Object clone() { - SequenceLock lock = this.lock; + public ReadMostlyVector clone() { + final SequenceLock lock = this.lock; Object[] a = null; - int c; boolean retry = false; long seq = lock.awaitAvailability(); Object[] items = array; - c = count; - if (c <= items.length) - a = Arrays.copyOf(items, c); + int n = count; + if (n <= items.length) + a = Arrays.copyOf(items, n); else retry = true; if (retry || lock.getSequence() != seq) { lock.lock(); try { - c = count; - a = Arrays.copyOf(array, c); + n = count; + a = Arrays.copyOf(array, n); } finally { lock.unlock(); } } - return new ReadMostlyVector(a, c, capacityIncrement); + return new ReadMostlyVector(a, n, capacityIncrement); } private void writeObject(java.io.ObjectOutputStream s) throws java.io.IOException { - SequenceLock lock = this.lock; + final SequenceLock lock = this.lock; lock.lock(); try { s.defaultWriteObject(); @@ -1075,16 +1096,16 @@ public class ReadMostlyVector impleme } } - static final class Itr implements ListIterator, Enumeration { + static final class Itr implements ListIterator, Enumeration { final ReadMostlyVector list; final SequenceLock lock; Object[] items; - Object next, prev; + E next, prev; long seq; int cursor; int fence; int lastRet; - boolean haveNext, havePrev; + boolean validNext, validPrev; Itr(ReadMostlyVector list, int index) { this.list = list; @@ -1097,51 +1118,68 @@ public class ReadMostlyVector impleme } private void refresh() { + validNext = validPrev = false; do { seq = lock.awaitAvailability(); items = list.array; - fence = list.count; - } while (lock.getSequence() != seq); + } while ((fence = list.count) > items.length || + lock.getSequence() != seq); } + @SuppressWarnings("unchecked") public boolean hasNext() { + boolean valid; int i = cursor; - while (i < fence && i >= 0) { + for (;;) { + if (i >= fence || i < 0 || i >= items.length) { + valid = false; + break; + } + next = (E) items[i]; if (lock.getSequence() == seq) { - next = items[i]; - return haveNext = true; + valid = true; + break; } refresh(); } - return false; + return validNext = valid; } + @SuppressWarnings("unchecked") public boolean hasPrevious() { - int i = cursor; - while (i <= fence && i > 0) { + boolean valid; + int i = cursor - 1; + for (;;) { + if (i >= fence || i < 0 || i >= items.length) { + valid = false; + break; + } + prev = (E) items[i]; if (lock.getSequence() == seq) { - prev = items[i - 1]; - return havePrev = true; + valid = true; + break; } refresh(); } - return false; + return validPrev = valid; } public E next() { - if (!haveNext && !hasNext()) - throw new NoSuchElementException(); - haveNext = false; - lastRet = cursor++; - return (E) next; + if (validNext || hasNext()) { + validNext = validPrev = false; + lastRet = cursor++; + return next; + } + throw new NoSuchElementException(); } public E previous() { - if (!havePrev && !hasPrevious()) - throw new NoSuchElementException(); - havePrev = false; - lastRet = cursor--; - return (E) prev; + if (validPrev || hasPrevious()) { + validNext = validPrev = false; + lastRet = cursor--; + return prev; + } + throw new NoSuchElementException(); } public void remove() { @@ -1196,12 +1234,16 @@ public class ReadMostlyVector impleme public int previousIndex() { return cursor - 1; } } - static final class ReadMostlyVectorSublist implements List, RandomAccess, java.io.Serializable { + static final class ReadMostlyVectorSublist + implements List, RandomAccess, java.io.Serializable { + static final long serialVersionUID = 3041673470172026059L; + final ReadMostlyVector list; final int offset; volatile int size; - ReadMostlyVectorSublist(ReadMostlyVector list, int offset, int size) { + ReadMostlyVectorSublist(ReadMostlyVector list, + int offset, int size) { this.list = list; this.offset = offset; this.size = size; @@ -1213,11 +1255,11 @@ public class ReadMostlyVector impleme } public boolean add(E element) { - SequenceLock lock = list.lock; + final SequenceLock lock = list.lock; lock.lock(); try { int c = size; - list.internalAddAt(c + offset, element); + list.rawAddAt(c + offset, element); size = c + 1; } finally { lock.unlock(); @@ -1226,12 +1268,12 @@ public class ReadMostlyVector impleme } public void add(int index, E element) { - SequenceLock lock = list.lock; + final SequenceLock lock = list.lock; lock.lock(); try { if (index < 0 || index > size) throw new ArrayIndexOutOfBoundsException(index); - list.internalAddAt(index + offset, element); + list.rawAddAt(index + offset, element); ++size; } finally { lock.unlock(); @@ -1240,45 +1282,43 @@ public class ReadMostlyVector impleme public boolean addAll(Collection c) { Object[] elements = c.toArray(); - int added; - SequenceLock lock = list.lock; + final SequenceLock lock = list.lock; lock.lock(); try { int s = size; int pc = list.count; - list.internalAddAllAt(offset + s, elements); - added = list.count - pc; + list.rawAddAllAt(offset + s, elements); + int added = list.count - pc; size = s + added; + return added != 0; } finally { lock.unlock(); } - return added != 0; } public boolean addAll(int index, Collection c) { Object[] elements = c.toArray(); - int added; - SequenceLock lock = list.lock; + final SequenceLock lock = list.lock; lock.lock(); try { int s = size; if (index < 0 || index > s) throw new ArrayIndexOutOfBoundsException(index); int pc = list.count; - list.internalAddAllAt(index + offset, elements); - added = list.count - pc; + list.rawAddAllAt(index + offset, elements); + int added = list.count - pc; size = s + added; + return added != 0; } finally { lock.unlock(); } - return added != 0; } public void clear() { - SequenceLock lock = list.lock; + final SequenceLock lock = list.lock; lock.lock(); try { - list.internalClear(offset, size); + list.internalClear(offset, offset + size); size = 0; } finally { lock.unlock(); @@ -1290,7 +1330,7 @@ public class ReadMostlyVector impleme } public boolean containsAll(Collection c) { - return list.internalContainsAll(c, offset, size); + return list.internalContainsAll(c, offset, offset + size); } public boolean equals(Object o) { @@ -1298,7 +1338,7 @@ public class ReadMostlyVector impleme return true; if (!(o instanceof List)) return false; - return list.internalEquals((List)(o), offset, size); + return list.internalEquals((List)(o), offset, offset + size); } public E get(int index) { @@ -1308,22 +1348,23 @@ public class ReadMostlyVector impleme } public int hashCode() { - return list.internalHashCode(offset, size); + return list.internalHashCode(offset, offset + size); } public int indexOf(Object o) { - SequenceLock lock = list.lock; + final SequenceLock lock = list.lock; long seq = lock.awaitAvailability(); Object[] items = list.array; int c = list.count; if (c <= items.length) { - int idx = internalIndexOf(o, items, offset, offset+size); + int idx = list.validatedIndexOf(o, items, offset, + offset + size, seq); if (lock.getSequence() == seq) return idx < 0 ? -1 : idx - offset; } lock.lock(); try { - int idx = internalIndexOf(o, list.array, offset, offset+size); + int idx = list.rawIndexOf(o, offset, offset + size); return idx < 0 ? -1 : idx - offset; } finally { lock.unlock(); @@ -1335,23 +1376,23 @@ public class ReadMostlyVector impleme } public Iterator iterator() { - return new SubItr(this, offset); + return new SubItr(this, offset); } public int lastIndexOf(Object o) { - SequenceLock lock = list.lock; + final SequenceLock lock = list.lock; long seq = lock.awaitAvailability(); Object[] items = list.array; int c = list.count; if (c <= items.length) { - int idx = internalLastIndexOf(o, items, offset+size-1, offset); + int idx = list.validatedLastIndexOf(o, items, offset+size-1, + offset, seq); if (lock.getSequence() == seq) return idx < 0 ? -1 : idx - offset; } lock.lock(); try { - int idx = internalLastIndexOf(o, list.array, offset+size-1, - offset); + int idx = list.rawLastIndexOf(o, offset + size - 1, offset); return idx < 0 ? -1 : idx - offset; } finally { lock.unlock(); @@ -1359,52 +1400,53 @@ public class ReadMostlyVector impleme } public ListIterator listIterator() { - return new SubItr(this, offset); + return new SubItr(this, offset); } public ListIterator listIterator(int index) { - return new SubItr(this, index + offset); + return new SubItr(this, index + offset); } public E remove(int index) { - E result; - SequenceLock lock = list.lock; + final SequenceLock lock = list.lock; lock.lock(); try { - if (index < 0 || index >= size) - throw new ArrayIndexOutOfBoundsException(index); + Object[] items = list.array; int i = index + offset; - result = (E)list.array[i]; - list.internalRemoveAt(i); + if (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.unlock(); } - return result; } public boolean remove(Object o) { - boolean removed = false; - SequenceLock lock = list.lock; + final SequenceLock lock = list.lock; lock.lock(); try { - if (list.internalRemoveAt(internalIndexOf(o, list.array, offset, - offset+size))) { - removed = true; + if (list.rawRemoveAt(list.rawIndexOf(o, offset, + offset + size))) { --size; + return true; } + else + return false; } finally { lock.unlock(); } - return removed; } public boolean removeAll(Collection c) { - return list.internalRemoveAll(c, offset, size); + return list.internalRemoveAll(c, offset, offset + size); } public boolean retainAll(Collection c) { - return list.internalRetainAll(c, offset, size); + return list.internalRetainAll(c, offset, offset + size); } public E set(int index, E element) { @@ -1422,19 +1464,19 @@ public class ReadMostlyVector impleme int ssize = toIndex - fromIndex; if (fromIndex < 0 || toIndex > c || ssize < 0) throw new IndexOutOfBoundsException(); - return new ReadMostlyVectorSublist(list, offset+fromIndex, ssize); + return new ReadMostlyVectorSublist(list, offset+fromIndex, ssize); } public Object[] toArray() { - return list.internalToArray(offset, size); + return list.internalToArray(offset, offset + size); } public T[] toArray(T[] a) { - return list.internalToArray(a, offset, size); + return list.internalToArray(a, offset, offset + size); } public String toString() { - return list.internalToString(offset, size); + return list.internalToString(offset, offset + size); } } @@ -1444,12 +1486,12 @@ public class ReadMostlyVector impleme final ReadMostlyVector list; final SequenceLock lock; Object[] items; - Object next, prev; + E next, prev; long seq; int cursor; int fence; int lastRet; - boolean haveNext, havePrev; + boolean validNext, validPrev; SubItr(ReadMostlyVectorSublist sublist, int index) { this.sublist = sublist; @@ -1463,53 +1505,72 @@ public class ReadMostlyVector impleme } private void refresh() { + validNext = validPrev = false; do { + int n; seq = lock.awaitAvailability(); items = list.array; - int c = list.count; + if ((n = list.count) > items.length) + continue; int b = sublist.offset + sublist.size; - fence = b < c ? b : c; + fence = b < n ? b : n; } while (lock.getSequence() != seq); } + @SuppressWarnings("unchecked") public boolean hasNext() { + boolean valid; int i = cursor; - while (i < fence && i >= 0) { + for (;;) { + if (i >= fence || i < 0 || i >= items.length) { + valid = false; + break; + } + next = (E) items[i]; if (lock.getSequence() == seq) { - next = items[i]; - return haveNext = true; + valid = true; + break; } refresh(); } - return false; + return validNext = valid; } + @SuppressWarnings("unchecked") public boolean hasPrevious() { - int i = cursor; - while (i <= fence && i > 0) { + boolean valid; + int i = cursor - 1; + for (;;) { + if (i >= fence || i < 0 || i >= items.length) { + valid = false; + break; + } + prev = (E) items[i]; if (lock.getSequence() == seq) { - prev = items[i - 1]; - return havePrev = true; + valid = true; + break; } refresh(); } - return false; + return validPrev = valid; } public E next() { - if (!haveNext && !hasNext()) - throw new NoSuchElementException(); - haveNext = false; - lastRet = cursor++; - return (E) next; + if (validNext || hasNext()) { + validNext = validPrev = false; + lastRet = cursor++; + return next; + } + throw new NoSuchElementException(); } public E previous() { - if (!havePrev && !hasPrevious()) - throw new NoSuchElementException(); - havePrev = false; - lastRet = cursor--; - return (E) prev; + if (validPrev || hasPrevious()) { + validNext = validPrev = false; + lastRet = cursor--; + return prev; + } + throw new NoSuchElementException(); } public int nextIndex() { @@ -1572,4 +1633,3 @@ public class ReadMostlyVector impleme } } -