--- jsr166/src/jsr166e/extra/ReadMostlyVector.java 2011/07/16 13:20:35 1.2 +++ jsr166/src/jsr166e/extra/ReadMostlyVector.java 2011/07/21 12:49:37 1.12 @@ -12,14 +12,17 @@ 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. + * 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. Alternatvely, + * 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 @@ -40,7 +43,7 @@ public class ReadMostlyVector impleme * 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 @@ -54,9 +57,9 @@ 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; + volatile Object[] array; final SequenceLock lock; - int count; + volatile int count; final int capacityIncrement; /** @@ -126,7 +129,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); @@ -134,7 +137,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) { @@ -151,13 +154,14 @@ public class ReadMostlyVector impleme * as well as sublist and iterator classes. */ - final int validatedIndexOf(Object x, Object[] items, int index, int fence, + // Version of indexOf that returns -1 if either not present or invalid + 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 : (e != null && x.equals(e))) + if ((x == null) ? e == null : x.equals(e)) return i; } return -1; @@ -167,19 +171,19 @@ public class ReadMostlyVector impleme Object[] items = array; for (int i = index; i < fence; ++i) { Object e = items[i]; - if (x == null? e == null : (e != null && x.equals(e))) + if ((x == null) ? e == null : x.equals(e)) return i; } return -1; } - final int validatedLastIndexOf(Object x, Object[] items, + final int validatedLastIndexOf(Object x, Object[] items, int index, int origin, long seq) { for (int i = index; i >= origin; --i) { Object e = items[i]; if (lock.getSequence() != seq) break; - if (x == null? e == null : (e != null && x.equals(e))) + if ((x == null) ? e == null : x.equals(e)) return i; } return -1; @@ -189,58 +193,62 @@ public class ReadMostlyVector impleme Object[] items = array; for (int i = index; i >= origin; --i) { Object e = items[i]; - if (x == null? e == null : (e != null && x.equals(e))) + if ((x == null) ? e == null : x.equals(e)) return i; } return -1; } - final void internalAdd(Object e) { + final void rawAdd(Object e) { int n = count; - if (n >= array.length) - grow(n + 1); - array[n] = e; + Object[] items = array; + if (n >= items.length) + items = grow(n + 1); + items[n] = e; count = n + 1; } - final void internalAddAt(int index, Object e) { + final void rawAddAt(int index, Object e) { int n = count; + Object[] items = array; if (index > n) throw new ArrayIndexOutOfBoundsException(index); - if (n >= array.length) - grow(n + 1); + if (n >= items.length) + items = grow(n + 1); if (index < n) - System.arraycopy(array, index, array, index + 1, n - index); - array[index] = e; + System.arraycopy(items, index, items, index + 1, n - index); + items[index] = e; count = n + 1; } - final boolean internalAddAllAt(int index, Object[] elements) { + 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 (newCount >= array.length) - grow(newCount); - int mv = count - index; + 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) { + final boolean rawRemoveAt(int index) { int n = count - 1; + Object[] items = array; if (index < 0 || index > n) return false; int mv = n - index; if (mv > 0) - System.arraycopy(array, index + 1, array, index, mv); - array[n] = null; + System.arraycopy(items, index + 1, items, index, mv); + items[n] = null; count = n; return true; } @@ -261,7 +269,7 @@ public class ReadMostlyVector impleme int fence = bound < 0 || bound > n ? n : bound; if (origin >= 0 && origin < fence) { for (Object x : c) { - while (internalRemoveAt(rawIndexOf(x, origin, fence))) + while (rawRemoveAt(rawIndexOf(x, origin, fence))) removed = true; } } @@ -277,20 +285,24 @@ public class ReadMostlyVector impleme if (c != this) { lock.lock(); try { + Object[] items = array; int i = origin; int n = count; int fence = bound < 0 || bound > n ? n : bound; - while (i < fence) { - if (c.contains(array[i])) + 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(); } @@ -302,13 +314,14 @@ public class ReadMostlyVector impleme 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 = n - removed; int mv = n - (origin + removed); if (mv > 0) - System.arraycopy(array, origin + removed, array, origin, mv); + System.arraycopy(items, origin + removed, items, origin, mv); for (int i = n; i < newCount; ++i) - array[i] = null; + items[i] = null; count = newCount; } } @@ -320,9 +333,9 @@ public class ReadMostlyVector impleme try { for (;;) { long seq = lock.awaitAvailability(); + int n = count; Object[] items = array; int len = items.length; - int n = count; if (n > len) continue; int fence = bound < 0 || bound > n ? n : bound; @@ -331,7 +344,11 @@ public class ReadMostlyVector impleme else { contained = true; for (Object e : c) { - if (validatedIndexOf(e, items, origin, fence, seq) < 0) { + int idx = (locked ? + rawIndexOf(e, origin, fence) : + validatedIndexOf(e, items, origin, + fence, seq)); + if (idx < 0) { contained = false; break; } @@ -351,32 +368,26 @@ public class ReadMostlyVector impleme final boolean internalEquals(List list, int origin, int bound) { SequenceLock lock = this.lock; - boolean equal; boolean locked = false; + boolean equal; try { - outer:for (;;) { - equal = true; + for (;;) { long seq = lock.awaitAvailability(); Object[] items = array; - int len = items.length; int n = count; - if (n > len) - continue; - int fence = bound < 0 || bound > n ? n : bound; - if (origin < 0) + 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 (lock.getSequence() != seq) - continue outer; - 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; } @@ -405,8 +416,8 @@ public class ReadMostlyVector impleme hash = 1; long seq = lock.awaitAvailability(); Object[] items = array; - int len = items.length; int n = count; + int len = items.length; if (n > len) continue; int fence = bound < 0 || bound > n ? n : bound; @@ -436,8 +447,8 @@ public class ReadMostlyVector impleme outer:for (;;) { long seq = lock.awaitAvailability(); Object[] items = array; - int len = items.length; int n = count; + int len = items.length; if (n > len) continue; int fence = bound < 0 || bound > n ? n : bound; @@ -450,7 +461,7 @@ public class ReadMostlyVector impleme Object e = items[i]; if (e == this) sb.append("(this Collection)"); - else if (lock.getSequence() != seq) + else if (!locked && lock.getSequence() != seq) continue outer; else sb.append(e.toString()); @@ -483,8 +494,8 @@ public class ReadMostlyVector impleme result = null; long seq = lock.awaitAvailability(); Object[] items = array; - int len = items.length; int n = count; + int len = items.length; if (n > len) continue; int fence = bound < 0 || bound > n ? n : bound; @@ -512,23 +523,23 @@ public class ReadMostlyVector impleme for (;;) { long seq = lock.awaitAvailability(); Object[] items = array; - int len = items.length; int n = count; + int len = items.length; 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) - rlen = 0; - else if (rlen > 0) - System.arraycopy(array, 0, a, origin, rlen); + if (rlen > 0) + System.arraycopy(items, 0, a, origin, rlen); if (alen > rlen) a[rlen] = null; result = a; } - else - result = (T[]) Arrays.copyOfRange(array, origin, + else + result = (T[]) Arrays.copyOfRange(items, origin, fence, a.getClass()); if (lock.getSequence() == seq) break; @@ -548,7 +559,7 @@ public class ReadMostlyVector impleme SequenceLock lock = this.lock; lock.lock(); try { - internalAdd(e); + rawAdd(e); } finally { lock.unlock(); } @@ -559,7 +570,7 @@ public class ReadMostlyVector impleme SequenceLock lock = this.lock; lock.lock(); try { - internalAddAt(index, element); + rawAddAt(index, element); } finally { lock.unlock(); } @@ -573,10 +584,12 @@ public class ReadMostlyVector impleme 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(); @@ -590,7 +603,7 @@ public class ReadMostlyVector impleme Object[] elements = c.toArray(); lock.lock(); try { - ret = internalAddAllAt(index, elements); + ret = rawAddAllAt(index, elements); } finally { lock.unlock(); } @@ -601,8 +614,10 @@ public class ReadMostlyVector impleme 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(); @@ -622,15 +637,15 @@ 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; for (;;) { long seq = lock.awaitAvailability(); - Object[] items = array; int n = count; + Object[] items = array; if (n > items.length) continue; Object e; boolean ex; @@ -657,55 +672,68 @@ public class ReadMostlyVector impleme public int indexOf(Object o) { SequenceLock lock = this.lock; - long seq = lock.awaitAvailability(); - Object[] items = array; - int n = count; - if (n <= items.length) { - int idx = validatedIndexOf(o, items, 0, n, seq); - if (lock.getSequence() == seq) - return idx; - } - lock.lock(); - try { - return rawIndexOf(o, 0, count); - } finally { - lock.unlock(); + for (;;) { + long seq = lock.awaitAvailability(); + Object[] items = array; + int n = count; + if (n <= items.length) { + for (int i = 0; i < n; ++i) { + Object e = items[i]; + if (lock.getSequence() != seq) { + lock.lock(); + try { + return rawIndexOf(o, 0, count); + } finally { + lock.unlock(); + } + } + else if ((o == null) ? e == null : o.equals(e)) + return i; + } + return -1; + } } } 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 n = count; - if (n <= items.length) { - int idx = validatedLastIndexOf(o, items, n - 1, 0, seq); - if (lock.getSequence() == seq) - return idx; - } - lock.lock(); - try { - return rawLastIndexOf(o, count - 1, 0); - } finally { - lock.unlock(); + 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, 0, count); + } 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) { @@ -716,7 +744,7 @@ public class ReadMostlyVector impleme if (index < 0 || index >= count) throw new ArrayIndexOutOfBoundsException(index); oldValue = array[index]; - internalRemoveAt(index); + rawRemoveAt(index); } finally { lock.unlock(); } @@ -728,7 +756,7 @@ public class ReadMostlyVector impleme boolean removed; lock.lock(); try { - removed = internalRemoveAt(rawIndexOf(o, 0, count)); + removed = rawRemoveAt(rawIndexOf(o, 0, count)); } finally { lock.unlock(); } @@ -748,10 +776,11 @@ public class ReadMostlyVector impleme SequenceLock lock = this.lock; lock.lock(); try { + Object[] items = array; if (index < 0 || index >= count) throw new ArrayIndexOutOfBoundsException(index); - oldValue = array[index]; - array[index] = element; + oldValue = items[index]; + items[index] = element; } finally { lock.unlock(); } @@ -759,7 +788,6 @@ public class ReadMostlyVector impleme } public int size() { - long ignore = lock.getSequence(); return count; } @@ -768,7 +796,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() { @@ -789,7 +817,7 @@ public class ReadMostlyVector impleme * Append 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; @@ -797,7 +825,7 @@ public class ReadMostlyVector impleme lock.lock(); try { if (rawIndexOf(e, 0, count) < 0) { - internalAdd(e); + rawAdd(e); added = true; } else @@ -829,7 +857,7 @@ public class ReadMostlyVector impleme for (int i = 0; i < clen; ++i) { Object e = cs[i]; if (rawIndexOf(e, 0, count) < 0) { - internalAdd(e); + rawAdd(e); ++added; } } @@ -840,6 +868,31 @@ 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 { + final Object[] items; + int cursor; + SnapshotIterator(ReadMostlyVector v) { items = v.toArray(); } + public boolean hasNext() { return cursor < items.length; } + 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} */ @@ -971,8 +1024,9 @@ public class ReadMostlyVector impleme if (newSize > n) grow(newSize); else { + Object[] items = array; for (int i = newSize ; i < n ; i++) - array[i] = null; + items[i] = null; } count = newSize; } finally { @@ -996,8 +1050,10 @@ public class ReadMostlyVector impleme 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(); } @@ -1019,12 +1075,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; } @@ -1065,7 +1120,7 @@ public class ReadMostlyVector impleme // other methods - public Object clone() { + public ReadMostlyVector clone() { SequenceLock lock = this.lock; Object[] a = null; boolean retry = false; @@ -1085,7 +1140,7 @@ public class ReadMostlyVector impleme lock.unlock(); } } - return new ReadMostlyVector(a, n, capacityIncrement); + return new ReadMostlyVector(a, n, capacityIncrement); } private void writeObject(java.io.ObjectOutputStream s) @@ -1256,7 +1311,7 @@ public class ReadMostlyVector impleme lock.lock(); try { int c = size; - list.internalAddAt(c + offset, element); + list.rawAddAt(c + offset, element); size = c + 1; } finally { lock.unlock(); @@ -1270,7 +1325,7 @@ public class ReadMostlyVector impleme try { if (index < 0 || index > size) throw new ArrayIndexOutOfBoundsException(index); - list.internalAddAt(index + offset, element); + list.rawAddAt(index + offset, element); ++size; } finally { lock.unlock(); @@ -1285,7 +1340,7 @@ public class ReadMostlyVector impleme try { int s = size; int pc = list.count; - list.internalAddAllAt(offset + s, elements); + list.rawAddAllAt(offset + s, elements); added = list.count - pc; size = s + added; } finally { @@ -1304,7 +1359,7 @@ public class ReadMostlyVector impleme if (index < 0 || index > s) throw new ArrayIndexOutOfBoundsException(index); int pc = list.count; - list.internalAddAllAt(index + offset, elements); + list.rawAddAllAt(index + offset, elements); added = list.count - pc; size = s + added; } finally { @@ -1356,13 +1411,14 @@ public class ReadMostlyVector impleme Object[] items = list.array; int c = list.count; if (c <= items.length) { - int idx = list.validatedIndexOf(o, items, offset, offset+size, seq); + 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 = list.rawIndexOf(o, offset, offset+size); + int idx = list.rawIndexOf(o, offset, offset + size); return idx < 0 ? -1 : idx - offset; } finally { lock.unlock(); @@ -1374,7 +1430,7 @@ public class ReadMostlyVector impleme } public Iterator iterator() { - return new SubItr(this, offset); + return new SubItr(this, offset); } public int lastIndexOf(Object o) { @@ -1383,7 +1439,7 @@ public class ReadMostlyVector impleme Object[] items = list.array; int c = list.count; if (c <= items.length) { - int idx = list.validatedLastIndexOf(o, items, offset+size-1, + int idx = list.validatedLastIndexOf(o, items, offset+size-1, offset, seq); if (lock.getSequence() == seq) return idx < 0 ? -1 : idx - offset; @@ -1398,11 +1454,11 @@ 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) { @@ -1410,11 +1466,12 @@ public class ReadMostlyVector impleme 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 = list.array[i]; - list.internalRemoveAt(i); + if (index < 0 || index >= size || i >= items.length) + throw new ArrayIndexOutOfBoundsException(index); + result = items[i]; + list.rawRemoveAt(i); size--; } finally { lock.unlock(); @@ -1427,8 +1484,8 @@ public class ReadMostlyVector impleme SequenceLock lock = list.lock; lock.lock(); try { - if (list.internalRemoveAt(list.rawIndexOf(o, offset, - offset + size))) { + if (list.rawRemoveAt(list.rawIndexOf(o, offset, + offset + size))) { removed = true; --size; } @@ -1461,7 +1518,7 @@ 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() {