forEach: Perform a given action on each element.
@@ -189,13 +189,13 @@ import java.io.Serializable;
* exceptions, or would have done so if the first exception had
* not occurred.
*
- * Parallel speedups for bulk operations 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.
+ *
Speedups for parallel compared to sequential forms are common
+ * but not guaranteed. Parallel operations involving brief functions
+ * on small maps may execute more slowly than sequential forms 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.
*
@@ -295,15 +295,15 @@ public class ConcurrentHashMapV8
* the same or better than java.util.HashMap, and to support high
* initial insertion rates on an empty table by many threads.
*
- * Each key-value mapping is held in a Node. Because Node fields
- * can contain special values, they are defined using plain Object
- * types. Similarly in turn, all internal methods that use them
- * work off Object types. And similarly, so do the internal
- * methods of auxiliary iterator and view classes. This also
- * allows many of the public methods to be factored into a smaller
- * number of internal methods (although sadly not so for the five
- * variants of put-related operations). The validation-based
- * approach explained below leads to a lot of code sprawl because
+ * Each key-value mapping is held in a Node. Because Node key
+ * fields can contain special values, they are defined using plain
+ * Object types (not type "K"). This leads to a lot of explicit
+ * casting (and many explicit warning suppressions to tell
+ * compilers not to complain about it). It also allows some of the
+ * public methods to be factored into a smaller number of internal
+ * methods (although sadly not so for the five variants of
+ * put-related operations). The validation-based approach
+ * explained below leads to a lot of code sprawl because
* retry-control precludes factoring into smaller methods.
*
* The table is lazily initialized to a power-of-two size upon the
@@ -578,12 +578,12 @@ public class ConcurrentHashMapV8
* The array of bins. Lazily initialized upon first insertion.
* Size is always a power of two. Accessed directly by iterators.
*/
- transient volatile Node[] table;
+ transient volatile Node[] table;
/**
* The next table to use; non-null only while resizing.
*/
- private transient volatile Node[] nextTable;
+ private transient volatile Node[] nextTable;
/**
* Base counter value, used mainly when there is no contention,
@@ -644,15 +644,18 @@ public class ConcurrentHashMapV8
* inline assignments below.
*/
- static final Node tabAt(Node[] tab, int i) { // used by Traverser
- return (Node)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
+ @SuppressWarnings("unchecked") static final Node tabAt
+ (Node[] tab, int i) { // used by Traverser
+ return (Node)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
}
- private static final boolean casTabAt(Node[] tab, int i, Node c, Node v) {
+ private static final boolean casTabAt
+ (Node[] tab, int i, Node c, Node v) {
return U.compareAndSwapObject(tab, ((long)i << ASHIFT) + ABASE, c, v);
}
- private static final void setTabAt(Node[] tab, int i, Node v) {
+ private static final void setTabAt
+ (Node[] tab, int i, Node v) {
U.putObjectVolatile(tab, ((long)i << ASHIFT) + ABASE, v);
}
@@ -668,13 +671,13 @@ public class ConcurrentHashMapV8
* before a val, but can only be used after checking val to be
* non-null.
*/
- static class Node {
+ static class Node {
final int hash;
final Object key;
- volatile Object val;
- volatile Node next;
+ volatile V val;
+ volatile Node next;
- Node(int hash, Object key, Object val, Node next) {
+ Node(int hash, Object key, V val, Node next) {
this.hash = hash;
this.key = key;
this.val = val;
@@ -687,14 +690,14 @@ public class ConcurrentHashMapV8
/**
* Nodes for use in TreeBins
*/
- static final class TreeNode extends Node {
- TreeNode parent; // red-black tree links
- TreeNode left;
- TreeNode right;
- TreeNode prev; // needed to unlink next upon deletion
+ static final class TreeNode extends Node {
+ TreeNode parent; // red-black tree links
+ TreeNode left;
+ TreeNode right;
+ TreeNode prev; // needed to unlink next upon deletion
boolean red;
- TreeNode(int hash, Object key, Object val, Node next, TreeNode parent) {
+ TreeNode(int hash, Object key, V val, Node next, TreeNode parent) {
super(hash, key, val, next);
this.parent = parent;
}
@@ -743,10 +746,10 @@ public class ConcurrentHashMapV8
* and writers. Since we don't need to export full Lock API, we
* just override the minimal AQS methods and use them directly.
*/
- static final class TreeBin extends AbstractQueuedSynchronizer {
+ static final class TreeBin extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 2249069246763182397L;
- transient TreeNode root; // root of tree
- transient TreeNode first; // head of next-pointer list
+ transient TreeNode root; // root of tree
+ transient TreeNode first; // head of next-pointer list
/* AQS overrides */
public final boolean isHeldExclusively() { return getState() > 0; }
@@ -777,9 +780,9 @@ public class ConcurrentHashMapV8
}
/** From CLR */
- private void rotateLeft(TreeNode p) {
+ private void rotateLeft(TreeNode p) {
if (p != null) {
- TreeNode r = p.right, pp, rl;
+ TreeNode r = p.right, pp, rl;
if ((rl = p.right = r.left) != null)
rl.parent = p;
if ((pp = r.parent = p.parent) == null)
@@ -794,9 +797,9 @@ public class ConcurrentHashMapV8
}
/** From CLR */
- private void rotateRight(TreeNode p) {
+ private void rotateRight(TreeNode p) {
if (p != null) {
- TreeNode l = p.left, pp, lr;
+ TreeNode l = p.left, pp, lr;
if ((lr = p.left = l.right) != null)
lr.parent = p;
if ((pp = l.parent = p.parent) == null)
@@ -814,8 +817,8 @@ public class ConcurrentHashMapV8
* Returns the TreeNode (or null if not found) for the given key
* starting at given root.
*/
- @SuppressWarnings("unchecked") final TreeNode getTreeNode
- (int h, Object k, TreeNode p) {
+ @SuppressWarnings("unchecked") final TreeNode getTreeNode
+ (int h, Object k, TreeNode p) {
Class> c = k.getClass();
while (p != null) {
int dir, ph; Object pk; Class> pc;
@@ -827,7 +830,7 @@ public class ConcurrentHashMapV8
(dir = ((Comparable)k).compareTo((Comparable)pk)) == 0) {
if ((dir = (c == pc) ? 0 :
c.getName().compareTo(pc.getName())) == 0) {
- TreeNode r = null, pl, pr; // check both sides
+ TreeNode r = null, pl, pr; // check both sides
if ((pr = p.right) != null && h >= pr.hash &&
(r = getTreeNode(h, k, pr)) != null)
return r;
@@ -850,10 +853,10 @@ public class ConcurrentHashMapV8
* read-lock to call getTreeNode, but during failure to get
* lock, searches along next links.
*/
- final Object getValue(int h, Object k) {
- Node r = null;
+ final V getValue(int h, Object k) {
+ Node r = null;
int c = getState(); // Must read lock state first
- for (Node e = first; e != null; e = e.next) {
+ for (Node e = first; e != null; e = e.next) {
if (c <= 0 && compareAndSetState(c, c - 1)) {
try {
r = getTreeNode(h, k, root);
@@ -876,10 +879,10 @@ public class ConcurrentHashMapV8
* Finds or adds a node.
* @return null if added
*/
- @SuppressWarnings("unchecked") final TreeNode putTreeNode
- (int h, Object k, Object v) {
+ @SuppressWarnings("unchecked") final TreeNode putTreeNode
+ (int h, Object k, V v) {
Class> c = k.getClass();
- TreeNode pp = root, p = null;
+ TreeNode pp = root, p = null;
int dir = 0;
while (pp != null) { // find existing node or leaf to insert at
int ph; Object pk; Class> pc;
@@ -890,7 +893,7 @@ public class ConcurrentHashMapV8
if (c != (pc = pk.getClass()) ||
!(k instanceof Comparable) ||
(dir = ((Comparable)k).compareTo((Comparable)pk)) == 0) {
- TreeNode s = null, r = null, pr;
+ TreeNode s = null, r = null, pr;
if ((dir = (c == pc) ? 0 :
c.getName().compareTo(pc.getName())) == 0) {
if ((pr = p.right) != null && h >= pr.hash &&
@@ -910,12 +913,12 @@ public class ConcurrentHashMapV8
pp = (dir > 0) ? p.right : p.left;
}
- TreeNode f = first;
- TreeNode x = first = new TreeNode(h, k, v, f, p);
+ TreeNode f = first;
+ TreeNode x = first = new TreeNode(h, k, v, f, p);
if (p == null)
root = x;
else { // attach and rebalance; adapted from CLR
- TreeNode xp, xpp;
+ TreeNode xp, xpp;
if (f != null)
f.prev = x;
if (dir <= 0)
@@ -925,9 +928,9 @@ public class ConcurrentHashMapV8
x.red = true;
while (x != null && (xp = x.parent) != null && xp.red &&
(xpp = xp.parent) != null) {
- TreeNode xppl = xpp.left;
+ TreeNode xppl = xpp.left;
if (xp == xppl) {
- TreeNode y = xpp.right;
+ TreeNode y = xpp.right;
if (y != null && y.red) {
y.red = false;
xp.red = false;
@@ -949,7 +952,7 @@ public class ConcurrentHashMapV8
}
}
else {
- TreeNode y = xppl;
+ TreeNode y = xppl;
if (y != null && y.red) {
y.red = false;
xp.red = false;
@@ -971,7 +974,7 @@ public class ConcurrentHashMapV8
}
}
}
- TreeNode r = root;
+ TreeNode r = root;
if (r != null && r.red)
r.red = false;
}
@@ -986,31 +989,31 @@ public class ConcurrentHashMapV8
* that are accessible independently of lock. So instead we
* swap the tree linkages.
*/
- final void deleteTreeNode(TreeNode p) {
- TreeNode next = (TreeNode)p.next; // unlink traversal pointers
- TreeNode pred = p.prev;
+ final void deleteTreeNode(TreeNode p) {
+ TreeNode next = (TreeNode)p.next; // unlink traversal pointers
+ TreeNode pred = p.prev;
if (pred == null)
first = next;
else
pred.next = next;
if (next != null)
next.prev = pred;
- TreeNode replacement;
- TreeNode pl = p.left;
- TreeNode pr = p.right;
+ TreeNode replacement;
+ TreeNode pl = p.left;
+ TreeNode pr = p.right;
if (pl != null && pr != null) {
- TreeNode s = pr, sl;
+ TreeNode s = pr, sl;
while ((sl = s.left) != null) // find successor
s = sl;
boolean c = s.red; s.red = p.red; p.red = c; // swap colors
- TreeNode sr = s.right;
- TreeNode pp = p.parent;
+ TreeNode sr = s.right;
+ TreeNode pp = p.parent;
if (s == pr) { // p was s's direct parent
p.parent = s;
s.right = p;
}
else {
- TreeNode sp = s.parent;
+ TreeNode sp = s.parent;
if ((p.parent = sp) != null) {
if (s == sp.left)
sp.left = p;
@@ -1035,7 +1038,7 @@ public class ConcurrentHashMapV8
}
else
replacement = (pl != null) ? pl : pr;
- TreeNode pp = p.parent;
+ TreeNode pp = p.parent;
if (replacement == null) {
if (pp == null) {
root = null;
@@ -1054,15 +1057,15 @@ public class ConcurrentHashMapV8
p.left = p.right = p.parent = null;
}
if (!p.red) { // rebalance, from CLR
- TreeNode x = replacement;
+ TreeNode x = replacement;
while (x != null) {
- TreeNode xp, xpl;
+ TreeNode xp, xpl;
if (x.red || (xp = x.parent) == null) {
x.red = false;
break;
}
if (x == (xpl = xp.left)) {
- TreeNode sib = xp.right;
+ TreeNode sib = xp.right;
if (sib != null && sib.red) {
sib.red = false;
xp.red = true;
@@ -1072,7 +1075,7 @@ public class ConcurrentHashMapV8
if (sib == null)
x = xp;
else {
- TreeNode sl = sib.left, sr = sib.right;
+ TreeNode sl = sib.left, sr = sib.right;
if ((sr == null || !sr.red) &&
(sl == null || !sl.red)) {
sib.red = true;
@@ -1101,7 +1104,7 @@ public class ConcurrentHashMapV8
}
}
else { // symmetric
- TreeNode sib = xpl;
+ TreeNode sib = xpl;
if (sib != null && sib.red) {
sib.red = false;
xp.red = true;
@@ -1111,7 +1114,7 @@ public class ConcurrentHashMapV8
if (sib == null)
x = xp;
else {
- TreeNode sl = sib.left, sr = sib.right;
+ TreeNode sl = sib.left, sr = sib.right;
if ((sl == null || !sl.red) &&
(sr == null || !sr.red)) {
sib.red = true;
@@ -1175,12 +1178,12 @@ public class ConcurrentHashMapV8
* Replaces a list bin with a tree bin if key is comparable. Call
* only when locked.
*/
- private final void replaceWithTreeBin(Node[] tab, int index, Object key) {
+ private final void replaceWithTreeBin(Node[] tab, int index, Object key) {
if (key instanceof Comparable) {
- TreeBin t = new TreeBin();
- for (Node e = tabAt(tab, index); e != null; e = e.next)
+ TreeBin t = new TreeBin();
+ for (Node e = tabAt(tab, index); e != null; e = e.next)
t.putTreeNode(e.hash, e.key, e.val);
- setTabAt(tab, index, new Node(MOVED, t, null, null));
+ setTabAt(tab, index, new Node(MOVED, t, null, null));
}
}
@@ -1189,20 +1192,20 @@ public class ConcurrentHashMapV8
/** Implementation for get and containsKey */
@SuppressWarnings("unchecked") private final V internalGet(Object k) {
int h = spread(k.hashCode());
- retry: for (Node[] tab = table; tab != null;) {
- Node e; Object ek, ev; int eh; // locals to read fields once
+ retry: for (Node[] tab = table; tab != null;) {
+ Node e; Object ek; V ev; int eh; // locals to read fields once
for (e = tabAt(tab, (tab.length - 1) & h); e != null; e = e.next) {
if ((eh = e.hash) < 0) {
if ((ek = e.key) instanceof TreeBin) // search TreeBin
- return (V)((TreeBin)ek).getValue(h, k);
- else { // restart with new table
- tab = (Node[])ek;
+ return ((TreeBin)ek).getValue(h, k);
+ else { // restart with new table
+ tab = (Node[])ek;
continue retry;
}
}
else if (eh == h && (ev = e.val) != null &&
((ek = e.key) == k || k.equals(ek)))
- return (V)ev;
+ return ev;
}
break;
}
@@ -1217,24 +1220,24 @@ public class ConcurrentHashMapV8
@SuppressWarnings("unchecked") private final V internalReplace
(Object k, V v, Object cv) {
int h = spread(k.hashCode());
- Object oldVal = null;
- for (Node[] tab = table;;) {
- Node f; int i, fh; Object fk;
+ V oldVal = null;
+ for (Node[] tab = table;;) {
+ Node f; int i, fh; Object fk;
if (tab == null ||
(f = tabAt(tab, i = (tab.length - 1) & h)) == null)
break;
else if ((fh = f.hash) < 0) {
if ((fk = f.key) instanceof TreeBin) {
- TreeBin t = (TreeBin)fk;
+ TreeBin t = (TreeBin)fk;
boolean validated = false;
boolean deleted = false;
t.acquire(0);
try {
if (tabAt(tab, i) == f) {
validated = true;
- TreeNode p = t.getTreeNode(h, k, t.root);
+ TreeNode p = t.getTreeNode(h, k, t.root);
if (p != null) {
- Object pv = p.val;
+ V pv = p.val;
if (cv == null || cv == pv || cv.equals(pv)) {
oldVal = pv;
if ((p.val = v) == null) {
@@ -1254,7 +1257,7 @@ public class ConcurrentHashMapV8
}
}
else
- tab = (Node[])fk;
+ tab = (Node[])fk;
}
else if (fh != h && f.next == null) // precheck
break; // rules out possible existence
@@ -1264,8 +1267,8 @@ public class ConcurrentHashMapV8
synchronized (f) {
if (tabAt(tab, i) == f) {
validated = true;
- for (Node e = f, pred = null;;) {
- Object ek, ev;
+ for (Node e = f, pred = null;;) {
+ Object ek; V ev;
if (e.hash == h &&
((ev = e.val) != null) &&
((ek = e.key) == k || k.equals(ek))) {
@@ -1273,7 +1276,7 @@ public class ConcurrentHashMapV8
oldVal = ev;
if ((e.val = v) == null) {
deleted = true;
- Node en = e.next;
+ Node en = e.next;
if (pred != null)
pred.next = en;
else
@@ -1295,7 +1298,7 @@ public class ConcurrentHashMapV8
}
}
}
- return (V)oldVal;
+ return oldVal;
}
/*
@@ -1322,23 +1325,23 @@ public class ConcurrentHashMapV8
if (k == null || v == null) throw new NullPointerException();
int h = spread(k.hashCode());
int len = 0;
- for (Node[] tab = table;;) {
- int i, fh; Node f; Object fk, fv;
+ for (Node[] tab = table;;) {
+ int i, fh; Node f; Object fk; V 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)))
+ if (casTabAt(tab, i, null, new Node(h, k, v, null)))
break; // no lock when adding to empty bin
}
else if ((fh = f.hash) < 0) {
if ((fk = f.key) instanceof TreeBin) {
- TreeBin t = (TreeBin)fk;
- Object oldVal = null;
+ TreeBin t = (TreeBin)fk;
+ V oldVal = null;
t.acquire(0);
try {
if (tabAt(tab, i) == f) {
len = 2;
- TreeNode p = t.putTreeNode(h, k, v);
+ TreeNode p = t.putTreeNode(h, k, v);
if (p != null) {
oldVal = p.val;
if (!onlyIfAbsent)
@@ -1350,23 +1353,23 @@ public class ConcurrentHashMapV8
}
if (len != 0) {
if (oldVal != null)
- return (V)oldVal;
+ return oldVal;
break;
}
}
else
- tab = (Node[])fk;
+ tab = (Node[])fk;
}
else if (onlyIfAbsent && fh == h && (fv = f.val) != null &&
((fk = f.key) == k || k.equals(fk))) // peek while nearby
- return (V)fv;
+ return fv;
else {
- Object oldVal = null;
+ V oldVal = null;
synchronized (f) {
if (tabAt(tab, i) == f) {
len = 1;
- for (Node e = f;; ++len) {
- Object ek, ev;
+ for (Node e = f;; ++len) {
+ Object ek; V ev;
if (e.hash == h &&
(ev = e.val) != null &&
((ek = e.key) == k || k.equals(ek))) {
@@ -1375,9 +1378,9 @@ public class ConcurrentHashMapV8
e.val = v;
break;
}
- Node last = e;
+ Node last = e;
if ((e = e.next) == null) {
- last.next = new Node(h, k, v, null);
+ last.next = new Node(h, k, v, null);
if (len >= TREE_THRESHOLD)
replaceWithTreeBin(tab, i, k);
break;
@@ -1387,7 +1390,7 @@ public class ConcurrentHashMapV8
}
if (len != 0) {
if (oldVal != null)
- return (V)oldVal;
+ return oldVal;
break;
}
}
@@ -1398,18 +1401,18 @@ public class ConcurrentHashMapV8
/** Implementation for computeIfAbsent */
@SuppressWarnings("unchecked") private final V internalComputeIfAbsent
- (K k, Fun super K, ?> mf) {
+ (K k, Fun super K, ? extends V> mf) {
if (k == null || mf == null)
throw new NullPointerException();
int h = spread(k.hashCode());
- Object val = null;
+ V val = null;
int len = 0;
- for (Node[] tab = table;;) {
- Node f; int i; Object fk;
+ for (Node[] tab = table;;) {
+ Node f; int i; Object fk;
if (tab == null)
tab = initTable();
else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) {
- Node node = new Node(h, k, null, null);
+ Node node = new Node(h, k, null, null);
synchronized (node) {
if (casTabAt(tab, i, null, node)) {
len = 1;
@@ -1427,13 +1430,13 @@ public class ConcurrentHashMapV8
}
else if (f.hash < 0) {
if ((fk = f.key) instanceof TreeBin) {
- TreeBin t = (TreeBin)fk;
+ TreeBin t = (TreeBin)fk;
boolean added = false;
t.acquire(0);
try {
if (tabAt(tab, i) == f) {
len = 1;
- TreeNode p = t.getTreeNode(h, k, t.root);
+ TreeNode p = t.getTreeNode(h, k, t.root);
if (p != null)
val = p.val;
else if ((val = mf.apply(k)) != null) {
@@ -1447,37 +1450,37 @@ public class ConcurrentHashMapV8
}
if (len != 0) {
if (!added)
- return (V)val;
+ return val;
break;
}
}
else
- tab = (Node[])fk;
+ tab = (Node[])fk;
}
else {
- for (Node e = f; e != null; e = e.next) { // prescan
- Object ek, ev;
+ for (Node e = f; e != null; e = e.next) { // prescan
+ Object ek; V ev;
if (e.hash == h && (ev = e.val) != null &&
((ek = e.key) == k || k.equals(ek)))
- return (V)ev;
+ return ev;
}
boolean added = false;
synchronized (f) {
if (tabAt(tab, i) == f) {
len = 1;
- for (Node e = f;; ++len) {
- Object ek, ev;
+ for (Node e = f;; ++len) {
+ Object ek; V ev;
if (e.hash == h &&
(ev = e.val) != null &&
((ek = e.key) == k || k.equals(ek))) {
val = ev;
break;
}
- Node last = e;
+ Node last = e;
if ((e = e.next) == null) {
if ((val = mf.apply(k)) != null) {
added = true;
- last.next = new Node(h, k, val, null);
+ last.next = new Node(h, k, val, null);
if (len >= TREE_THRESHOLD)
replaceWithTreeBin(tab, i, k);
}
@@ -1488,14 +1491,14 @@ public class ConcurrentHashMapV8
}
if (len != 0) {
if (!added)
- return (V)val;
+ return val;
break;
}
}
}
if (val != null)
addCount(1L, len);
- return (V)val;
+ return val;
}
/** Implementation for compute */
@@ -1505,17 +1508,17 @@ public class ConcurrentHashMapV8
if (k == null || mf == null)
throw new NullPointerException();
int h = spread(k.hashCode());
- Object val = null;
+ V val = null;
int delta = 0;
int len = 0;
- for (Node[] tab = table;;) {
- Node f; int i, fh; Object fk;
+ for (Node[] tab = table;;) {
+ Node f; int i, fh; Object fk;
if (tab == null)
tab = initTable();
else if ((f = tabAt(tab, i = (tab.length - 1) & h)) == null) {
if (onlyIfPresent)
break;
- Node node = new Node(h, k, null, null);
+ Node node = new Node(h, k, null, null);
synchronized (node) {
if (casTabAt(tab, i, null, node)) {
try {
@@ -1535,16 +1538,16 @@ public class ConcurrentHashMapV8
}
else if ((fh = f.hash) < 0) {
if ((fk = f.key) instanceof TreeBin) {
- TreeBin t = (TreeBin)fk;
+ TreeBin t = (TreeBin)fk;
t.acquire(0);
try {
if (tabAt(tab, i) == f) {
len = 1;
- TreeNode p = t.getTreeNode(h, k, t.root);
+ TreeNode p = t.getTreeNode(h, k, t.root);
if (p == null && onlyIfPresent)
break;
- Object pv = (p == null) ? null : p.val;
- if ((val = mf.apply(k, (V)pv)) != null) {
+ V pv = (p == null) ? null : p.val;
+ if ((val = mf.apply(k, pv)) != null) {
if (p != null)
p.val = val;
else {
@@ -1565,23 +1568,23 @@ public class ConcurrentHashMapV8
break;
}
else
- tab = (Node[])fk;
+ tab = (Node[])fk;
}
else {
synchronized (f) {
if (tabAt(tab, i) == f) {
len = 1;
- for (Node e = f, pred = null;; ++len) {
- Object ek, ev;
+ for (Node e = f, pred = null;; ++len) {
+ Object ek; V ev;
if (e.hash == h &&
(ev = e.val) != null &&
((ek = e.key) == k || k.equals(ek))) {
- val = mf.apply(k, (V)ev);
+ val = mf.apply(k, ev);
if (val != null)
e.val = val;
else {
delta = -1;
- Node en = e.next;
+ Node en = e.next;
if (pred != null)
pred.next = en;
else
@@ -1593,7 +1596,7 @@ public class ConcurrentHashMapV8
if ((e = e.next) == null) {
if (!onlyIfPresent &&
(val = mf.apply(k, null)) != null) {
- pred.next = new Node(h, k, val, null);
+ pred.next = new Node(h, k, val, null);
delta = 1;
if (len >= TREE_THRESHOLD)
replaceWithTreeBin(tab, i, k);
@@ -1609,7 +1612,7 @@ public class ConcurrentHashMapV8
}
if (delta != 0)
addCount((long)delta, len);
- return (V)val;
+ return val;
}
/** Implementation for merge */
@@ -1618,15 +1621,15 @@ public class ConcurrentHashMapV8
if (k == null || v == null || mf == null)
throw new NullPointerException();
int h = spread(k.hashCode());
- Object val = null;
+ V val = null;
int delta = 0;
int len = 0;
- for (Node[] tab = table;;) {
- int i; Node f; Object fk, fv;
+ for (Node[] tab = table;;) {
+ int i; Node f; Object fk; V 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))) {
+ if (casTabAt(tab, i, null, new Node(h, k, v, null))) {
delta = 1;
val = v;
break;
@@ -1634,13 +1637,13 @@ public class ConcurrentHashMapV8
}
else if (f.hash < 0) {
if ((fk = f.key) instanceof TreeBin) {
- TreeBin t = (TreeBin)fk;
+ TreeBin t = (TreeBin)fk;
t.acquire(0);
try {
if (tabAt(tab, i) == f) {
len = 1;
- TreeNode p = t.getTreeNode(h, k, t.root);
- val = (p == null) ? v : mf.apply((V)p.val, v);
+ TreeNode p = t.getTreeNode(h, k, t.root);
+ val = (p == null) ? v : mf.apply(p.val, v);
if (val != null) {
if (p != null)
p.val = val;
@@ -1662,23 +1665,23 @@ public class ConcurrentHashMapV8
break;
}
else
- tab = (Node[])fk;
+ tab = (Node[])fk;
}
else {
synchronized (f) {
if (tabAt(tab, i) == f) {
len = 1;
- for (Node e = f, pred = null;; ++len) {
- Object ek, ev;
+ for (Node e = f, pred = null;; ++len) {
+ Object ek; V ev;
if (e.hash == h &&
(ev = e.val) != null &&
((ek = e.key) == k || k.equals(ek))) {
- val = mf.apply((V)ev, v);
+ val = mf.apply(ev, v);
if (val != null)
e.val = val;
else {
delta = -1;
- Node en = e.next;
+ Node en = e.next;
if (pred != null)
pred.next = en;
else
@@ -1689,7 +1692,7 @@ public class ConcurrentHashMapV8
pred = e;
if ((e = e.next) == null) {
val = v;
- pred.next = new Node(h, k, val, null);
+ pred.next = new Node(h, k, val, null);
delta = 1;
if (len >= TREE_THRESHOLD)
replaceWithTreeBin(tab, i, k);
@@ -1704,42 +1707,43 @@ public class ConcurrentHashMapV8
}
if (delta != 0)
addCount((long)delta, len);
- return (V)val;
+ return val;
}
/** Implementation for putAll */
- private final void internalPutAll(Map, ?> m) {
+ @SuppressWarnings("unchecked") private final void internalPutAll
+ (Map extends K, ? extends V> m) {
tryPresize(m.size());
long delta = 0L; // number of uncommitted additions
boolean npe = false; // to throw exception on exit for nulls
try { // to clean up counts on other exceptions
- for (Map.Entry, ?> entry : m.entrySet()) {
- Object k, v;
+ for (Map.Entry, ? extends V> entry : m.entrySet()) {
+ Object k; V v;
if (entry == null || (k = entry.getKey()) == null ||
(v = entry.getValue()) == null) {
npe = true;
break;
}
int h = spread(k.hashCode());
- for (Node[] tab = table;;) {
- int i; Node f; int fh; Object fk;
+ for (Node[] tab = table;;) {
+ int i; Node f; int fh; Object fk;
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))) {
+ if (casTabAt(tab, i, null, new Node(h, k, v, null))) {
++delta;
break;
}
}
else if ((fh = f.hash) < 0) {
if ((fk = f.key) instanceof TreeBin) {
- TreeBin t = (TreeBin)fk;
+ TreeBin t = (TreeBin)fk;
boolean validated = false;
t.acquire(0);
try {
if (tabAt(tab, i) == f) {
validated = true;
- TreeNode p = t.getTreeNode(h, k, t.root);
+ TreeNode p = t.getTreeNode(h, k, t.root);
if (p != null)
p.val = v;
else {
@@ -1754,25 +1758,25 @@ public class ConcurrentHashMapV8
break;
}
else
- tab = (Node[])fk;
+ tab = (Node[])fk;
}
else {
int len = 0;
synchronized (f) {
if (tabAt(tab, i) == f) {
len = 1;
- for (Node e = f;; ++len) {
- Object ek, ev;
+ for (Node e = f;; ++len) {
+ Object ek; V ev;
if (e.hash == h &&
(ev = e.val) != null &&
((ek = e.key) == k || k.equals(ek))) {
e.val = v;
break;
}
- Node last = e;
+ Node last = e;
if ((e = e.next) == null) {
++delta;
- last.next = new Node(h, k, v, null);
+ last.next = new Node(h, k, v, null);
if (len >= TREE_THRESHOLD)
replaceWithTreeBin(tab, i, k);
break;
@@ -1800,22 +1804,22 @@ public class ConcurrentHashMapV8
* Implementation for clear. Steps through each bin, removing all
* nodes.
*/
- private final void internalClear() {
+ @SuppressWarnings("unchecked") private final void internalClear() {
long delta = 0L; // negative number of deletions
int i = 0;
- Node[] tab = table;
+ Node[] tab = table;
while (tab != null && i < tab.length) {
- Node f = tabAt(tab, i);
+ Node f = tabAt(tab, i);
if (f == null)
++i;
else if (f.hash < 0) {
Object fk;
if ((fk = f.key) instanceof TreeBin) {
- TreeBin t = (TreeBin)fk;
+ TreeBin t = (TreeBin)fk;
t.acquire(0);
try {
if (tabAt(tab, i) == f) {
- for (Node p = t.first; p != null; p = p.next) {
+ for (Node p = t.first; p != null; p = p.next) {
if (p.val != null) { // (currently always true)
p.val = null;
--delta;
@@ -1830,12 +1834,12 @@ public class ConcurrentHashMapV8
}
}
else
- tab = (Node[])fk;
+ tab = (Node[])fk;
}
else {
synchronized (f) {
if (tabAt(tab, i) == f) {
- for (Node e = f; e != null; e = e.next) {
+ for (Node e = f; e != null; e = e.next) {
if (e.val != null) { // (currently always true)
e.val = null;
--delta;
@@ -1870,8 +1874,8 @@ public class ConcurrentHashMapV8
/**
* Initializes table, using the size recorded in sizeCtl.
*/
- private final Node[] initTable() {
- Node[] tab; int sc;
+ @SuppressWarnings("unchecked") private final Node[] initTable() {
+ Node[] tab; int sc;
while ((tab = table) == null) {
if ((sc = sizeCtl) < 0)
Thread.yield(); // lost initialization race; just spin
@@ -1879,7 +1883,8 @@ public class ConcurrentHashMapV8
try {
if ((tab = table) == null) {
int n = (sc > 0) ? sc : DEFAULT_CAPACITY;
- tab = table = new Node[n];
+ @SuppressWarnings("rawtypes") Node[] tb = new Node[n];
+ table = tab = (Node[])tb;
sc = n - (n >>> 2);
}
} finally {
@@ -1920,7 +1925,7 @@ public class ConcurrentHashMapV8
s = sumCount();
}
if (check >= 0) {
- Node[] tab, nt; int sc;
+ Node[] tab, nt; int sc;
while (s >= (long)(sc = sizeCtl) && (tab = table) != null &&
tab.length < MAXIMUM_CAPACITY) {
if (sc < 0) {
@@ -1942,18 +1947,19 @@ public class ConcurrentHashMapV8
*
* @param size number of elements (doesn't need to be perfectly accurate)
*/
- private final void tryPresize(int size) {
+ @SuppressWarnings("unchecked") private final void tryPresize(int size) {
int c = (size >= (MAXIMUM_CAPACITY >>> 1)) ? MAXIMUM_CAPACITY :
tableSizeFor(size + (size >>> 1) + 1);
int sc;
while ((sc = sizeCtl) >= 0) {
- Node[] tab = table; int n;
+ Node[] tab = table; int n;
if (tab == null || (n = tab.length) == 0) {
n = (sc > c) ? sc : c;
if (U.compareAndSwapInt(this, SIZECTL, sc, -1)) {
try {
if (table == tab) {
- table = new Node[n];
+ @SuppressWarnings("rawtypes") Node[] tb = new Node[n];
+ table = (Node[])tb;
sc = n - (n >>> 2);
}
} finally {
@@ -1973,13 +1979,15 @@ public class ConcurrentHashMapV8
* Moves and/or copies the nodes in each bin to new table. See
* above for explanation.
*/
- private final void transfer(Node[] tab, Node[] nextTab) {
+ @SuppressWarnings("unchecked") private final void transfer
+ (Node[] tab, Node[] nextTab) {
int n = tab.length, stride;
if ((stride = (NCPU > 1) ? (n >>> 3) / NCPU : n) < MIN_TRANSFER_STRIDE)
stride = MIN_TRANSFER_STRIDE; // subdivide range
if (nextTab == null) { // initiating
try {
- nextTab = new Node[n << 1];
+ @SuppressWarnings("rawtypes") Node[] tb = new Node[n << 1];
+ nextTab = (Node[])tb;
} catch (Throwable ex) { // try to cope with OOME
sizeCtl = Integer.MAX_VALUE;
return;
@@ -1987,7 +1995,7 @@ public class ConcurrentHashMapV8
nextTable = nextTab;
transferOrigin = n;
transferIndex = n;
- Node rev = new Node(MOVED, tab, null, null);
+ Node rev = new Node(MOVED, tab, null, null);
for (int k = n; k > 0;) { // progressively reveal ready slots
int nextk = (k > stride) ? k - stride : 0;
for (int m = nextk; m < k; ++m)
@@ -1998,10 +2006,10 @@ public class ConcurrentHashMapV8
}
}
int nextn = nextTab.length;
- Node fwd = new Node(MOVED, nextTab, null, null);
+ Node fwd = new Node(MOVED, nextTab, null, null);
boolean advance = true;
for (int i = 0, bound = 0;;) {
- int nextIndex, nextBound; Node f; Object fk;
+ int nextIndex, nextBound; Node f; Object fk;
while (advance) {
if (--i >= bound)
advance = false;
@@ -2041,8 +2049,8 @@ public class ConcurrentHashMapV8
synchronized (f) {
if (tabAt(tab, i) == f) {
int runBit = f.hash & n;
- Node lastRun = f, lo = null, hi = null;
- for (Node p = f.next; p != null; p = p.next) {
+ Node lastRun = f, lo = null, hi = null;
+ for (Node p = f.next; p != null; p = p.next) {
int b = p.hash & n;
if (b != runBit) {
runBit = b;
@@ -2053,13 +2061,13 @@ public class ConcurrentHashMapV8
lo = lastRun;
else
hi = lastRun;
- for (Node p = f; p != lastRun; p = p.next) {
+ for (Node p = f; p != lastRun; p = p.next) {
int ph = p.hash;
- Object pk = p.key, pv = p.val;
+ Object pk = p.key; V pv = p.val;
if ((ph & n) == 0)
- lo = new Node(ph, pk, pv, lo);
+ lo = new Node(ph, pk, pv, lo);
else
- hi = new Node(ph, pk, pv, hi);
+ hi = new Node(ph, pk, pv, hi);
}
setTabAt(nextTab, i, lo);
setTabAt(nextTab, i + n, hi);
@@ -2069,16 +2077,16 @@ public class ConcurrentHashMapV8
}
}
else if ((fk = f.key) instanceof TreeBin) {
- TreeBin t = (TreeBin)fk;
+ TreeBin t = (TreeBin)fk;
t.acquire(0);
try {
if (tabAt(tab, i) == f) {
- TreeBin lt = new TreeBin();
- TreeBin ht = new TreeBin();
+ TreeBin lt = new TreeBin();
+ TreeBin ht = new TreeBin();
int lc = 0, hc = 0;
- for (Node e = t.first; e != null; e = e.next) {
+ for (Node e = t.first; e != null; e = e.next) {
int h = e.hash;
- Object k = e.key, v = e.val;
+ Object k = e.key; V v = e.val;
if ((h & n) == 0) {
++lc;
lt.putTreeNode(h, k, v);
@@ -2088,22 +2096,22 @@ public class ConcurrentHashMapV8
ht.putTreeNode(h, k, v);
}
}
- Node ln, hn; // throw away trees if too small
+ Node ln, hn; // throw away trees if too small
if (lc < TREE_THRESHOLD) {
ln = null;
- for (Node p = lt.first; p != null; p = p.next)
- ln = new Node(p.hash, p.key, p.val, ln);
+ for (Node p = lt.first; p != null; p = p.next)
+ ln = new Node(p.hash, p.key, p.val, ln);
}
else
- ln = new Node(MOVED, lt, null, null);
+ ln = new Node(MOVED, lt, null, null);
setTabAt(nextTab, i, ln);
if (hc < TREE_THRESHOLD) {
hn = null;
- for (Node p = ht.first; p != null; p = p.next)
- hn = new Node(p.hash, p.key, p.val, hn);
+ for (Node p = ht.first; p != null; p = p.next)
+ hn = new Node(p.hash, p.key, p.val, hn);
}
else
- hn = new Node(MOVED, ht, null, null);
+ hn = new Node(MOVED, ht, null, null);
setTabAt(nextTab, i + n, hn);
setTabAt(tab, i, fwd);
advance = true;
@@ -2270,10 +2278,10 @@ public class ConcurrentHashMapV8
@SuppressWarnings("serial") static class Traverser
extends CountedCompleter {
final ConcurrentHashMapV8 map;
- Node next; // the next entry to use
+ Node next; // the next entry to use
Object nextKey; // cached key field of next
- Object nextVal; // cached val field of next
- Node[] tab; // current table; updated if resized
+ V nextVal; // cached val field of next
+ Node[] tab; // current table; updated if resized
int index; // index of bin to use next
int baseIndex; // current index of initial table
int baseLimit; // index bound for initial table
@@ -2290,7 +2298,7 @@ public class ConcurrentHashMapV8
super(it);
this.batch = batch;
if ((this.map = map) != null && it != null) { // split parent
- Node[] t;
+ Node[] t;
if ((t = it.tab) == null &&
(t = it.tab = map.table) != null)
it.baseLimit = it.baseSize = t.length;
@@ -2306,15 +2314,15 @@ public class ConcurrentHashMapV8
* Advances next; returns nextVal or null if terminated.
* See above for explanation.
*/
- final Object advance() {
- Node e = next;
- Object ev = null;
+ @SuppressWarnings("unchecked") final V advance() {
+ Node e = next;
+ V ev = null;
outer: do {
if (e != null) // advance past used/skipped node
e = e.next;
while (e == null) { // get to next non-null bin
ConcurrentHashMapV8 m;
- Node[] t; int b, i, n; Object ek; // checks must use locals
+ Node[] t; int b, i, n; Object ek; // must use locals
if ((t = tab) != null)
n = t.length;
else if ((m = map) != null && (t = tab = m.table) != null)
@@ -2326,9 +2334,9 @@ public class ConcurrentHashMapV8
break outer;
if ((e = tabAt(t, i)) != null && e.hash < 0) {
if ((ek = e.key) instanceof TreeBin)
- e = ((TreeBin)ek).first;
+ e = ((TreeBin)ek).first;
else {
- tab = (Node[])ek;
+ tab = (Node[])ek;
continue; // restarts due to null val
}
} // visit upper slots if present
@@ -2366,7 +2374,7 @@ public class ConcurrentHashMapV8