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

Print this page
rev 6197 : [mq]: collections

@@ -34,10 +34,13 @@
  */
 
 package java.util.concurrent;
 import java.util.*;
 import java.util.concurrent.locks.ReentrantLock;
+import java.util.function.Block;
+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.

@@ -1315,10 +1318,96 @@
         public void add(E e) {
             throw new UnsupportedOperationException();
         }
     }
 
+    @SuppressWarnings("unchecked")
+    public void forEach(Block<? super E> block) {
+        Objects.requireNonNull(block);
+        final Object[] elements = getArray();
+        for (final Object element : elements) {
+            block.accept((E) element);
+        }
+    }
+
+    @Override
+    public void sort(Comparator<? super E> c) {
+        Objects.requireNonNull(c);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            @SuppressWarnings("unchecked")
+            final E[] elements = (E[]) getArray();
+            final E[] newElements = Arrays.copyOf(elements, elements.length);
+            Arrays.sort(newElements, c);
+            setArray(newElements);
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    @Override
+    public boolean removeAll(Predicate<? super E> filter) {
+        Objects.requireNonNull(filter);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            @SuppressWarnings("unchecked")
+            final E[] elements = (E[]) getArray();
+            final int size = elements.length;
+
+            // 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 BitSet removeSet = new BitSet(size);
+            for (int i=0; i < size; i++) {
+                final E element = elements[i];
+                if (filter.test(element)) {
+                    removeSet.set(i);
+                    removeCount++;
+                }
+            }
+
+            // copy surviving elements into a new array
+            final boolean anyToRemove = removeCount > 0;
+            if (anyToRemove) {
+                final int newSize = size - removeCount;
+                final Object[] newElements = new Object[newSize];
+                for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
+                    i = removeSet.nextClearBit(i);
+                    newElements[j] = elements[i];
+                }
+                setArray(newElements);
+            }
+
+            return anyToRemove;
+        } finally {
+            lock.unlock();
+        }
+    }
+
+    @Override
+    public void replaceAll(UnaryOperator<E> operator) {
+        Objects.requireNonNull(operator);
+        final ReentrantLock lock = this.lock;
+        lock.lock();
+        try {
+            @SuppressWarnings("unchecked")
+            final E[] elements = (E[]) getArray();
+            final int len = elements.length;
+            @SuppressWarnings("unchecked")
+            final E[] newElements = (E[]) new Object[len];
+            for (int i=0; i < len; i++) {
+                newElements[i] = operator.operate(elements[i]);
+            }
+            setArray(newElements);
+        } finally {
+            lock.unlock();
+        }
+    }
+
     // Support for resetting lock while deserializing
     private void resetLock() {
         UNSAFE.putObjectVolatile(this, lockOffset, new ReentrantLock());
     }
     private static final sun.misc.Unsafe UNSAFE;