src/share/classes/java/util/concurrent/CopyOnWriteArrayList.java

Print this page
rev 6971 : [mq]: collections

*** 34,43 **** --- 34,46 ---- */ package java.util.concurrent; import java.util.*; import java.util.concurrent.locks.ReentrantLock; + import java.util.function.Consumer; + import java.util.function.Predicate; + import java.util.function.UnaryOperator; /** * A thread-safe variant of {@link java.util.ArrayList} in which all mutative * operations (<tt>add</tt>, <tt>set</tt>, and so on) are implemented by * making a fresh copy of the underlying array.
*** 1258,1269 **** --- 1261,1321 ---- } finally { lock.unlock(); } } + @Override + public void forEach(Consumer<? super E> action) { + @SuppressWarnings("unchecked") + final E[] elements = (E[]) l.getArray(); + checkForComodification(); + l.forEach(action, elements, offset, offset + size); + } + + @Override + public void sort(Comparator<? super E> c) { + final ReentrantLock lock = l.lock; + lock.lock(); + try { + checkForComodification(); + l.sort(c, offset, offset + size); + expectedArray = l.getArray(); + } finally { + lock.unlock(); + } } + @Override + public boolean removeIf(Predicate<? super E> filter) { + Objects.requireNonNull(filter); + final ReentrantLock lock = l.lock; + lock.lock(); + try { + checkForComodification(); + final int removeCount = + l.removeIf(filter, offset, offset + size); + expectedArray = l.getArray(); + size -= removeCount; + return removeCount > 0; + } finally { + lock.unlock(); + } + } + + @Override + public void replaceAll(UnaryOperator<E> operator) { + final ReentrantLock lock = l.lock; + lock.lock(); + try { + checkForComodification(); + l.replaceAll(operator, offset, offset + size); + expectedArray = l.getArray(); + } finally { + lock.unlock(); + } + } + } private static class COWSubListIterator<E> implements ListIterator<E> { private final ListIterator<E> it; private final int offset; private final int size;
*** 1331,1336 **** --- 1383,1523 ---- (k.getDeclaredField("lock")); } catch (Exception e) { throw new Error(e); } } + + @Override + @SuppressWarnings("unchecked") + public void forEach(Consumer<? super E> action) { + forEach(action, (E[]) getArray(), 0, size()); + } + + private void forEach(Consumer<? super E> action, + final E[] elements, + final int from, final int to) { + Objects.requireNonNull(action); + for (int i = from; i < to; i++) { + action.accept(elements[i]); + } + } + + @Override + public void sort(Comparator<? super E> c) { + final ReentrantLock lock = this.lock; + lock.lock(); + try { + sort(c, 0, size()); + } finally { + lock.unlock(); + } + } + + // must be called with this.lock held + @SuppressWarnings("unchecked") + private void sort(Comparator<? super E> c, final int from, final int to) { + final E[] elements = (E[]) getArray(); + final E[] newElements = Arrays.copyOf(elements, elements.length); + // only elements [from, to) are sorted + Arrays.sort(newElements, from, to, c); + setArray(newElements); + } + + @Override + public boolean removeIf(Predicate<? super E> filter) { + Objects.requireNonNull(filter); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + return removeIf(filter, 0, size()) > 0; + } finally { + lock.unlock(); + } + } + + // must be called with this.lock held + private int removeIf(Predicate<? super E> filter, final int from, final int to) { + Objects.requireNonNull(filter); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + @SuppressWarnings("unchecked") + final E[] elements = (E[]) getArray(); + + // figure out which elements are to be removed + // any exception thrown from the filter predicate at this stage + // will leave the collection unmodified + int removeCount = 0; + final int range = to - from; + final BitSet removeSet = new BitSet(range); + for (int i = 0; i < range; i++) { + final E element = elements[from + i]; + if (filter.test(element)) { + // removeSet is zero-based to keep its size small + removeSet.set(i); + removeCount++; + } + } + + // copy surviving elements into a new array + if (removeCount > 0) { + final int newSize = elements.length - removeCount; + final int newRange = newSize - from; + @SuppressWarnings("unchecked") + final E[] newElements = (E[]) new Object[newSize]; + // copy elements before [from, to) unmodified + for (int i = 0; i < from; i++) { + newElements[i] = elements[i]; + } + // elements [from, to) are subject to removal + int j = 0; + for (int i = 0; (i < range) && (j < newRange); i++) { + i = removeSet.nextClearBit(i); + if (i >= range) { + break; + } + newElements[from + (j++)] = elements[from + i]; + } + // copy any remaining elements beyond [from, to) + j += from; + for (int i = to; (i < elements.length) && (j < newSize); i++) { + newElements[j++] = elements[i]; + } + setArray(newElements); + } + + return removeCount; + } finally { + lock.unlock(); + } + } + + @Override + public void replaceAll(UnaryOperator<E> operator) { + Objects.requireNonNull(operator); + final ReentrantLock lock = this.lock; + lock.lock(); + try { + replaceAll(operator, 0, size()); + } finally { + lock.unlock(); + } + } + + // must be called with this.lock held + @SuppressWarnings("unchecked") + private void replaceAll(UnaryOperator<E> operator, final int from, final int to) { + final E[] elements = (E[]) getArray(); + final E[] newElements = (E[]) new Object[elements.length]; + for (int i = 0; i < from; i++) { + newElements[i] = elements[i]; + } + // the operator is only applied to elements [from, to) + for (int i = from; i < to; i++) { + newElements[i] = operator.apply(elements[i]); + } + for (int i = to; i < elements.length; i++) { + newElements[i] = elements[i]; + } + setArray(newElements); + } }