--- jsr166/src/jsr166e/ConcurrentHashMapV8.java 2012/07/18 01:30:54 1.51 +++ jsr166/src/jsr166e/ConcurrentHashMapV8.java 2012/08/13 15:52:33 1.52 @@ -6,6 +6,10 @@ package jsr166e; import jsr166e.LongAdder; +import jsr166e.ForkJoinPool; +import jsr166e.ForkJoinTask; + +import java.util.Comparator; import java.util.Arrays; import java.util.Map; import java.util.Set; @@ -23,6 +27,8 @@ import java.util.concurrent.ConcurrentMa import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.locks.LockSupport; import java.util.concurrent.locks.AbstractQueuedSynchronizer; +import java.util.concurrent.atomic.AtomicReference; + import java.io.Serializable; /** @@ -88,7 +94,9 @@ import java.io.Serializable; * Java Collections Framework. * *

jsr166e note: This class is a candidate replacement for - * java.util.concurrent.ConcurrentHashMap. + * java.util.concurrent.ConcurrentHashMap. During transition, this + * class declares and uses nested functional interfaces with different + * names but the same forms as those expected for JDK8. * * @since 1.5 * @author Doug Lea @@ -96,41 +104,10 @@ import java.io.Serializable; * @param the type of mapped values */ public class ConcurrentHashMapV8 - implements ConcurrentMap, Serializable { + implements ConcurrentMap, Serializable { private static final long serialVersionUID = 7249069246763182397L; /** - * A function computing a mapping from the given key to a value. - * This is a place-holder for an upcoming JDK8 interface. - */ - public static interface MappingFunction { - /** - * Returns a value for the given key, or null if there is no mapping. - * - * @param key the (non-null) key - * @return a value for the key, or null if none - */ - V map(K key); - } - - /** - * A function computing a new mapping given a key and its current - * mapped value (or {@code null} if there is no current - * mapping). This is a place-holder for an upcoming JDK8 - * interface. - */ - public static interface RemappingFunction { - /** - * Returns a new value given a key and its current value. - * - * @param key the (non-null) key - * @param value the current value, or null if there is no mapping - * @return a value for the key, or null if none - */ - V remap(K key, V value); - } - - /** * A partitionable iterator. A Spliterator can be traversed * directly, but can also be partitioned (before traversal) by * creating another Spliterator that covers a non-overlapping @@ -150,13 +127,15 @@ public class ConcurrentHashMapV8 * *

      * {@code ConcurrentHashMapV8 m = ...
-     * // Uses parallel depth of log2 of size / (parallelism * slack of 8).
-     * int depth = 32 - Integer.numberOfLeadingZeros(m.size() / (aForkJoinPool.getParallelism() * 8));
-     * long sum = aForkJoinPool.invoke(new SumValues(m.valueSpliterator(), depth, null));
+     * // split as if have 8 * parallelism, for load balance
+     * int n = m.size();
+     * int p = aForkJoinPool.getParallelism() * 8;
+     * int split = (n < p)? n : p;
+     * long sum = aForkJoinPool.invoke(new SumValues(m.valueSpliterator(), split, null));
      * // ...
      * static class SumValues extends RecursiveTask {
      *   final Spliterator s;
-     *   final int depth;             // number of splits before processing
+     *   final int split;             // split while > 1
      *   final SumValues nextJoin;    // records forked subtasks to join
      *   SumValues(Spliterator s, int depth, SumValues nextJoin) {
      *     this.s = s; this.depth = depth; this.nextJoin = nextJoin;
@@ -164,8 +143,8 @@ public class ConcurrentHashMapV8
      *   public Long compute() {
      *     long sum = 0;
      *     SumValues subtasks = null; // fork subtasks
-     *     for (int d = depth - 1; d >= 0; --d)
-     *       (subtasks = new SumValues(s.split(), d, subtasks)).fork();
+     *     for (int s = split >>> 1; s > 0; s >>>= 1)
+     *       (subtasks = new SumValues(s.split(), s, subtasks)).fork();
      *     while (s.hasNext())        // directly process remaining elements
      *       sum += s.next();
      *     for (SumValues t = subtasks; t != null; t = t.nextJoin)
@@ -348,7 +327,7 @@ public class ConcurrentHashMapV8
      * When there are no lock acquisition failures, this is arranged
      * simply by proceeding from the last bin (table.length - 1) up
      * towards the first.  Upon seeing a forwarding node, traversals
-     * (see class InternalIterator) arrange to move to the new table
+     * (see class Iter) arrange to move to the new table
      * without revisiting nodes.  However, when any node is skipped
      * during a transfer, all earlier table bins may have become
      * visible, so are initialized with a reverse-forwarding node back
@@ -358,7 +337,7 @@ public class ConcurrentHashMapV8
      * mechanics trigger only when necessary.
      *
      * The traversal scheme also applies to partial traversals of
-     * ranges of bins (via an alternate InternalIterator constructor)
+     * ranges of bins (via an alternate Traverser constructor)
      * to support partitioned aggregate operations.  Also, read-only
      * operations give up if ever forwarded to a null table, which
      * provides support for shutdown-style clearing, which is also not
@@ -500,7 +479,7 @@ public class ConcurrentHashMapV8
      * inline assignments below.
      */
 
-    static final Node tabAt(Node[] tab, int i) { // used by InternalIterator
+    static final Node tabAt(Node[] tab, int i) { // used by Iter
         return (Node)UNSAFE.getObjectVolatile(tab, ((long)i<
          * starting at given root.
          */
         @SuppressWarnings("unchecked") // suppress Comparable cast warning
-        final TreeNode getTreeNode(int h, Object k, TreeNode p) {
+            final TreeNode getTreeNode(int h, Object k, TreeNode p) {
             Class c = k.getClass();
             while (p != null) {
                 int dir, ph;  Object pk; Class pc;
@@ -798,7 +777,7 @@ public class ConcurrentHashMapV8
          * @return null if added
          */
         @SuppressWarnings("unchecked") // suppress Comparable cast warning
-        final TreeNode putTreeNode(int h, Object k, Object v) {
+            final TreeNode putTreeNode(int h, Object k, Object v) {
             Class c = k.getClass();
             TreeNode pp = root, p = null;
             int dir = 0;
@@ -1439,7 +1418,7 @@ public class ConcurrentHashMapV8
 
     /** Implementation for computeIfAbsent */
     private final Object internalComputeIfAbsent(K k,
-                                                 MappingFunction mf) {
+                                                 Fun mf) {
         int h = spread(k.hashCode());
         Object val = null;
         int count = 0;
@@ -1452,7 +1431,7 @@ public class ConcurrentHashMapV8
                 if (casTabAt(tab, i, null, node)) {
                     count = 1;
                     try {
-                        if ((val = mf.map(k)) != null)
+                        if ((val = mf.apply(k)) != null)
                             node.val = val;
                     } finally {
                         if (val == null)
@@ -1477,7 +1456,7 @@ public class ConcurrentHashMapV8
                             TreeNode p = t.getTreeNode(h, k, t.root);
                             if (p != null)
                                 val = p.val;
-                            else if ((val = mf.map(k)) != null) {
+                            else if ((val = mf.apply(k)) != null) {
                                 added = true;
                                 count = 2;
                                 t.putTreeNode(h, k, val);
@@ -1531,7 +1510,7 @@ public class ConcurrentHashMapV8
                                 }
                                 Node last = e;
                                 if ((e = e.next) == null) {
-                                    if ((val = mf.map(k)) != null) {
+                                    if ((val = mf.apply(k)) != null) {
                                         added = true;
                                         last.next = new Node(h, k, val, null);
                                         if (count >= TREE_THRESHOLD)
@@ -1567,8 +1546,8 @@ public class ConcurrentHashMapV8
 
     /** Implementation for compute */
     @SuppressWarnings("unchecked")
-    private final Object internalCompute(K k,
-                                         RemappingFunction mf) {
+        private final Object internalCompute(K k, boolean onlyIfPresent,
+                                             BiFun mf) {
         int h = spread(k.hashCode());
         Object val = null;
         int delta = 0;
@@ -1578,11 +1557,13 @@ public class ConcurrentHashMapV8
             if (tab == null)
                 tab = initTable();
             else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) {
+                if (onlyIfPresent)
+                    break;
                 Node node = new Node(fh = h | LOCKED, k, null, null);
                 if (casTabAt(tab, i, null, node)) {
                     try {
                         count = 1;
-                        if ((val = mf.remap(k, null)) != null) {
+                        if ((val = mf.apply(k, null)) != null) {
                             node.val = val;
                             delta = 1;
                         }
@@ -1607,7 +1588,7 @@ public class ConcurrentHashMapV8
                             count = 1;
                             TreeNode p = t.getTreeNode(h, k, t.root);
                             Object pv = (p == null) ? null : p.val;
-                            if ((val = mf.remap(k, (V)pv)) != null) {
+                            if ((val = mf.apply(k, (V)pv)) != null) {
                                 if (p != null)
                                     p.val = val;
                                 else {
@@ -1643,7 +1624,7 @@ public class ConcurrentHashMapV8
                             if ((e.hash & HASH_BITS) == h &&
                                 (ev = e.val) != null &&
                                 ((ek = e.key) == k || k.equals(ek))) {
-                                val = mf.remap(k, (V)ev);
+                                val = mf.apply(k, (V)ev);
                                 if (val != null)
                                     e.val = val;
                                 else {
@@ -1658,7 +1639,7 @@ public class ConcurrentHashMapV8
                             }
                             pred = e;
                             if ((e = e.next) == null) {
-                                if ((val = mf.remap(k, null)) != null) {
+                                if (!onlyIfPresent && (val = mf.apply(k, null)) != null) {
                                     pred.next = new Node(h, k, val, null);
                                     delta = 1;
                                     if (count >= TREE_THRESHOLD)
@@ -1689,6 +1670,113 @@ public class ConcurrentHashMapV8
         return val;
     }
 
+    private final Object internalMerge(K k, V v,
+                                       BiFun mf) {
+        int h = spread(k.hashCode());
+        Object val = null;
+        int delta = 0;
+        int count = 0;
+        for (Node[] tab = table;;) {
+            int i; Node f; int fh; Object fk, fv;
+            if (tab == null)
+                tab = initTable();
+            else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) {
+                if (casTabAt(tab, i, null, new Node(h, k, v, null))) {
+                    delta = 1;
+                    val = v;
+                    break;
+                }
+            }
+            else if ((fh = f.hash) == MOVED) {
+                if ((fk = f.key) instanceof TreeBin) {
+                    TreeBin t = (TreeBin)fk;
+                    t.acquire(0);
+                    try {
+                        if (tabAt(tab, i) == f) {
+                            count = 1;
+                            TreeNode p = t.getTreeNode(h, k, t.root);
+                            val = (p == null) ? v : mf.apply((V)p.val, v);
+                            if (val != null) {
+                                if (p != null)
+                                    p.val = val;
+                                else {
+                                    count = 2;
+                                    delta = 1;
+                                    t.putTreeNode(h, k, val);
+                                }
+                            }
+                            else if (p != null) {
+                                delta = -1;
+                                t.deleteTreeNode(p);
+                            }
+                        }
+                    } finally {
+                        t.release(0);
+                    }
+                    if (count != 0)
+                        break;
+                }
+                else
+                    tab = (Node[])fk;
+            }
+            else if ((fh & LOCKED) != 0) {
+                checkForResize();
+                f.tryAwaitLock(tab, i);
+            }
+            else if (f.casHash(fh, fh | LOCKED)) {
+                try {
+                    if (tabAt(tab, i) == f) {
+                        count = 1;
+                        for (Node e = f, pred = null;; ++count) {
+                            Object ek, ev;
+                            if ((e.hash & HASH_BITS) == h &&
+                                (ev = e.val) != null &&
+                                ((ek = e.key) == k || k.equals(ek))) {
+                                val = mf.apply(v, (V)ev);
+                                if (val != null)
+                                    e.val = val;
+                                else {
+                                    delta = -1;
+                                    Node en = e.next;
+                                    if (pred != null)
+                                        pred.next = en;
+                                    else
+                                        setTabAt(tab, i, en);
+                                }
+                                break;
+                            }
+                            pred = e;
+                            if ((e = e.next) == null) {
+                                val = v;
+                                pred.next = new Node(h, k, val, null);
+                                delta = 1;
+                                if (count >= TREE_THRESHOLD)
+                                    replaceWithTreeBin(tab, i, k);
+                                break;
+                            }
+                        }
+                    }
+                } finally {
+                    if (!f.casHash(fh | LOCKED, fh)) {
+                        f.hash = fh;
+                        synchronized (f) { f.notifyAll(); };
+                    }
+                }
+                if (count != 0) {
+                    if (tab.length <= 64)
+                        count = 2;
+                    break;
+                }
+            }
+        }
+        if (delta != 0) {
+            counter.add((long)delta);
+            if (count > 1)
+                checkForResize();
+        }
+        return val;
+    }
+
     /** Implementation for putAll */
     private final void internalPutAll(Map m) {
         tryPresize(m.size());
@@ -2168,8 +2256,13 @@ public class ConcurrentHashMapV8
      * paranoically cope with potential sharing by users of iterators
      * across threads, iteration terminates if a bounds checks fails
      * for a table read.
+     *
+     * This class extends ForkJoinTask to streamline parallel
+     * iteration in bulk operations (see BulkTask). This adds only an
+     * int of space overhead, which is close enough to negligible in
+     * cases where it is not needed to not worry about it.
      */
-    static class InternalIterator {
+    static class Traverser extends ForkJoinTask {
         final ConcurrentHashMapV8 map;
         Node next;           // the next entry to use
         Node last;           // the last entry used
@@ -2182,20 +2275,24 @@ public class ConcurrentHashMapV8
         final int baseSize;  // initial table size
 
         /** Creates iterator for all entries in the table. */
-        InternalIterator(ConcurrentHashMapV8 map) {
+        Traverser(ConcurrentHashMapV8 map) {
             this.tab = (this.map = map).table;
             baseLimit = baseSize = (tab == null) ? 0 : tab.length;
         }
 
-        /** Creates iterator for clone() and split() methods. */
-        InternalIterator(InternalIterator it, boolean split) {
+        /** Creates iterator for split() methods */
+        Traverser(Traverser it, boolean split) {
             this.map = it.map;
             this.tab = it.tab;
             this.baseSize = it.baseSize;
             int lo = it.baseIndex;
             int hi = this.baseLimit = it.baseLimit;
-            this.index = this.baseIndex =
-                (split) ? (it.baseLimit = (lo + hi + 1) >>> 1) : lo;
+            int i;
+            if (split) // adjust parent
+                i = it.baseLimit = (lo + hi + 1) >>> 1;
+            else       // clone parent
+                i = lo;
+            this.index = this.baseIndex = i;
         }
 
         /**
@@ -2244,6 +2341,9 @@ public class ConcurrentHashMapV8
         }
 
         public final boolean hasMoreElements() { return hasNext(); }
+        public final void setRawResult(Object x) { }
+        public R getRawResult() { return null; }
+        public boolean exec() { return true; }
     }
 
     /* ---------------- Public operations -------------- */
@@ -2353,7 +2453,16 @@ public class ConcurrentHashMapV8
                 (int)n);
     }
 
-    final long longSize() { // accurate version of size needed for views
+    /**
+     * Returns the number of mappings. This method should be used
+     * instead of {@link #size} because a ConcurrentHashMap may
+     * contain more mappings than can be represented as an int. The
+     * value returned is a snapshot; the actual count may differ if
+     * there are ongoing concurrent insertions of removals.
+     *
+     * @return the number of mappings
+     */
+    public long mappingCount() {
         long n = counter.sum();
         return (n < 0L) ? 0L : n;
     }
@@ -2370,7 +2479,7 @@ public class ConcurrentHashMapV8
      * @throws NullPointerException if the specified key is null
      */
     @SuppressWarnings("unchecked")
-    public V get(Object key) {
+        public V get(Object key) {
         if (key == null)
             throw new NullPointerException();
         return (V)internalGet(key);
@@ -2405,7 +2514,7 @@ public class ConcurrentHashMapV8
         if (value == null)
             throw new NullPointerException();
         Object v;
-        InternalIterator it = new InternalIterator(this);
+        Traverser it = new Traverser(this);
         while ((v = it.advance()) != null) {
             if (v == value || value.equals(v))
                 return true;
@@ -2446,7 +2555,7 @@ public class ConcurrentHashMapV8
      * @throws NullPointerException if the specified key or value is null
      */
     @SuppressWarnings("unchecked")
-    public V put(K key, V value) {
+        public V put(K key, V value) {
         if (key == null || value == null)
             throw new NullPointerException();
         return (V)internalPut(key, value);
@@ -2460,7 +2569,7 @@ public class ConcurrentHashMapV8
      * @throws NullPointerException if the specified key or value is null
      */
     @SuppressWarnings("unchecked")
-    public V putIfAbsent(K key, V value) {
+        public V putIfAbsent(K key, V value) {
         if (key == null || value == null)
             throw new NullPointerException();
         return (V)internalPutIfAbsent(key, value);
@@ -2484,7 +2593,7 @@ public class ConcurrentHashMapV8
      * 
 {@code
      * if (map.containsKey(key))
      *   return map.get(key);
-     * value = mappingFunction.map(key);
+     * value = mappingFunction.apply(key);
      * if (value != null)
      *   map.put(key, value);
      * return value;}
@@ -2501,7 +2610,7 @@ public class ConcurrentHashMapV8 * memoized result, as in: * *
 {@code
-     * map.computeIfAbsent(key, new MappingFunction() {
+     * map.computeIfAbsent(key, new Fun() {
      *   public V map(K k) { return new Value(f(k)); }});}
* * @param key key with which the specified value is to be associated @@ -2517,18 +2626,59 @@ public class ConcurrentHashMapV8 * in which case the mapping is left unestablished */ @SuppressWarnings("unchecked") - public V computeIfAbsent(K key, MappingFunction mappingFunction) { + public V computeIfAbsent(K key, Fun mappingFunction) { if (key == null || mappingFunction == null) throw new NullPointerException(); return (V)internalComputeIfAbsent(key, mappingFunction); } /** + * If the given key is present, computes a new mapping value given a key and + * its current mapped value. This is equivalent to + *
 {@code
+     *   if (map.containsKey(key)) {
+     *     value = remappingFunction.apply(key, map.get(key));
+     *     if (value != null)
+     *       map.put(key, value);
+     *     else
+     *       map.remove(key);
+     *   }
+     * }
+ * + * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. For example, + * to either create or append new messages to a value mapping: + * + * @param key key with which the specified value is to be associated + * @param remappingFunction the function to compute a value + * @return the new value associated with + * the specified key, or null if none. + * @throws NullPointerException if the specified key or remappingFunction + * is null + * @throws IllegalStateException if the computation detectably + * attempts a recursive update to this map that would + * otherwise never complete + * @throws RuntimeException or Error if the remappingFunction does so, + * in which case the mapping is unchanged + */ + public V computeIfPresent(K key, BiFun remappingFunction) { + if (key == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalCompute(key, true, remappingFunction); + } + + /** * Computes a new mapping value given a key and * its current mapped value (or {@code null} if there is no current * mapping). This is equivalent to *
 {@code
-     *   value = remappingFunction.remap(key, map.get(key));
+     *   value = remappingFunction.apply(key, map.get(key));
      *   if (value != null)
      *     map.put(key, value);
      *   else
@@ -2548,8 +2698,8 @@ public class ConcurrentHashMapV8
      * 
 {@code
      * Map map = ...;
      * final String msg = ...;
-     * map.compute(key, new RemappingFunction() {
-     *   public String remap(Key k, String v) {
+     * map.compute(key, new BiFun() {
+     *   public String apply(Key k, String v) {
      *    return (v == null) ? msg : v + msg;});}}
* * @param key key with which the specified value is to be associated @@ -2564,11 +2714,43 @@ public class ConcurrentHashMapV8 * @throws RuntimeException or Error if the remappingFunction does so, * in which case the mapping is unchanged */ - @SuppressWarnings("unchecked") - public V compute(K key, RemappingFunction remappingFunction) { + // @SuppressWarnings("unchecked") + public V compute(K key, BiFun remappingFunction) { if (key == null || remappingFunction == null) throw new NullPointerException(); - return (V)internalCompute(key, remappingFunction); + return (V)internalCompute(key, false, remappingFunction); + } + + /** + * If the specified key is not already associated + * with a value, associate it with the given value. + * Otherwise, replace the value with the results of + * the given remapping function. This is equivalent to: + *
 {@code
+     *   if (!map.containsKey(key))
+     *     map.put(value);
+     *   else {
+     *     newValue = remappingFunction.apply(map.get(key), value);
+     *     if (value != null)
+     *       map.put(key, value);
+     *     else
+     *       map.remove(key);
+     *   }
+     * }
+ * except that the action is performed atomically. If the + * function returns {@code null}, the mapping is removed. If the + * function itself throws an (unchecked) exception, the exception + * is rethrown to its caller, and the current mapping is left + * unchanged. Some attempted update operations on this map by + * other threads may be blocked while computation is in progress, + * so the computation should be short and simple, and must not + * attempt to update any other mappings of this Map. + */ + // @SuppressWarnings("unchecked") + public V merge(K key, V value, BiFun remappingFunction) { + if (key == null || value == null || remappingFunction == null) + throw new NullPointerException(); + return (V)internalMerge(key, value, remappingFunction); } /** @@ -2581,7 +2763,7 @@ public class ConcurrentHashMapV8 * @throws NullPointerException if the specified key is null */ @SuppressWarnings("unchecked") - public V remove(Object key) { + public V remove(Object key) { if (key == null) throw new NullPointerException(); return (V)internalReplace(key, null, null); @@ -2619,7 +2801,7 @@ public class ConcurrentHashMapV8 * @throws NullPointerException if the specified key or value is null */ @SuppressWarnings("unchecked") - public V replace(K key, V value) { + public V replace(K key, V value) { if (key == null || value == null) throw new NullPointerException(); return (V)internalReplace(key, value, null); @@ -2751,7 +2933,7 @@ public class ConcurrentHashMapV8 */ public int hashCode() { int h = 0; - InternalIterator it = new InternalIterator(this); + Traverser it = new Traverser(this); Object v; while ((v = it.advance()) != null) { h += it.nextKey.hashCode() ^ v.hashCode(); @@ -2771,7 +2953,7 @@ public class ConcurrentHashMapV8 * @return a string representation of this map */ public String toString() { - InternalIterator it = new InternalIterator(this); + Traverser it = new Traverser(this); StringBuilder sb = new StringBuilder(); sb.append('{'); Object v; @@ -2804,7 +2986,7 @@ public class ConcurrentHashMapV8 if (!(o instanceof Map)) return false; Map m = (Map) o; - InternalIterator it = new InternalIterator(this); + Traverser it = new Traverser(this); Object val; while ((val = it.advance()) != null) { Object v = m.get(it.nextKey); @@ -2825,10 +3007,10 @@ public class ConcurrentHashMapV8 /* ----------------Iterators -------------- */ - static final class KeyIterator extends InternalIterator + static final class KeyIterator extends Traverser implements Spliterator, Enumeration { KeyIterator(ConcurrentHashMapV8 map) { super(map); } - KeyIterator(InternalIterator it, boolean split) { + KeyIterator(Traverser it, boolean split) { super(it, split); } public KeyIterator split() { @@ -2836,14 +3018,8 @@ public class ConcurrentHashMapV8 throw new IllegalStateException(); return new KeyIterator(this, true); } - public KeyIterator clone() { - if (last != null || (next != null && nextVal == null)) - throw new IllegalStateException(); - return new KeyIterator(this, false); - } - @SuppressWarnings("unchecked") - public final K next() { + public final K next() { if (nextVal == null && advance() == null) throw new NoSuchElementException(); Object k = nextKey; @@ -2854,10 +3030,10 @@ public class ConcurrentHashMapV8 public final K nextElement() { return next(); } } - static final class ValueIterator extends InternalIterator + static final class ValueIterator extends Traverser implements Spliterator, Enumeration { ValueIterator(ConcurrentHashMapV8 map) { super(map); } - ValueIterator(InternalIterator it, boolean split) { + ValueIterator(Traverser it, boolean split) { super(it, split); } public ValueIterator split() { @@ -2866,14 +3042,8 @@ public class ConcurrentHashMapV8 return new ValueIterator(this, true); } - public ValueIterator clone() { - if (last != null || (next != null && nextVal == null)) - throw new IllegalStateException(); - return new ValueIterator(this, false); - } - @SuppressWarnings("unchecked") - public final V next() { + public final V next() { Object v; if ((v = nextVal) == null && (v = advance()) == null) throw new NoSuchElementException(); @@ -2884,10 +3054,10 @@ public class ConcurrentHashMapV8 public final V nextElement() { return next(); } } - static final class EntryIterator extends InternalIterator + static final class EntryIterator extends Traverser implements Spliterator> { EntryIterator(ConcurrentHashMapV8 map) { super(map); } - EntryIterator(InternalIterator it, boolean split) { + EntryIterator(Traverser it, boolean split) { super(it, split); } public EntryIterator split() { @@ -2895,14 +3065,9 @@ public class ConcurrentHashMapV8 throw new IllegalStateException(); return new EntryIterator(this, true); } - public EntryIterator clone() { - if (last != null || (next != null && nextVal == null)) - throw new IllegalStateException(); - return new EntryIterator(this, false); - } @SuppressWarnings("unchecked") - public final Map.Entry next() { + public final Map.Entry next() { Object v; if ((v = nextVal) == null && (v = advance()) == null) throw new NoSuchElementException(); @@ -2960,9 +3125,9 @@ public class ConcurrentHashMapV8 /** * Base class for views. */ - static abstract class MapView { + static abstract class CHMView { final ConcurrentHashMapV8 map; - MapView(ConcurrentHashMapV8 map) { this.map = map; } + CHMView(ConcurrentHashMapV8 map) { this.map = map; } public final int size() { return map.size(); } public final boolean isEmpty() { return map.isEmpty(); } public final void clear() { map.clear(); } @@ -2975,7 +3140,7 @@ public class ConcurrentHashMapV8 private static final String oomeMsg = "Required array size too large"; public final Object[] toArray() { - long sz = map.longSize(); + long sz = map.mappingCount(); if (sz > (long)(MAX_ARRAY_SIZE)) throw new OutOfMemoryError(oomeMsg); int n = (int)sz; @@ -2998,8 +3163,8 @@ public class ConcurrentHashMapV8 } @SuppressWarnings("unchecked") - public final T[] toArray(T[] a) { - long sz = map.longSize(); + public final T[] toArray(T[] a) { + long sz = map.mappingCount(); if (sz > (long)(MAX_ARRAY_SIZE)) throw new OutOfMemoryError(oomeMsg); int m = (int)sz; @@ -3086,8 +3251,10 @@ public class ConcurrentHashMapV8 } - static final class KeySet extends MapView implements Set { - KeySet(ConcurrentHashMapV8 map) { super(map); } + static final class KeySet extends CHMView implements Set { + KeySet(ConcurrentHashMapV8 map) { + super(map); + } public final boolean contains(Object o) { return map.containsKey(o); } public final boolean remove(Object o) { return map.remove(o) != null; } public final Iterator iterator() { @@ -3107,7 +3274,8 @@ public class ConcurrentHashMapV8 } } - static final class Values extends MapView + + static final class Values extends CHMView implements Collection { Values(ConcurrentHashMapV8 map) { super(map); } public final boolean contains(Object o) { return map.containsValue(o); } @@ -3132,9 +3300,10 @@ public class ConcurrentHashMapV8 public final boolean addAll(Collection c) { throw new UnsupportedOperationException(); } + } - static final class EntrySet extends MapView + static final class EntrySet extends CHMView implements Set> { EntrySet(ConcurrentHashMapV8 map) { super(map); } public final boolean contains(Object o) { @@ -3191,8 +3360,8 @@ public class ConcurrentHashMapV8 * The key-value mappings are emitted in no particular order. */ @SuppressWarnings("unchecked") - private void writeObject(java.io.ObjectOutputStream s) - throws java.io.IOException { + private void writeObject(java.io.ObjectOutputStream s) + throws java.io.IOException { if (segments == null) { // for serialization compatibility segments = (Segment[]) new Segment[DEFAULT_CONCURRENCY_LEVEL]; @@ -3200,7 +3369,7 @@ public class ConcurrentHashMapV8 segments[i] = new Segment(LOAD_FACTOR); } s.defaultWriteObject(); - InternalIterator it = new InternalIterator(this); + Traverser it = new Traverser(this); Object v; while ((v = it.advance()) != null) { s.writeObject(it.nextKey); @@ -3216,8 +3385,8 @@ public class ConcurrentHashMapV8 * @param s the stream */ @SuppressWarnings("unchecked") - private void readObject(java.io.ObjectInputStream s) - throws java.io.IOException, ClassNotFoundException { + private void readObject(java.io.ObjectInputStream s) + throws java.io.IOException, ClassNotFoundException { s.defaultReadObject(); this.segments = null; // unneeded // initialize transient final field @@ -3294,6 +3463,3247 @@ public class ConcurrentHashMapV8 } } + + // ------------------------------------------------------- + + // Sams + /** Interface describing a void action of one argument */ + public interface Action { void apply(A a); } + /** Interface describing a void action of two arguments */ + public interface BiAction { void apply(A a, B b); } + /** Interface describing a function of one argument */ + public interface Fun { T apply(A a); } + /** Interface describing a function of two arguments */ + public interface BiFun { T apply(A a, B b); } + /** Interface describing a function of no arguments */ + public interface Generator { T apply(); } + /** Interface describing a function mapping its argument to a double */ + public interface ObjectToDouble { double apply(A a); } + /** Interface describing a function mapping its argument to a long */ + public interface ObjectToLong { long apply(A a); } + /** Interface describing a function mapping its argument to an int */ + public interface ObjectToInt {int apply(A a); } + /** Interface describing a function mapping two arguments to a double */ + public interface ObjectByObjectToDouble { double apply(A a, B b); } + /** Interface describing a function mapping two arguments to a long */ + public interface ObjectByObjectToLong { long apply(A a, B b); } + /** Interface describing a function mapping two arguments to an int */ + public interface ObjectByObjectToInt {int apply(A a, B b); } + /** Interface describing a function mapping a double to a double */ + public interface DoubleToDouble { double apply(double a); } + /** Interface describing a function mapping a long to a long */ + public interface LongToLong { long apply(long a); } + /** Interface describing a function mapping an int to an int */ + public interface IntToInt { int apply(int a); } + /** Interface describing a function mapping two doubles to a double */ + public interface DoubleByDoubleToDouble { double apply(double a, double b); } + /** Interface describing a function mapping two longs to a long */ + public interface LongByLongToLong { long apply(long a, long b); } + /** Interface describing a function mapping two ints to an int */ + public interface IntByIntToInt { int apply(int a, int b); } + + + // ------------------------------------------------------- + + /** + * Returns an extended {@link Parallel} view of this map using the + * given executor for bulk parallel operations. + * + * @param executor the executor + * @return a parallel view + */ + public Parallel parallel(ForkJoinPool executor) { + return new Parallel(executor); + } + + /** + * An extended view of a ConcurrentHashMap supporting bulk + * parallel operations. These operations are designed to be be + * safely, and often sensibly, applied even with maps that are + * being concurrently updated by other threads; for example, when + * computing a snapshot summary of the values in a shared + * registry. There are three kinds of operation, each with four + * forms, accepting functions with Keys, Values, Entries, and + * (Key, Value) arguments and/or return values. Because the + * elements of a ConcurrentHashMap are not ordered in any + * particular way, and may be processed in different orders in + * different parallel executions, the correctness of supplied + * functions should not depend on any ordering, or on any other + * objects or values that may transiently change while computation + * is in progress; and except for forEach actions, should ideally + * be side-effect-free. + * + *
    + *
  • forEach: Perform a given action on each element. + * A variant form applies a given transformation on each element + * before performing the action.
  • + * + *
  • search: Return the first available non-null result of + * applying a given function on each element; skipping further + * search when a result is found.
  • + * + *
  • reduce: Accumulate each element. The supplied reduction + * function cannot rely on ordering (more formally, it should be + * both associative and commutative). There are five variants: + * + *
      + * + *
    • Plain reductions. (There is not a form of this method for + * (key, value) function arguments since there is no corresponding + * return type.)
    • + * + *
    • Mapped reductions that accumulate the results of a given + * function applied to each element.
    • + * + *
    • Reductions to scalar doubles, longs, and ints, using a + * given basis value.
    • + * + * + *
    + *
+ * + *

The concurrency properties of the bulk operations follow + * from those of ConcurrentHashMap: Any non-null result returned + * from {@code get(key)} and related access methods bears a + * happens-before relation with the associated insertion or + * update. The result of any bulk operation reflects the + * composition of these per-element relations (but is not + * necessarily atomic with respect to the map as a whole unless it + * is somehow known to be quiescent). Conversely, because keys + * and values in the map are never null, null serves as a reliable + * atomic indicator of the current lack of any result. To + * maintain this property, null serves as an implicit basis for + * all non-scalar reduction operations. For the double, long, and + * int versions, the basis should be one that, when combined with + * any other value, returns that other value (more formally, it + * should be the identity element for the reduction). Most common + * reductions have these properties; for example, computing a sum + * with basis 0 or a minimum with basis MAX_VALUE. + * + *

Search and transformation functions provided as arguments + * should similarly return null to indicate the lack of any result + * (in which case it is not used). In the case of mapped + * reductions, this also enables transformations to serve as + * filters, returning null (or, in the case of primitive + * specializations, the identity basis) if the element should not + * be combined. You can create compound transformations and + * filterings by composing them yourself under this "null means + * there is nothing there now" rule before using them in search or + * reduce operations. + * + *

Methods accepting and/or returning Entry arguments maintain + * key-value associations. They may be useful for example when + * finding the key for the greatest value. Note that "plain" Entry + * arguments can be supplied using {@code new + * AbstractMap.SimpleEntry(k,v)}. + * + *

Bulk operations may complete abruptly, throwing an + * exception encountered in the application of a supplied + * function. Bear in mind when handling such exceptions that other + * concurrently executing functions could also have thrown + * exceptions, or would have done so if the first exception had + * not occurred. + * + *

Parallel speedups compared to sequential processing are + * common but not guaranteed. Operations involving brief + * functions on small maps may execute more slowly than sequential + * loops if the underlying work to parallelize the computation is + * more expensive than the computation itself. Similarly, + * parallelization may not lead to much actual parallelism if all + * processors are busy performing unrelated tasks. + * + *

All arguments to all task methods must be non-null. + * + *

jsr166e note: During transition, this class + * uses nested functional interfaces with different names but the + * same forms as those expected for JDK8. + */ + public class Parallel { + final ForkJoinPool fjp; + + /** + * Returns an extended view of this map using the given + * executor for bulk parallel operations. + * + * @param executor the executor + */ + public Parallel(ForkJoinPool executor) { + this.fjp = executor; + } + + /** + * Performs the given action for each (key, value). + * + * @param action the action + */ + public void forEach(BiAction action) { + fjp.invoke(ForkJoinTasks.forEach + (ConcurrentHashMapV8.this, action)); + } + + /** + * Performs the given action for each non-null transformation + * of each (key, value). + * + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case the action is not applied). + * @param action the action + */ + public void forEach(BiFun transformer, + Action action) { + fjp.invoke(ForkJoinTasks.forEach + (ConcurrentHashMapV8.this, transformer, action)); + } + + /** + * Returns a non-null result from applying the given search + * function on each (key, value), or null if none. Further + * element processing is suppressed upon success. However, + * this method does not return until other in-progress + * parallel invocations of the search function also complete. + * + * @param searchFunction a function returning a non-null + * result on success, else null + * @return a non-null result from applying the given search + * function on each (key, value), or null if none + */ + public U search(BiFun searchFunction) { + return fjp.invoke(ForkJoinTasks.search + (ConcurrentHashMapV8.this, searchFunction)); + } + + /** + * Returns the result of accumulating the given transformation + * of all (key, value) pairs using the given reducer to + * combine values, or null if none. + * + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case it is not combined). + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all (key, value) pairs + */ + public U reduce(BiFun transformer, + BiFun reducer) { + return fjp.invoke(ForkJoinTasks.reduce + (ConcurrentHashMapV8.this, transformer, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all (key, value) pairs using the given reducer to + * combine values, and the given basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all (key, value) pairs + */ + public double reduceToDouble(ObjectByObjectToDouble transformer, + double basis, + DoubleByDoubleToDouble reducer) { + return fjp.invoke(ForkJoinTasks.reduceToDouble + (ConcurrentHashMapV8.this, transformer, basis, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all (key, value) pairs using the given reducer to + * combine values, and the given basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all (key, value) pairs using the given reducer to + * combine values, and the given basis as an identity value. + */ + public long reduceToLong(ObjectByObjectToLong transformer, + long basis, + LongByLongToLong reducer) { + return fjp.invoke(ForkJoinTasks.reduceToLong + (ConcurrentHashMapV8.this, transformer, basis, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all (key, value) pairs using the given reducer to + * combine values, and the given basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all (key, value) pairs + */ + public int reduceToInt(ObjectByObjectToInt transformer, + int basis, + IntByIntToInt reducer) { + return fjp.invoke(ForkJoinTasks.reduceToInt + (ConcurrentHashMapV8.this, transformer, basis, reducer)); + } + + /** + * Performs the given action for each key + * + * @param action the action + */ + public void forEachKey(Action action) { + fjp.invoke(ForkJoinTasks.forEachKey + (ConcurrentHashMapV8.this, action)); + } + + /** + * Performs the given action for each non-null transformation + * of each key + * + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case the action is not applied). + * @param action the action + */ + public void forEachKey(Fun transformer, + Action action) { + fjp.invoke(ForkJoinTasks.forEachKey + (ConcurrentHashMapV8.this, transformer, action)); + } + + /** + * Returns a non-null result from applying the given search + * function on each key, or null if none. Further element + * processing is suppressed upon success. However, this method + * does not return until other in-progress parallel + * invocations of the search function also complete. + * + * @param searchFunction a function returning a non-null + * result on success, else null + * @return a non-null result from applying the given search + * function on each key, or null if none + */ + public U searchKeys(Fun searchFunction) { + return fjp.invoke(ForkJoinTasks.searchKeys + (ConcurrentHashMapV8.this, searchFunction)); + } + + /** + * Returns the result of accumulating all keys using the given + * reducer to combine values, or null if none. + * + * @param reducer a commutative associative combining function + * @return the result of accumulating all keys using the given + * reducer to combine values, or null if none + */ + public K reduceKeys(BiFun reducer) { + return fjp.invoke(ForkJoinTasks.reduceKeys + (ConcurrentHashMapV8.this, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all keys using the given reducer to combine values, or + * null if none. + * + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case it is not combined). + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all keys + */ + public U reduceKeys(Fun transformer, + BiFun reducer) { + return fjp.invoke(ForkJoinTasks.reduceKeys + (ConcurrentHashMapV8.this, transformer, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all keys using the given reducer to combine values, and + * the given basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all keys + */ + public double reduceKeysToDouble(ObjectToDouble transformer, + double basis, + DoubleByDoubleToDouble reducer) { + return fjp.invoke(ForkJoinTasks.reduceKeysToDouble + (ConcurrentHashMapV8.this, transformer, basis, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all keys using the given reducer to combine values, and + * the given basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all keys + */ + public long reduceKeysToLong(ObjectToLong transformer, + long basis, + LongByLongToLong reducer) { + return fjp.invoke(ForkJoinTasks.reduceKeysToLong + (ConcurrentHashMapV8.this, transformer, basis, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all keys using the given reducer to combine values, and + * the given basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all keys + */ + public int reduceKeysToInt(ObjectToInt transformer, + int basis, + IntByIntToInt reducer) { + return fjp.invoke(ForkJoinTasks.reduceKeysToInt + (ConcurrentHashMapV8.this, transformer, basis, reducer)); + } + + /** + * Performs the given action for each value + * + * @param action the action + */ + public void forEachValue(Action action) { + fjp.invoke(ForkJoinTasks.forEachValue + (ConcurrentHashMapV8.this, action)); + } + + /** + * Performs the given action for each non-null transformation + * of each value + * + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case the action is not applied). + */ + public void forEachValue(Fun transformer, + Action action) { + fjp.invoke(ForkJoinTasks.forEachValue + (ConcurrentHashMapV8.this, transformer, action)); + } + + /** + * Returns a non-null result from applying the given search + * function on each value, or null if none. Further element + * processing is suppressed upon success. However, this method + * does not return until other in-progress parallel + * invocations of the search function also complete. + * + * @param searchFunction a function returning a non-null + * result on success, else null + * @return a non-null result from applying the given search + * function on each value, or null if none + * + */ + public U searchValues(Fun searchFunction) { + return fjp.invoke(ForkJoinTasks.searchValues + (ConcurrentHashMapV8.this, searchFunction)); + } + + /** + * Returns the result of accumulating all values using the + * given reducer to combine values, or null if none. + * + * @param reducer a commutative associative combining function + * @return the result of accumulating all values + */ + public V reduceValues(BiFun reducer) { + return fjp.invoke(ForkJoinTasks.reduceValues + (ConcurrentHashMapV8.this, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all values using the given reducer to combine values, or + * null if none. + * + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case it is not combined). + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all values + */ + public U reduceValues(Fun transformer, + BiFun reducer) { + return fjp.invoke(ForkJoinTasks.reduceValues + (ConcurrentHashMapV8.this, transformer, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all values using the given reducer to combine values, + * and the given basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all values + */ + public double reduceValuesToDouble(ObjectToDouble transformer, + double basis, + DoubleByDoubleToDouble reducer) { + return fjp.invoke(ForkJoinTasks.reduceValuesToDouble + (ConcurrentHashMapV8.this, transformer, basis, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all values using the given reducer to combine values, + * and the given basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all values + */ + public long reduceValuesToLong(ObjectToLong transformer, + long basis, + LongByLongToLong reducer) { + return fjp.invoke(ForkJoinTasks.reduceValuesToLong + (ConcurrentHashMapV8.this, transformer, basis, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all values using the given reducer to combine values, + * and the given basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all values + */ + public int reduceValuesToInt(ObjectToInt transformer, + int basis, + IntByIntToInt reducer) { + return fjp.invoke(ForkJoinTasks.reduceValuesToInt + (ConcurrentHashMapV8.this, transformer, basis, reducer)); + } + + /** + * Perform the given action for each entry + * + * @param action the action + */ + public void forEachEntry(Action> action) { + fjp.invoke(ForkJoinTasks.forEachEntry + (ConcurrentHashMapV8.this, action)); + } + + /** + * Perform the given action for each non-null transformation + * of each entry + * + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case the action is not applied). + * @param action the action + */ + public void forEachEntry(Fun, ? extends U> transformer, + Action action) { + fjp.invoke(ForkJoinTasks.forEachEntry + (ConcurrentHashMapV8.this, transformer, action)); + } + + /** + * Returns a non-null result from applying the given search + * function on each entry, or null if none. Further element + * processing is suppressed upon success. However, this method + * does not return until other in-progress parallel + * invocations of the search function also complete. + * + * @param searchFunction a function returning a non-null + * result on success, else null + * @return a non-null result from applying the given search + * function on each entry, or null if none + */ + public U searchEntries(Fun, ? extends U> searchFunction) { + return fjp.invoke(ForkJoinTasks.searchEntries + (ConcurrentHashMapV8.this, searchFunction)); + } + + /** + * Returns the result of accumulating all entries using the + * given reducer to combine values, or null if none. + * + * @param reducer a commutative associative combining function + * @return the result of accumulating all entries + */ + public Map.Entry reduceEntries(BiFun, Map.Entry, ? extends Map.Entry> reducer) { + return fjp.invoke(ForkJoinTasks.reduceEntries + (ConcurrentHashMapV8.this, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all entries using the given reducer to combine values, + * or null if none. + * + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case it is not combined). + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all entries + */ + public U reduceEntries(Fun, ? extends U> transformer, + BiFun reducer) { + return fjp.invoke(ForkJoinTasks.reduceEntries + (ConcurrentHashMapV8.this, transformer, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all entries using the given reducer to combine values, + * and the given basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all entries + */ + public double reduceEntriesToDouble(ObjectToDouble> transformer, + double basis, + DoubleByDoubleToDouble reducer) { + return fjp.invoke(ForkJoinTasks.reduceEntriesToDouble + (ConcurrentHashMapV8.this, transformer, basis, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all entries using the given reducer to combine values, + * and the given basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all entries + */ + public long reduceEntriesToLong(ObjectToLong> transformer, + long basis, + LongByLongToLong reducer) { + return fjp.invoke(ForkJoinTasks.reduceEntriesToLong + (ConcurrentHashMapV8.this, transformer, basis, reducer)); + } + + /** + * Returns the result of accumulating the given transformation + * of all entries using the given reducer to combine values, + * and the given basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the result of accumulating the given transformation + * of all entries + */ + public int reduceEntriesToInt(ObjectToInt> transformer, + int basis, + IntByIntToInt reducer) { + return fjp.invoke(ForkJoinTasks.reduceEntriesToInt + (ConcurrentHashMapV8.this, transformer, basis, reducer)); + } + } + + // --------------------------------------------------------------------- + + /** + * Predefined tasks for performing bulk parallel operations on + * ConcurrentHashMaps. These tasks follow the forms and rules used + * in class {@link Parallel}. Each method has the same name, but + * returns a task rather than invoking it. These methods may be + * useful in custom applications such as submitting a task without + * waiting for completion, or combining with other tasks. + */ + public static class ForkJoinTasks { + private ForkJoinTasks() {} + + /** + * Returns a task that when invoked, performs the given + * action for each (key, value) + * + * @param map the map + * @param action the action + * @return the task + */ + public static ForkJoinTask forEach + (ConcurrentHashMapV8 map, + BiAction action) { + if (action == null) throw new NullPointerException(); + return new ForEachMappingTask(map, action); + } + + /** + * Returns a task that when invoked, performs the given + * action for each non-null transformation of each (key, value) + * + * @param map the map + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case the action is not applied). + * @param action the action + * @return the task + */ + public static ForkJoinTask forEach + (ConcurrentHashMapV8 map, + BiFun transformer, + Action action) { + if (transformer == null || action == null) + throw new NullPointerException(); + return new ForEachTransformedMappingTask + (map, transformer, action); + } + + /** + * Returns a task that when invoked, returns a non-null + * result from applying the given search function on each + * (key, value), or null if none. Further element processing + * is suppressed upon success. However, this method does not + * return until other in-progress parallel invocations of the + * search function also complete. + * + * @param map the map + * @param searchFunction a function returning a non-null + * result on success, else null + * @return the task + */ + public static ForkJoinTask search + (ConcurrentHashMapV8 map, + BiFun searchFunction) { + if (searchFunction == null) throw new NullPointerException(); + return new SearchMappingsTask + (map, searchFunction, + new AtomicReference()); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all (key, value) pairs + * using the given reducer to combine values, or null if none. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case it is not combined). + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduce + (ConcurrentHashMapV8 map, + BiFun transformer, + BiFun reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceMappingsTask + (map, transformer, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all (key, value) pairs + * using the given reducer to combine values, and the given + * basis as an identity value. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceToDouble + (ConcurrentHashMapV8 map, + ObjectByObjectToDouble transformer, + double basis, + DoubleByDoubleToDouble reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceMappingsToDoubleTask + (map, transformer, basis, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all (key, value) pairs + * using the given reducer to combine values, and the given + * basis as an identity value. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceToLong + (ConcurrentHashMapV8 map, + ObjectByObjectToLong transformer, + long basis, + LongByLongToLong reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceMappingsToLongTask + (map, transformer, basis, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all (key, value) pairs + * using the given reducer to combine values, and the given + * basis as an identity value. + * + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceToInt + (ConcurrentHashMapV8 map, + ObjectByObjectToInt transformer, + int basis, + IntByIntToInt reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceMappingsToIntTask + (map, transformer, basis, reducer); + } + + /** + * Returns a task that when invoked, performs the given action + * for each key + * + * @param map the map + * @param action the action + * @return the task + */ + public static ForkJoinTask forEachKey + (ConcurrentHashMapV8 map, + Action action) { + if (action == null) throw new NullPointerException(); + return new ForEachKeyTask(map, action); + } + + /** + * Returns a task that when invoked, performs the given action + * for each non-null transformation of each key + * + * @param map the map + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case the action is not applied). + * @param action the action + * @return the task + */ + public static ForkJoinTask forEachKey + (ConcurrentHashMapV8 map, + Fun transformer, + Action action) { + if (transformer == null || action == null) + throw new NullPointerException(); + return new ForEachTransformedKeyTask + (map, transformer, action); + } + + /** + * Returns a task that when invoked, returns a non-null result + * from applying the given search function on each key, or + * null if none. Further element processing is suppressed + * upon success. However, this method does not return until + * other in-progress parallel invocations of the search + * function also complete. + * + * @param map the map + * @param searchFunction a function returning a non-null + * result on success, else null + * @return the task + */ + public static ForkJoinTask searchKeys + (ConcurrentHashMapV8 map, + Fun searchFunction) { + if (searchFunction == null) throw new NullPointerException(); + return new SearchKeysTask + (map, searchFunction, + new AtomicReference()); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating all keys using the given reducer to combine + * values, or null if none. + * + * @param map the map + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceKeys + (ConcurrentHashMapV8 map, + BiFun reducer) { + if (reducer == null) throw new NullPointerException(); + return new ReduceKeysTask + (map, reducer); + } + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all keys using the given + * reducer to combine values, or null if none. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case it is not combined). + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceKeys + (ConcurrentHashMapV8 map, + Fun transformer, + BiFun reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceKeysTask + (map, transformer, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all keys using the given + * reducer to combine values, and the given basis as an + * identity value. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceKeysToDouble + (ConcurrentHashMapV8 map, + ObjectToDouble transformer, + double basis, + DoubleByDoubleToDouble reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceKeysToDoubleTask + (map, transformer, basis, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all keys using the given + * reducer to combine values, and the given basis as an + * identity value. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceKeysToLong + (ConcurrentHashMapV8 map, + ObjectToLong transformer, + long basis, + LongByLongToLong reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceKeysToLongTask + (map, transformer, basis, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all keys using the given + * reducer to combine values, and the given basis as an + * identity value. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceKeysToInt + (ConcurrentHashMapV8 map, + ObjectToInt transformer, + int basis, + IntByIntToInt reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceKeysToIntTask + (map, transformer, basis, reducer); + } + + /** + * Returns a task that when invoked, performs the given action + * for each value + * + * @param map the map + * @param action the action + */ + public static ForkJoinTask forEachValue + (ConcurrentHashMapV8 map, + Action action) { + if (action == null) throw new NullPointerException(); + return new ForEachValueTask(map, action); + } + + /** + * Returns a task that when invoked, performs the given action + * for each non-null transformation of each value + * + * @param map the map + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case the action is not applied). + * @param action the action + */ + public static ForkJoinTask forEachValue + (ConcurrentHashMapV8 map, + Fun transformer, + Action action) { + if (transformer == null || action == null) + throw new NullPointerException(); + return new ForEachTransformedValueTask + (map, transformer, action); + } + + /** + * Returns a task that when invoked, returns a non-null result + * from applying the given search function on each value, or + * null if none. Further element processing is suppressed + * upon success. However, this method does not return until + * other in-progress parallel invocations of the search + * function also complete. + * + * @param map the map + * @param searchFunction a function returning a non-null + * result on success, else null + * @return the task + * + */ + public static ForkJoinTask searchValues + (ConcurrentHashMapV8 map, + Fun searchFunction) { + if (searchFunction == null) throw new NullPointerException(); + return new SearchValuesTask + (map, searchFunction, + new AtomicReference()); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating all values using the given reducer to combine + * values, or null if none. + * + * @param map the map + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceValues + (ConcurrentHashMapV8 map, + BiFun reducer) { + if (reducer == null) throw new NullPointerException(); + return new ReduceValuesTask + (map, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all values using the + * given reducer to combine values, or null if none. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case it is not combined). + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceValues + (ConcurrentHashMapV8 map, + Fun transformer, + BiFun reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceValuesTask + (map, transformer, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all values using the + * given reducer to combine values, and the given basis as an + * identity value. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceValuesToDouble + (ConcurrentHashMapV8 map, + ObjectToDouble transformer, + double basis, + DoubleByDoubleToDouble reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceValuesToDoubleTask + (map, transformer, basis, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all values using the + * given reducer to combine values, and the given basis as an + * identity value. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceValuesToLong + (ConcurrentHashMapV8 map, + ObjectToLong transformer, + long basis, + LongByLongToLong reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceValuesToLongTask + (map, transformer, basis, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all values using the + * given reducer to combine values, and the given basis as an + * identity value. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceValuesToInt + (ConcurrentHashMapV8 map, + ObjectToInt transformer, + int basis, + IntByIntToInt reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceValuesToIntTask + (map, transformer, basis, reducer); + } + + /** + * Returns a task that when invoked, perform the given action + * for each entry + * + * @param map the map + * @param action the action + */ + public static ForkJoinTask forEachEntry + (ConcurrentHashMapV8 map, + Action> action) { + if (action == null) throw new NullPointerException(); + return new ForEachEntryTask(map, action); + } + + /** + * Returns a task that when invoked, perform the given action + * for each non-null transformation of each entry + * + * @param map the map + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case the action is not applied). + * @param action the action + */ + public static ForkJoinTask forEachEntry + (ConcurrentHashMapV8 map, + Fun, ? extends U> transformer, + Action action) { + if (transformer == null || action == null) + throw new NullPointerException(); + return new ForEachTransformedEntryTask + (map, transformer, action); + } + + /** + * Returns a task that when invoked, returns a non-null result + * from applying the given search function on each entry, or + * null if none. Further element processing is suppressed + * upon success. However, this method does not return until + * other in-progress parallel invocations of the search + * function also complete. + * + * @param map the map + * @param searchFunction a function returning a non-null + * result on success, else null + * @return the task + * + */ + public static ForkJoinTask searchEntries + (ConcurrentHashMapV8 map, + Fun, ? extends U> searchFunction) { + if (searchFunction == null) throw new NullPointerException(); + return new SearchEntriesTask + (map, searchFunction, + new AtomicReference()); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating all entries using the given reducer to combine + * values, or null if none. + * + * @param map the map + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask> reduceEntries + (ConcurrentHashMapV8 map, + BiFun, Map.Entry, ? extends Map.Entry> reducer) { + if (reducer == null) throw new NullPointerException(); + return new ReduceEntriesTask + (map, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all entries using the + * given reducer to combine values, or null if none. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element, or null of there is no transformation (in + * which case it is not combined). + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceEntries + (ConcurrentHashMapV8 map, + Fun, ? extends U> transformer, + BiFun reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceEntriesTask + (map, transformer, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all entries using the + * given reducer to combine values, and the given basis as an + * identity value. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceEntriesToDouble + (ConcurrentHashMapV8 map, + ObjectToDouble> transformer, + double basis, + DoubleByDoubleToDouble reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceEntriesToDoubleTask + (map, transformer, basis, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all entries using the + * given reducer to combine values, and the given basis as an + * identity value. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceEntriesToLong + (ConcurrentHashMapV8 map, + ObjectToLong> transformer, + long basis, + LongByLongToLong reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceEntriesToLongTask + (map, transformer, basis, reducer); + } + + /** + * Returns a task that when invoked, returns the result of + * accumulating the given transformation of all entries using the + * given reducer to combine values, and the given basis as an + * identity value. + * + * @param map the map + * @param transformer a function returning the transformation + * for an element + * @param basis the identity (initial default value) for the reduction + * @param reducer a commutative associative combining function + * @return the task + */ + public static ForkJoinTask reduceEntriesToInt + (ConcurrentHashMapV8 map, + ObjectToInt> transformer, + int basis, + IntByIntToInt reducer) { + if (transformer == null || reducer == null) + throw new NullPointerException(); + return new MapReduceEntriesToIntTask + (map, transformer, basis, reducer); + } + } + + // ------------------------------------------------------- + + /** + * Base for FJ tasks for bulk operations. This adds a variant of + * CountedCompleters and some split and merge bookeeping to + * iterator functionality. The forEach and reduce methods are + * similar to those illustrated in CountedCompleter documentation, + * except that bottom-up reduction completions perform them within + * their compute methods. The search methods are like forEach + * except they continually poll for success and exit early. Also, + * exceptions are handled in a simpler manner, by just trying to + * complete root task exceptionally. + */ + static abstract class BulkTask extends Traverser { + final BulkTask parent; // completion target + int batch; // split control + int pending; // completion control + + /** Constructor for root tasks */ + BulkTask(ConcurrentHashMapV8 map) { + super(map); + this.parent = null; + this.batch = -1; // force call to batch() on execution + } + + /** Constructor for subtasks */ + BulkTask(BulkTask parent, int batch, boolean split) { + super(parent, split); + this.parent = parent; + this.batch = batch; + } + + // FJ methods + + /** + * Propagate completion. Note that all reduce actions + * bypass this method to combine while completing. + */ + final void tryComplete() { + BulkTask a = this, s = a; + for (int c;;) { + if ((c = a.pending) == 0) { + if ((a = (s = a).parent) == null) { + s.quietlyComplete(); + break; + } + } + else if (U.compareAndSwapInt(a, PENDING, c, c - 1)) + break; + } + } + + /** + * Force root task to throw exception unless already complete. + */ + final void tryAbortComputation(Throwable ex) { + for (BulkTask a = this;;) { + BulkTask p = a.parent; + if (p == null) { + a.completeExceptionally(ex); + break; + } + a = p; + } + } + + public final boolean exec() { + try { + compute(); + } + catch(Throwable ex) { + tryAbortComputation(ex); + } + return false; + } + + public abstract void compute(); + + // utilities + + /** CompareAndSet pending count */ + final boolean casPending(int cmp, int val) { + return U.compareAndSwapInt(this, PENDING, cmp, val); + } + + /** + * Return approx exp2 of the number of times (minus one) to + * split task by two before executing leaf action. This value + * is faster to compute and more convenient to use as a guide + * to splitting than is the depth, since it is used while + * dividing by two anyway. + */ + final int batch() { + int b = batch; + if (b < 0) { + long n = map.counter.sum(); + int sp = getPool().getParallelism() << 3; // slack of 8 + b = batch = (n <= 0L)? 0 : (n < (long)sp) ? (int)n : sp; + } + return b; + } + + /** + * Error message for hoisted null checks of functions + */ + static final String NullFunctionMessage = + "Unexpected null function"; + + /** + * Return exportable snapshot entry + */ + static AbstractMap.SimpleEntry entryFor(K k, V v) { + return new AbstractMap.SimpleEntry(k, v); + } + + // Unsafe mechanics + private static final sun.misc.Unsafe U; + private static final long PENDING; + static { + try { + U = sun.misc.Unsafe.getUnsafe(); + PENDING = U.objectFieldOffset + (BulkTask.class.getDeclaredField("pending")); + } catch (Exception e) { + throw new Error(e); + } + } + } + + /* + * Task classes. Coded in a regular but ugly format/style to + * simplify checks that each variant differs in the right way from + * others. + */ + + static final class ForEachKeyTask + extends BulkTask { + final Action action; + ForEachKeyTask + (ConcurrentHashMapV8 m, + Action action) { + super(m); + this.action = action; + } + ForEachKeyTask + (BulkTask p, int b, boolean split, + Action action) { + super(p, b, split); + this.action = action; + } + public final void compute() { + final Action action = this.action; + if (action == null) + throw new Error(NullFunctionMessage); + int b = batch(), c; + while (b > 1 && baseIndex != baseLimit) { + do {} while (!casPending(c = pending, c+1)); + new ForEachKeyTask(this, b >>>= 1, true, action).fork(); + } + while (advance() != null) + action.apply((K)nextKey); + tryComplete(); + } + } + + static final class ForEachValueTask + extends BulkTask { + final Action action; + ForEachValueTask + (ConcurrentHashMapV8 m, + Action action) { + super(m); + this.action = action; + } + ForEachValueTask + (BulkTask p, int b, boolean split, + Action action) { + super(p, b, split); + this.action = action; + } + public final void compute() { + final Action action = this.action; + if (action == null) + throw new Error(NullFunctionMessage); + int b = batch(), c; + while (b > 1 && baseIndex != baseLimit) { + do {} while (!casPending(c = pending, c+1)); + new ForEachValueTask(this, b >>>= 1, true, action).fork(); + } + Object v; + while ((v = advance()) != null) + action.apply((V)v); + tryComplete(); + } + } + + static final class ForEachEntryTask + extends BulkTask { + final Action> action; + ForEachEntryTask + (ConcurrentHashMapV8 m, + Action> action) { + super(m); + this.action = action; + } + ForEachEntryTask + (BulkTask p, int b, boolean split, + Action> action) { + super(p, b, split); + this.action = action; + } + public final void compute() { + final Action> action = this.action; + if (action == null) + throw new Error(NullFunctionMessage); + int b = batch(), c; + while (b > 1 && baseIndex != baseLimit) { + do {} while (!casPending(c = pending, c+1)); + new ForEachEntryTask(this, b >>>= 1, true, action).fork(); + } + Object v; + while ((v = advance()) != null) + action.apply(entryFor((K)nextKey, (V)v)); + tryComplete(); + } + } + + static final class ForEachMappingTask + extends BulkTask { + final BiAction action; + ForEachMappingTask + (ConcurrentHashMapV8 m, + BiAction action) { + super(m); + this.action = action; + } + ForEachMappingTask + (BulkTask p, int b, boolean split, + BiAction action) { + super(p, b, split); + this.action = action; + } + + public final void compute() { + final BiAction action = this.action; + if (action == null) + throw new Error(NullFunctionMessage); + int b = batch(), c; + while (b > 1 && baseIndex != baseLimit) { + do {} while (!casPending(c = pending, c+1)); + new ForEachMappingTask(this, b >>>= 1, true, + action).fork(); + } + Object v; + while ((v = advance()) != null) + action.apply((K)nextKey, (V)v); + tryComplete(); + } + } + + static final class ForEachTransformedKeyTask + extends BulkTask { + final Fun transformer; + final Action action; + ForEachTransformedKeyTask + (ConcurrentHashMapV8 m, + Fun transformer, + Action action) { + super(m); + this.transformer = transformer; + this.action = action; + + } + ForEachTransformedKeyTask + (BulkTask p, int b, boolean split, + Fun transformer, + Action action) { + super(p, b, split); + this.transformer = transformer; + this.action = action; + } + public final void compute() { + final Fun transformer = + this.transformer; + final Action action = this.action; + if (transformer == null || action == null) + throw new Error(NullFunctionMessage); + int b = batch(), c; + while (b > 1 && baseIndex != baseLimit) { + do {} while (!casPending(c = pending, c+1)); + new ForEachTransformedKeyTask + (this, b >>>= 1, true, transformer, action).fork(); + } + U u; + while (advance() != null) { + if ((u = transformer.apply((K)nextKey)) != null) + action.apply(u); + } + tryComplete(); + } + } + + static final class ForEachTransformedValueTask + extends BulkTask { + final Fun transformer; + final Action action; + ForEachTransformedValueTask + (ConcurrentHashMapV8 m, + Fun transformer, + Action action) { + super(m); + this.transformer = transformer; + this.action = action; + + } + ForEachTransformedValueTask + (BulkTask p, int b, boolean split, + Fun transformer, + Action action) { + super(p, b, split); + this.transformer = transformer; + this.action = action; + } + public final void compute() { + final Fun transformer = + this.transformer; + final Action action = this.action; + if (transformer == null || action == null) + throw new Error(NullFunctionMessage); + int b = batch(), c; + while (b > 1 && baseIndex != baseLimit) { + do {} while (!casPending(c = pending, c+1)); + new ForEachTransformedValueTask + (this, b >>>= 1, true, transformer, action).fork(); + } + Object v; U u; + while ((v = advance()) != null) { + if ((u = transformer.apply((V)v)) != null) + action.apply(u); + } + tryComplete(); + } + } + + static final class ForEachTransformedEntryTask + extends BulkTask { + final Fun, ? extends U> transformer; + final Action action; + ForEachTransformedEntryTask + (ConcurrentHashMapV8 m, + Fun, ? extends U> transformer, + Action action) { + super(m); + this.transformer = transformer; + this.action = action; + + } + ForEachTransformedEntryTask + (BulkTask p, int b, boolean split, + Fun, ? extends U> transformer, + Action action) { + super(p, b, split); + this.transformer = transformer; + this.action = action; + } + public final void compute() { + final Fun, ? extends U> transformer = + this.transformer; + final Action action = this.action; + if (transformer == null || action == null) + throw new Error(NullFunctionMessage); + int b = batch(), c; + while (b > 1 && baseIndex != baseLimit) { + do {} while (!casPending(c = pending, c+1)); + new ForEachTransformedEntryTask + (this, b >>>= 1, true, transformer, action).fork(); + } + Object v; U u; + while ((v = advance()) != null) { + if ((u = transformer.apply(entryFor((K)nextKey, (V)v))) != null) + action.apply(u); + } + tryComplete(); + } + } + + static final class ForEachTransformedMappingTask + extends BulkTask { + final BiFun transformer; + final Action action; + ForEachTransformedMappingTask + (ConcurrentHashMapV8 m, + BiFun transformer, + Action action) { + super(m); + this.transformer = transformer; + this.action = action; + + } + ForEachTransformedMappingTask + (BulkTask p, int b, boolean split, + BiFun transformer, + Action action) { + super(p, b, split); + this.transformer = transformer; + this.action = action; + } + public final void compute() { + final BiFun transformer = + this.transformer; + final Action action = this.action; + if (transformer == null || action == null) + throw new Error(NullFunctionMessage); + int b = batch(), c; + while (b > 1 && baseIndex != baseLimit) { + do {} while (!casPending(c = pending, c+1)); + new ForEachTransformedMappingTask + (this, b >>>= 1, true, transformer, action).fork(); + } + Object v; U u; + while ((v = advance()) != null) { + if ((u = transformer.apply((K)nextKey, (V)v)) != null) + action.apply(u); + } + tryComplete(); + } + } + + static final class SearchKeysTask + extends BulkTask { + final Fun searchFunction; + final AtomicReference result; + SearchKeysTask + (ConcurrentHashMapV8 m, + Fun searchFunction, + AtomicReference result) { + super(m); + this.searchFunction = searchFunction; this.result = result; + } + SearchKeysTask + (BulkTask p, int b, boolean split, + Fun searchFunction, + AtomicReference result) { + super(p, b, split); + this.searchFunction = searchFunction; this.result = result; + } + public final void compute() { + AtomicReference result = this.result; + final Fun searchFunction = + this.searchFunction; + if (searchFunction == null || result == null) + throw new Error(NullFunctionMessage); + int b = batch(), c; + while (b > 1 && baseIndex != baseLimit && result.get() == null) { + do {} while (!casPending(c = pending, c+1)); + new SearchKeysTask(this, b >>>= 1, true, + searchFunction, result).fork(); + } + U u; + while (result.get() == null && advance() != null) { + if ((u = searchFunction.apply((K)nextKey)) != null) { + result.compareAndSet(null, u); + break; + } + } + tryComplete(); + } + public final U getRawResult() { return result.get(); } + } + + static final class SearchValuesTask + extends BulkTask { + final Fun searchFunction; + final AtomicReference result; + SearchValuesTask + (ConcurrentHashMapV8 m, + Fun searchFunction, + AtomicReference result) { + super(m); + this.searchFunction = searchFunction; this.result = result; + } + SearchValuesTask + (BulkTask p, int b, boolean split, + Fun searchFunction, + AtomicReference result) { + super(p, b, split); + this.searchFunction = searchFunction; this.result = result; + } + public final void compute() { + AtomicReference result = this.result; + final Fun searchFunction = + this.searchFunction; + if (searchFunction == null || result == null) + throw new Error(NullFunctionMessage); + int b = batch(), c; + while (b > 1 && baseIndex != baseLimit && result.get() == null) { + do {} while (!casPending(c = pending, c+1)); + new SearchValuesTask(this, b >>>= 1, true, + searchFunction, result).fork(); + } + Object v; U u; + while (result.get() == null && (v = advance()) != null) { + if ((u = searchFunction.apply((V)v)) != null) { + result.compareAndSet(null, u); + break; + } + } + tryComplete(); + } + public final U getRawResult() { return result.get(); } + } + + static final class SearchEntriesTask + extends BulkTask { + final Fun, ? extends U> searchFunction; + final AtomicReference result; + SearchEntriesTask + (ConcurrentHashMapV8 m, + Fun, ? extends U> searchFunction, + AtomicReference result) { + super(m); + this.searchFunction = searchFunction; this.result = result; + } + SearchEntriesTask + (BulkTask p, int b, boolean split, + Fun, ? extends U> searchFunction, + AtomicReference result) { + super(p, b, split); + this.searchFunction = searchFunction; this.result = result; + } + public final void compute() { + AtomicReference result = this.result; + final Fun, ? extends U> searchFunction = + this.searchFunction; + if (searchFunction == null || result == null) + throw new Error(NullFunctionMessage); + int b = batch(), c; + while (b > 1 && baseIndex != baseLimit && result.get() == null) { + do {} while (!casPending(c = pending, c+1)); + new SearchEntriesTask(this, b >>>= 1, true, + searchFunction, result).fork(); + } + Object v; U u; + while (result.get() == null && (v = advance()) != null) { + if ((u = searchFunction.apply(entryFor((K)nextKey, (V)v))) != null) { + result.compareAndSet(null, u); + break; + } + } + tryComplete(); + } + public final U getRawResult() { return result.get(); } + } + + static final class SearchMappingsTask + extends BulkTask { + final BiFun searchFunction; + final AtomicReference result; + SearchMappingsTask + (ConcurrentHashMapV8 m, + BiFun searchFunction, + AtomicReference result) { + super(m); + this.searchFunction = searchFunction; this.result = result; + } + SearchMappingsTask + (BulkTask p, int b, boolean split, + BiFun searchFunction, + AtomicReference result) { + super(p, b, split); + this.searchFunction = searchFunction; this.result = result; + } + public final void compute() { + AtomicReference result = this.result; + final BiFun searchFunction = + this.searchFunction; + if (searchFunction == null || result == null) + throw new Error(NullFunctionMessage); + int b = batch(), c; + while (b > 1 && baseIndex != baseLimit && result.get() == null) { + do {} while (!casPending(c = pending, c+1)); + new SearchMappingsTask(this, b >>>= 1, true, + searchFunction, result).fork(); + } + Object v; U u; + while (result.get() == null && (v = advance()) != null) { + if ((u = searchFunction.apply((K)nextKey, (V)v)) != null) { + result.compareAndSet(null, u); + break; + } + } + tryComplete(); + } + public final U getRawResult() { return result.get(); } + } + + static final class ReduceKeysTask + extends BulkTask { + final BiFun reducer; + K result; + ReduceKeysTask sibling; + ReduceKeysTask + (ConcurrentHashMapV8 m, + BiFun reducer) { + super(m); + this.reducer = reducer; + } + ReduceKeysTask + (BulkTask p, int b, boolean split, + BiFun reducer) { + super(p, b, split); + this.reducer = reducer; + } + + public final void compute() { + ReduceKeysTask t = this; + final BiFun reducer = + this.reducer; + if (reducer == null) + throw new Error(NullFunctionMessage); + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + ReduceKeysTask rt = + new ReduceKeysTask + (t, b, true, reducer); + t = new ReduceKeysTask + (t, b, false, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + K r = null; + while (t.advance() != null) { + K u = (K)t.nextKey; + r = (r == null) ? u : reducer.apply(r, u); + } + t.result = r; + for (;;) { + int c; BulkTask par; ReduceKeysTask s, p; K u; + if ((par = t.parent) == null || + !(par instanceof ReduceKeysTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (ReduceKeysTask)par).pending) == 0) { + if ((s = t.sibling) != null && (u = s.result) != null) + r = (r == null) ? u : reducer.apply(r, u); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final K getRawResult() { return result; } + } + + static final class ReduceValuesTask + extends BulkTask { + final BiFun reducer; + V result; + ReduceValuesTask sibling; + ReduceValuesTask + (ConcurrentHashMapV8 m, + BiFun reducer) { + super(m); + this.reducer = reducer; + } + ReduceValuesTask + (BulkTask p, int b, boolean split, + BiFun reducer) { + super(p, b, split); + this.reducer = reducer; + } + + public final void compute() { + ReduceValuesTask t = this; + final BiFun reducer = + this.reducer; + if (reducer == null) + throw new Error(NullFunctionMessage); + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + ReduceValuesTask rt = + new ReduceValuesTask + (t, b, true, reducer); + t = new ReduceValuesTask + (t, b, false, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + V r = null; + Object v; + while ((v = t.advance()) != null) { + V u = (V)v; + r = (r == null) ? u : reducer.apply(r, u); + } + t.result = r; + for (;;) { + int c; BulkTask par; ReduceValuesTask s, p; V u; + if ((par = t.parent) == null || + !(par instanceof ReduceValuesTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (ReduceValuesTask)par).pending) == 0) { + if ((s = t.sibling) != null && (u = s.result) != null) + r = (r == null) ? u : reducer.apply(r, u); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final V getRawResult() { return result; } + } + + static final class ReduceEntriesTask + extends BulkTask> { + final BiFun, Map.Entry, ? extends Map.Entry> reducer; + Map.Entry result; + ReduceEntriesTask sibling; + ReduceEntriesTask + (ConcurrentHashMapV8 m, + BiFun, Map.Entry, ? extends Map.Entry> reducer) { + super(m); + this.reducer = reducer; + } + ReduceEntriesTask + (BulkTask p, int b, boolean split, + BiFun, Map.Entry, ? extends Map.Entry> reducer) { + super(p, b, split); + this.reducer = reducer; + } + + public final void compute() { + ReduceEntriesTask t = this; + final BiFun, Map.Entry, ? extends Map.Entry> reducer = + this.reducer; + if (reducer == null) + throw new Error(NullFunctionMessage); + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + ReduceEntriesTask rt = + new ReduceEntriesTask + (t, b, true, reducer); + t = new ReduceEntriesTask + (t, b, false, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + Map.Entry r = null; + Object v; + while ((v = t.advance()) != null) { + Map.Entry u = entryFor((K)t.nextKey, (V)v); + r = (r == null) ? u : reducer.apply(r, u); + } + t.result = r; + for (;;) { + int c; BulkTask par; ReduceEntriesTask s, p; + Map.Entry u; + if ((par = t.parent) == null || + !(par instanceof ReduceEntriesTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (ReduceEntriesTask)par).pending) == 0) { + if ((s = t.sibling) != null && (u = s.result) != null) + r = (r == null) ? u : reducer.apply(r, u); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Map.Entry getRawResult() { return result; } + } + + static final class MapReduceKeysTask + extends BulkTask { + final Fun transformer; + final BiFun reducer; + U result; + MapReduceKeysTask sibling; + MapReduceKeysTask + (ConcurrentHashMapV8 m, + Fun transformer, + BiFun reducer) { + super(m); + this.transformer = transformer; + this.reducer = reducer; + } + MapReduceKeysTask + (BulkTask p, int b, boolean split, + Fun transformer, + BiFun reducer) { + super(p, b, split); + this.transformer = transformer; + this.reducer = reducer; + } + public final void compute() { + MapReduceKeysTask t = this; + final Fun transformer = + this.transformer; + final BiFun reducer = + this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceKeysTask rt = + new MapReduceKeysTask + (t, b, true, transformer, reducer); + t = new MapReduceKeysTask + (t, b, false, transformer, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + U r = null, u; + while (t.advance() != null) { + if ((u = transformer.apply((K)t.nextKey)) != null) + r = (r == null) ? u : reducer.apply(r, u); + } + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceKeysTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceKeysTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceKeysTask)par).pending) == 0) { + if ((s = t.sibling) != null && (u = s.result) != null) + r = (r == null) ? u : reducer.apply(r, u); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final U getRawResult() { return result; } + } + + static final class MapReduceValuesTask + extends BulkTask { + final Fun transformer; + final BiFun reducer; + U result; + MapReduceValuesTask sibling; + MapReduceValuesTask + (ConcurrentHashMapV8 m, + Fun transformer, + BiFun reducer) { + super(m); + this.transformer = transformer; + this.reducer = reducer; + } + MapReduceValuesTask + (BulkTask p, int b, boolean split, + Fun transformer, + BiFun reducer) { + super(p, b, split); + this.transformer = transformer; + this.reducer = reducer; + } + public final void compute() { + MapReduceValuesTask t = this; + final Fun transformer = + this.transformer; + final BiFun reducer = + this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceValuesTask rt = + new MapReduceValuesTask + (t, b, true, transformer, reducer); + t = new MapReduceValuesTask + (t, b, false, transformer, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + U r = null, u; + Object v; + while ((v = t.advance()) != null) { + if ((u = transformer.apply((V)v)) != null) + r = (r == null) ? u : reducer.apply(r, u); + } + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceValuesTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceValuesTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceValuesTask)par).pending) == 0) { + if ((s = t.sibling) != null && (u = s.result) != null) + r = (r == null) ? u : reducer.apply(r, u); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final U getRawResult() { return result; } + } + + static final class MapReduceEntriesTask + extends BulkTask { + final Fun, ? extends U> transformer; + final BiFun reducer; + U result; + MapReduceEntriesTask sibling; + MapReduceEntriesTask + (ConcurrentHashMapV8 m, + Fun, ? extends U> transformer, + BiFun reducer) { + super(m); + this.transformer = transformer; + this.reducer = reducer; + } + MapReduceEntriesTask + (BulkTask p, int b, boolean split, + Fun, ? extends U> transformer, + BiFun reducer) { + super(p, b, split); + this.transformer = transformer; + this.reducer = reducer; + } + public final void compute() { + MapReduceEntriesTask t = this; + final Fun, ? extends U> transformer = + this.transformer; + final BiFun reducer = + this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceEntriesTask rt = + new MapReduceEntriesTask + (t, b, true, transformer, reducer); + t = new MapReduceEntriesTask + (t, b, false, transformer, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + U r = null, u; + Object v; + while ((v = t.advance()) != null) { + if ((u = transformer.apply(entryFor((K)t.nextKey, (V)v))) != null) + r = (r == null) ? u : reducer.apply(r, u); + } + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceEntriesTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceEntriesTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceEntriesTask)par).pending) == 0) { + if ((s = t.sibling) != null && (u = s.result) != null) + r = (r == null) ? u : reducer.apply(r, u); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final U getRawResult() { return result; } + } + + static final class MapReduceMappingsTask + extends BulkTask { + final BiFun transformer; + final BiFun reducer; + U result; + MapReduceMappingsTask sibling; + MapReduceMappingsTask + (ConcurrentHashMapV8 m, + BiFun transformer, + BiFun reducer) { + super(m); + this.transformer = transformer; + this.reducer = reducer; + } + MapReduceMappingsTask + (BulkTask p, int b, boolean split, + BiFun transformer, + BiFun reducer) { + super(p, b, split); + this.transformer = transformer; + this.reducer = reducer; + } + public final void compute() { + MapReduceMappingsTask t = this; + final BiFun transformer = + this.transformer; + final BiFun reducer = + this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceMappingsTask rt = + new MapReduceMappingsTask + (t, b, true, transformer, reducer); + t = new MapReduceMappingsTask + (t, b, false, transformer, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + U r = null, u; + Object v; + while ((v = t.advance()) != null) { + if ((u = transformer.apply((K)t.nextKey, (V)v)) != null) + r = (r == null) ? u : reducer.apply(r, u); + } + for (;;) { + int c; BulkTask par; MapReduceMappingsTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceMappingsTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceMappingsTask)par).pending) == 0) { + if ((s = t.sibling) != null && (u = s.result) != null) + r = (r == null) ? u : reducer.apply(r, u); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final U getRawResult() { return result; } + } + + static final class MapReduceKeysToDoubleTask + extends BulkTask { + final ObjectToDouble transformer; + final DoubleByDoubleToDouble reducer; + final double basis; + double result; + MapReduceKeysToDoubleTask sibling; + MapReduceKeysToDoubleTask + (ConcurrentHashMapV8 m, + ObjectToDouble transformer, + double basis, + DoubleByDoubleToDouble reducer) { + super(m); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + MapReduceKeysToDoubleTask + (BulkTask p, int b, boolean split, + ObjectToDouble transformer, + double basis, + DoubleByDoubleToDouble reducer) { + super(p, b, split); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + public final void compute() { + MapReduceKeysToDoubleTask t = this; + final ObjectToDouble transformer = + this.transformer; + final DoubleByDoubleToDouble reducer = this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + final double id = this.basis; + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceKeysToDoubleTask rt = + new MapReduceKeysToDoubleTask + (t, b, true, transformer, id, reducer); + t = new MapReduceKeysToDoubleTask + (t, b, false, transformer, id, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + double r = id; + while (t.advance() != null) + r = reducer.apply(r, transformer.apply((K)t.nextKey)); + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceKeysToDoubleTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceKeysToDoubleTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceKeysToDoubleTask)par).pending) == 0) { + if ((s = t.sibling) != null) + r = reducer.apply(r, s.result); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Double getRawResult() { return result; } + } + + static final class MapReduceValuesToDoubleTask + extends BulkTask { + final ObjectToDouble transformer; + final DoubleByDoubleToDouble reducer; + final double basis; + double result; + MapReduceValuesToDoubleTask sibling; + MapReduceValuesToDoubleTask + (ConcurrentHashMapV8 m, + ObjectToDouble transformer, + double basis, + DoubleByDoubleToDouble reducer) { + super(m); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + MapReduceValuesToDoubleTask + (BulkTask p, int b, boolean split, + ObjectToDouble transformer, + double basis, + DoubleByDoubleToDouble reducer) { + super(p, b, split); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + public final void compute() { + MapReduceValuesToDoubleTask t = this; + final ObjectToDouble transformer = + this.transformer; + final DoubleByDoubleToDouble reducer = this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + final double id = this.basis; + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceValuesToDoubleTask rt = + new MapReduceValuesToDoubleTask + (t, b, true, transformer, id, reducer); + t = new MapReduceValuesToDoubleTask + (t, b, false, transformer, id, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + double r = id; + Object v; + while ((v = t.advance()) != null) + r = reducer.apply(r, transformer.apply((V)v)); + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceValuesToDoubleTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceValuesToDoubleTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceValuesToDoubleTask)par).pending) == 0) { + if ((s = t.sibling) != null) + r = reducer.apply(r, s.result); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Double getRawResult() { return result; } + } + + static final class MapReduceEntriesToDoubleTask + extends BulkTask { + final ObjectToDouble> transformer; + final DoubleByDoubleToDouble reducer; + final double basis; + double result; + MapReduceEntriesToDoubleTask sibling; + MapReduceEntriesToDoubleTask + (ConcurrentHashMapV8 m, + ObjectToDouble> transformer, + double basis, + DoubleByDoubleToDouble reducer) { + super(m); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + MapReduceEntriesToDoubleTask + (BulkTask p, int b, boolean split, + ObjectToDouble> transformer, + double basis, + DoubleByDoubleToDouble reducer) { + super(p, b, split); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + public final void compute() { + MapReduceEntriesToDoubleTask t = this; + final ObjectToDouble> transformer = + this.transformer; + final DoubleByDoubleToDouble reducer = this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + final double id = this.basis; + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceEntriesToDoubleTask rt = + new MapReduceEntriesToDoubleTask + (t, b, true, transformer, id, reducer); + t = new MapReduceEntriesToDoubleTask + (t, b, false, transformer, id, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + double r = id; + Object v; + while ((v = t.advance()) != null) + r = reducer.apply(r, transformer.apply(entryFor((K)t.nextKey, (V)v))); + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceEntriesToDoubleTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceEntriesToDoubleTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceEntriesToDoubleTask)par).pending) == 0) { + if ((s = t.sibling) != null) + r = reducer.apply(r, s.result); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Double getRawResult() { return result; } + } + + static final class MapReduceMappingsToDoubleTask + extends BulkTask { + final ObjectByObjectToDouble transformer; + final DoubleByDoubleToDouble reducer; + final double basis; + double result; + MapReduceMappingsToDoubleTask sibling; + MapReduceMappingsToDoubleTask + (ConcurrentHashMapV8 m, + ObjectByObjectToDouble transformer, + double basis, + DoubleByDoubleToDouble reducer) { + super(m); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + MapReduceMappingsToDoubleTask + (BulkTask p, int b, boolean split, + ObjectByObjectToDouble transformer, + double basis, + DoubleByDoubleToDouble reducer) { + super(p, b, split); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + public final void compute() { + MapReduceMappingsToDoubleTask t = this; + final ObjectByObjectToDouble transformer = + this.transformer; + final DoubleByDoubleToDouble reducer = this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + final double id = this.basis; + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceMappingsToDoubleTask rt = + new MapReduceMappingsToDoubleTask + (t, b, true, transformer, id, reducer); + t = new MapReduceMappingsToDoubleTask + (t, b, false, transformer, id, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + double r = id; + Object v; + while ((v = t.advance()) != null) + r = reducer.apply(r, transformer.apply((K)t.nextKey, (V)v)); + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceMappingsToDoubleTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceMappingsToDoubleTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceMappingsToDoubleTask)par).pending) == 0) { + if ((s = t.sibling) != null) + r = reducer.apply(r, s.result); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Double getRawResult() { return result; } + } + + static final class MapReduceKeysToLongTask + extends BulkTask { + final ObjectToLong transformer; + final LongByLongToLong reducer; + final long basis; + long result; + MapReduceKeysToLongTask sibling; + MapReduceKeysToLongTask + (ConcurrentHashMapV8 m, + ObjectToLong transformer, + long basis, + LongByLongToLong reducer) { + super(m); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + MapReduceKeysToLongTask + (BulkTask p, int b, boolean split, + ObjectToLong transformer, + long basis, + LongByLongToLong reducer) { + super(p, b, split); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + public final void compute() { + MapReduceKeysToLongTask t = this; + final ObjectToLong transformer = + this.transformer; + final LongByLongToLong reducer = this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + final long id = this.basis; + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceKeysToLongTask rt = + new MapReduceKeysToLongTask + (t, b, true, transformer, id, reducer); + t = new MapReduceKeysToLongTask + (t, b, false, transformer, id, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + long r = id; + while (t.advance() != null) + r = reducer.apply(r, transformer.apply((K)t.nextKey)); + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceKeysToLongTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceKeysToLongTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceKeysToLongTask)par).pending) == 0) { + if ((s = t.sibling) != null) + r = reducer.apply(r, s.result); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Long getRawResult() { return result; } + } + + static final class MapReduceValuesToLongTask + extends BulkTask { + final ObjectToLong transformer; + final LongByLongToLong reducer; + final long basis; + long result; + MapReduceValuesToLongTask sibling; + MapReduceValuesToLongTask + (ConcurrentHashMapV8 m, + ObjectToLong transformer, + long basis, + LongByLongToLong reducer) { + super(m); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + MapReduceValuesToLongTask + (BulkTask p, int b, boolean split, + ObjectToLong transformer, + long basis, + LongByLongToLong reducer) { + super(p, b, split); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + public final void compute() { + MapReduceValuesToLongTask t = this; + final ObjectToLong transformer = + this.transformer; + final LongByLongToLong reducer = this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + final long id = this.basis; + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceValuesToLongTask rt = + new MapReduceValuesToLongTask + (t, b, true, transformer, id, reducer); + t = new MapReduceValuesToLongTask + (t, b, false, transformer, id, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + long r = id; + Object v; + while ((v = t.advance()) != null) + r = reducer.apply(r, transformer.apply((V)v)); + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceValuesToLongTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceValuesToLongTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceValuesToLongTask)par).pending) == 0) { + if ((s = t.sibling) != null) + r = reducer.apply(r, s.result); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Long getRawResult() { return result; } + } + + static final class MapReduceEntriesToLongTask + extends BulkTask { + final ObjectToLong> transformer; + final LongByLongToLong reducer; + final long basis; + long result; + MapReduceEntriesToLongTask sibling; + MapReduceEntriesToLongTask + (ConcurrentHashMapV8 m, + ObjectToLong> transformer, + long basis, + LongByLongToLong reducer) { + super(m); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + MapReduceEntriesToLongTask + (BulkTask p, int b, boolean split, + ObjectToLong> transformer, + long basis, + LongByLongToLong reducer) { + super(p, b, split); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + public final void compute() { + MapReduceEntriesToLongTask t = this; + final ObjectToLong> transformer = + this.transformer; + final LongByLongToLong reducer = this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + final long id = this.basis; + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceEntriesToLongTask rt = + new MapReduceEntriesToLongTask + (t, b, true, transformer, id, reducer); + t = new MapReduceEntriesToLongTask + (t, b, false, transformer, id, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + long r = id; + Object v; + while ((v = t.advance()) != null) + r = reducer.apply(r, transformer.apply(entryFor((K)t.nextKey, (V)v))); + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceEntriesToLongTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceEntriesToLongTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceEntriesToLongTask)par).pending) == 0) { + if ((s = t.sibling) != null) + r = reducer.apply(r, s.result); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Long getRawResult() { return result; } + } + + static final class MapReduceMappingsToLongTask + extends BulkTask { + final ObjectByObjectToLong transformer; + final LongByLongToLong reducer; + final long basis; + long result; + MapReduceMappingsToLongTask sibling; + MapReduceMappingsToLongTask + (ConcurrentHashMapV8 m, + ObjectByObjectToLong transformer, + long basis, + LongByLongToLong reducer) { + super(m); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + MapReduceMappingsToLongTask + (BulkTask p, int b, boolean split, + ObjectByObjectToLong transformer, + long basis, + LongByLongToLong reducer) { + super(p, b, split); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + public final void compute() { + MapReduceMappingsToLongTask t = this; + final ObjectByObjectToLong transformer = + this.transformer; + final LongByLongToLong reducer = this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + final long id = this.basis; + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceMappingsToLongTask rt = + new MapReduceMappingsToLongTask + (t, b, true, transformer, id, reducer); + t = new MapReduceMappingsToLongTask + (t, b, false, transformer, id, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + long r = id; + Object v; + while ((v = t.advance()) != null) + r = reducer.apply(r, transformer.apply((K)t.nextKey, (V)v)); + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceMappingsToLongTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceMappingsToLongTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceMappingsToLongTask)par).pending) == 0) { + if ((s = t.sibling) != null) + r = reducer.apply(r, s.result); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Long getRawResult() { return result; } + } + + static final class MapReduceKeysToIntTask + extends BulkTask { + final ObjectToInt transformer; + final IntByIntToInt reducer; + final int basis; + int result; + MapReduceKeysToIntTask sibling; + MapReduceKeysToIntTask + (ConcurrentHashMapV8 m, + ObjectToInt transformer, + int basis, + IntByIntToInt reducer) { + super(m); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + MapReduceKeysToIntTask + (BulkTask p, int b, boolean split, + ObjectToInt transformer, + int basis, + IntByIntToInt reducer) { + super(p, b, split); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + public final void compute() { + MapReduceKeysToIntTask t = this; + final ObjectToInt transformer = + this.transformer; + final IntByIntToInt reducer = this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + final int id = this.basis; + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceKeysToIntTask rt = + new MapReduceKeysToIntTask + (t, b, true, transformer, id, reducer); + t = new MapReduceKeysToIntTask + (t, b, false, transformer, id, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + int r = id; + while (t.advance() != null) + r = reducer.apply(r, transformer.apply((K)t.nextKey)); + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceKeysToIntTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceKeysToIntTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceKeysToIntTask)par).pending) == 0) { + if ((s = t.sibling) != null) + r = reducer.apply(r, s.result); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Integer getRawResult() { return result; } + } + + static final class MapReduceValuesToIntTask + extends BulkTask { + final ObjectToInt transformer; + final IntByIntToInt reducer; + final int basis; + int result; + MapReduceValuesToIntTask sibling; + MapReduceValuesToIntTask + (ConcurrentHashMapV8 m, + ObjectToInt transformer, + int basis, + IntByIntToInt reducer) { + super(m); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + MapReduceValuesToIntTask + (BulkTask p, int b, boolean split, + ObjectToInt transformer, + int basis, + IntByIntToInt reducer) { + super(p, b, split); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + public final void compute() { + MapReduceValuesToIntTask t = this; + final ObjectToInt transformer = + this.transformer; + final IntByIntToInt reducer = this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + final int id = this.basis; + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceValuesToIntTask rt = + new MapReduceValuesToIntTask + (t, b, true, transformer, id, reducer); + t = new MapReduceValuesToIntTask + (t, b, false, transformer, id, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + int r = id; + Object v; + while ((v = t.advance()) != null) + r = reducer.apply(r, transformer.apply((V)v)); + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceValuesToIntTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceValuesToIntTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceValuesToIntTask)par).pending) == 0) { + if ((s = t.sibling) != null) + r = reducer.apply(r, s.result); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Integer getRawResult() { return result; } + } + + static final class MapReduceEntriesToIntTask + extends BulkTask { + final ObjectToInt> transformer; + final IntByIntToInt reducer; + final int basis; + int result; + MapReduceEntriesToIntTask sibling; + MapReduceEntriesToIntTask + (ConcurrentHashMapV8 m, + ObjectToInt> transformer, + int basis, + IntByIntToInt reducer) { + super(m); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + MapReduceEntriesToIntTask + (BulkTask p, int b, boolean split, + ObjectToInt> transformer, + int basis, + IntByIntToInt reducer) { + super(p, b, split); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + public final void compute() { + MapReduceEntriesToIntTask t = this; + final ObjectToInt> transformer = + this.transformer; + final IntByIntToInt reducer = this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + final int id = this.basis; + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceEntriesToIntTask rt = + new MapReduceEntriesToIntTask + (t, b, true, transformer, id, reducer); + t = new MapReduceEntriesToIntTask + (t, b, false, transformer, id, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + int r = id; + Object v; + while ((v = t.advance()) != null) + r = reducer.apply(r, transformer.apply(entryFor((K)t.nextKey, (V)v))); + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceEntriesToIntTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceEntriesToIntTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceEntriesToIntTask)par).pending) == 0) { + if ((s = t.sibling) != null) + r = reducer.apply(r, s.result); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Integer getRawResult() { return result; } + } + + static final class MapReduceMappingsToIntTask + extends BulkTask { + final ObjectByObjectToInt transformer; + final IntByIntToInt reducer; + final int basis; + int result; + MapReduceMappingsToIntTask sibling; + MapReduceMappingsToIntTask + (ConcurrentHashMapV8 m, + ObjectByObjectToInt transformer, + int basis, + IntByIntToInt reducer) { + super(m); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + MapReduceMappingsToIntTask + (BulkTask p, int b, boolean split, + ObjectByObjectToInt transformer, + int basis, + IntByIntToInt reducer) { + super(p, b, split); + this.transformer = transformer; + this.basis = basis; this.reducer = reducer; + } + public final void compute() { + MapReduceMappingsToIntTask t = this; + final ObjectByObjectToInt transformer = + this.transformer; + final IntByIntToInt reducer = this.reducer; + if (transformer == null || reducer == null) + throw new Error(NullFunctionMessage); + final int id = this.basis; + int b = batch(); + while (b > 1 && t.baseIndex != t.baseLimit) { + b >>>= 1; + t.pending = 1; + MapReduceMappingsToIntTask rt = + new MapReduceMappingsToIntTask + (t, b, true, transformer, id, reducer); + t = new MapReduceMappingsToIntTask + (t, b, false, transformer, id, reducer); + t.sibling = rt; + rt.sibling = t; + rt.fork(); + } + int r = id; + Object v; + while ((v = t.advance()) != null) + r = reducer.apply(r, transformer.apply((K)t.nextKey, (V)v)); + t.result = r; + for (;;) { + int c; BulkTask par; MapReduceMappingsToIntTask s, p; + if ((par = t.parent) == null || + !(par instanceof MapReduceMappingsToIntTask)) { + t.quietlyComplete(); + break; + } + else if ((c = (p = (MapReduceMappingsToIntTask)par).pending) == 0) { + if ((s = t.sibling) != null) + r = reducer.apply(r, s.result); + (t = p).result = r; + } + else if (p.casPending(c, 0)) + break; + } + } + public final Integer getRawResult() { return result; } + } + + // Unsafe mechanics private static final sun.misc.Unsafe UNSAFE; private static final long counterOffset; @@ -3348,5 +6758,4 @@ public class ConcurrentHashMapV8 } } } - }