ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.32
Committed: Tue Feb 5 19:54:06 2013 UTC (11 years, 3 months ago) by jsr166
Branch: MAIN
Changes since 1.31: +8 -8 lines
Log Message:
javadoc style

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7 package extra166y;
8 import java.lang.ref.*;
9 import java.lang.reflect.*;
10 import java.io.*;
11 import java.util.*;
12 import java.util.concurrent.*;
13 import java.util.concurrent.locks.*;
14 import sun.misc.Unsafe;
15
16 /**
17 * A {@link java.util.ConcurrentMap} supporting user-defined
18 * equivalence comparisons, soft, weak, or strong keys and values, and
19 * user-supplied computational methods for setting and updating
20 * values. In particular: <ul>
21 *
22 * <li> Identity-based, Equality-based or User-definable {@link
23 * Equivalence}-based comparisons controlling membership.
24 *
25 * <li> {@linkplain SoftReference Soft}, {@linkplain
26 * WeakReference weak} or strong (regular) keys and values.
27 *
28 * <li> User-definable {@code MappingFunctions} that may be
29 * used in method {@link
30 * CustomConcurrentHashMap#computeIfAbsent} to atomically
31 * establish a computed value, along with
32 * {@code RemappingFunctions} that can be used in method
33 * {@link CustomConcurrentHashMap#compute} to atomically
34 * replace values.
35 *
36 * <li>Factory methods returning specialized forms for {@code int}
37 * keys and/or values, that may be more space-efficient
38 *
39 * </ul>
40 *
41 * Per-map settings are established in constructors, as in the
42 * following usages (that assume static imports to simplify expression
43 * of configuration parameters):
44 *
45 * <pre>
46 * {@code
47 * identityMap = new CustomConcurrentHashMap<Person,Salary>
48 * (STRONG, IDENTITY, STRONG, EQUALS, 0);
49 * weakKeyMap = new CustomConcurrentHashMap<Person,Salary>
50 * (WEAK, IDENTITY, STRONG, EQUALS, 0);
51 * .weakKeys());
52 * byNameMap = new CustomConcurrentHashMap<Person,Salary>
53 * (STRONG,
54 * new Equivalence<Person>() {
55 * public boolean equal(Person k, Object x) {
56 * return x instanceof Person && k.name.equals(((Person)x).name);
57 * }
58 * public int hash(Object x) {
59 * return (x instanceof Person) ? ((Person)x).name.hashCode() : 0;
60 * }
61 * },
62 * STRONG, EQUALS, 0);
63 * }
64 * </pre>
65 *
66 * The first usage above provides a replacement for {@link
67 * java.util.IdentityHashMap}, and the second a replacement for {@link
68 * java.util.WeakHashMap}, adding concurrency, asynchronous cleanup,
69 * and identity-based equality for keys. The third usage
70 * illustrates a map with a custom Equivalence that looks only at the
71 * name field of a (fictional) Person class.
72 *
73 * <p>This class also includes nested class {@link KeySet}
74 * that provides space-efficient Set views of maps, also supporting
75 * method {@code intern}, which may be of use in canonicalizing
76 * elements.
77 *
78 * <p>When used with (Weak or Soft) Reference keys and/or values,
79 * elements that have asynchronously become {@code null} are
80 * treated as absent from the map and (eventually) removed from maps
81 * via a background thread common across all maps. Because of the
82 * potential for asynchronous clearing of References, methods such as
83 * {@code containsValue} have weaker guarantees than you might
84 * expect even in the absence of other explicitly concurrent
85 * operations. For example {@code containsValue(value)} may
86 * return true even if {@code value} is no longer available upon
87 * return from the method.
88 *
89 * <p>When Equivalences other than equality are used, the returned
90 * collections may violate the specifications of {@code Map} and/or
91 * {@code Set} interfaces, which mandate the use of the
92 * {@code equals} method when comparing objects. The methods of this
93 * class otherwise have properties similar to those of {@link
94 * java.util.ConcurrentHashMap} under its default settings. To
95 * adaptively maintain semantics and performance under varying
96 * conditions, this class does <em>not</em> support load factor or
97 * concurrency level parameters. This class does not permit null keys
98 * or values. This class is serializable; however, serializing a map
99 * that uses soft or weak references can give unpredictable results.
100 * This class supports all optional operations of the {@code
101 * ConcurrentMap} interface. It supports have <i>weakly consistent
102 * iteration</i>: an iterator over one of the map's view collections
103 * may reflect some, all or none of the changes made to the collection
104 * after the iterator was created.
105 *
106 * <p>This class is a member of the
107 * <a href="{@docRoot}/../technotes/guides/collections/index.html">
108 * Java Collections Framework</a>.
109 *
110 * @param <K> the type of keys maintained by this map
111 * @param <V> the type of mapped values
112 */
113 public class CustomConcurrentHashMap<K, V> extends AbstractMap<K, V>
114 implements ConcurrentMap<K, V>, Serializable {
115 private static final long serialVersionUID = 7249069246764182397L;
116
117 /*
118 * This class uses a similar approach as ConcurrentHashMap, but
119 * makes different internal tradeoffs, mainly (1) We use more
120 * segments, but lazily initialize them; and (2) Links connecting
121 * nodes are not immutable, enabling unsplicing. These two
122 * adjustments help improve concurrency in the face of heavier
123 * per-element mechanics and the increased load due to reference
124 * removal, while still keeping footprint etc reasonable.
125 *
126 * Additionally, because Reference keys/values may become null
127 * asynchronously, we cannot ensure snapshot integrity in methods
128 * such as containsValue, so do not try to obtain them (so, no
129 * modCounts etc).
130 *
131 * Also, the volatility of Segment count vs table fields are
132 * swapped, enabled by ensuring fences on new node assignments.
133 */
134
135
136 /**
137 * The strength of keys and values that may be held by
138 * maps. strong denotes ordinary objects. weak and soft denote the
139 * corresponding {@link java.lang.ref.Reference} types.
140 */
141 public enum Strength {
142 strong("Strong"), weak("Weak"), soft("Soft");
143 private final String name;
144 Strength(String name) { this.name = name; }
145 String getName() { return name; }
146 };
147
148
149 /** The strength of ordinary references */
150 public static final Strength STRONG = Strength.strong;
151
152 /** The strength of weak references */
153 public static final Strength WEAK = Strength.weak;
154
155 /** The strength of soft references */
156 public static final Strength SOFT = Strength.soft;
157
158 /** Config string for self-map (Set view) refs */
159 private static final String SELF_STRING = "Self";
160
161 /** Config string for int maps */
162 private static final String INT_STRING = "Int";
163
164 /**
165 * An object performing equality comparisons, along with a hash
166 * function consistent with this comparison. The type signatures
167 * of the methods of this interface reflect those of {@link
168 * java.util.Map}: While only elements of {@code K} may be
169 * entered into a Map, any {@code Object} may be tested for
170 * membership. Note that the performance of hash maps is heavily
171 * dependent on the quality of hash functions.
172 */
173 public static interface Equivalence<K> {
174 /**
175 * Returns true if the given objects are considered equal.
176 * This function must obey an equivalence relation:
177 * equal(a, a) is always true, equal(a, b) implies equal(b, a),
178 * and (equal(a, b) &amp;&amp; equal(b, c) implies equal(a, c).
179 * Note that the second argument need not be known to have
180 * the same declared type as the first.
181 * @param key a key in, or being placed in, the map
182 * @param x an object queried for membership
183 * @return true if considered equal
184 */
185 boolean equal(K key, Object x);
186 /**
187 * Returns a hash value such that equal(a, b) implies
188 * hash(a)==hash(b).
189 * @param x an object queried for membership
190 * @return a hash value
191 */
192 int hash(Object x);
193 }
194
195 // builtin equivalences
196
197 static final class EquivalenceUsingIdentity
198 implements Equivalence<Object>, Serializable {
199 private static final long serialVersionUID = 7259069246764182397L;
200 public final boolean equal(Object a, Object b) { return a == b; }
201 public final int hash(Object a) { return System.identityHashCode(a); }
202 }
203
204 static final class EquivalenceUsingEquals
205 implements Equivalence<Object>, Serializable {
206 private static final long serialVersionUID = 7259069247764182397L;
207 public final boolean equal(Object a, Object b) { return a.equals(b); }
208 public final int hash(Object a) { return a.hashCode(); }
209 }
210
211 /**
212 * An Equivalence object performing identity-based comparisons
213 * and using {@link System#identityHashCode} for hashing
214 */
215 public static final Equivalence<Object> IDENTITY =
216 new EquivalenceUsingIdentity();
217
218 /**
219 * An Equivalence object performing {@link Object#equals} based comparisons
220 * and using {@link Object#hashCode} hashing
221 */
222 public static final Equivalence<Object> EQUALS =
223 new EquivalenceUsingEquals();
224
225 /**
226 * A function computing a mapping from the given key to a value,
227 * or {@code null} if there is no mapping.
228 */
229 public static interface MappingFunction<K, V> {
230 /**
231 * Returns a value for the given key, or null if there is no
232 * mapping. If this function throws an (unchecked) exception,
233 * the exception is rethrown to its caller, and no mapping is
234 * recorded. Because this function is invoked within
235 * atomicity control, the computation should be short and
236 * simple. The most common usage is to construct a new object
237 * serving as an initial mapped value.
238 *
239 * @param key the (non-null) key
240 * @return a value, or null if none
241 */
242 V map(K key);
243 }
244
245 /**
246 * A function computing a new mapping from the given key and its
247 * current value to a new value, or {@code null} if there is
248 * no mapping.
249 */
250 public static interface RemappingFunction<K, V> {
251 /**
252 * Returns a new value for the given key and its current, or
253 * null if there is no mapping.
254 * @param key the key
255 * @param value the current value, or null if none
256 * @return a value, or null if none
257 */
258 V remap(K key, V value);
259 }
260
261 /**
262 * An object that may be subject to cleanup operations when
263 * removed from a {@link java.lang.ref.ReferenceQueue}
264 */
265 static interface Reclaimable {
266 /**
267 * The action taken upon removal of this object
268 * from a ReferenceQueue.
269 */
270 void onReclamation();
271 }
272
273 /**
274 * A factory for Nodes.
275 */
276 static interface NodeFactory extends Serializable {
277 /**
278 * Creates and returns a Node using the given parameters.
279 *
280 * @param locator an opaque immutable locator for this node
281 * @param key the (non-null) immutable key
282 * @param value the (non-null) volatile value
283 * @param cchm the table creating this node
284 * @param linkage an opaque volatile linkage for maintaining this node
285 */
286 Node newNode(int locator, Object key, Object value,
287 CustomConcurrentHashMap cchm, Node linkage);
288 }
289
290 /**
291 * An object maintaining a key-value mapping. Nodes provide
292 * methods that are intended to used <em>only</em> by the map
293 * creating the node. This includes methods used solely for
294 * internal bookkeeping by maps, that must be treating opaquely by
295 * implementation classes. (This requirement stems from the fact
296 * that concrete implementations may be required to subclass
297 * {@link java.lang.ref.Reference} or other classes, so a base
298 * class cannot be established.)
299 *
300 * This interface uses raw types as the lesser of evils.
301 * Otherwise we'd encounter almost as many unchecked casts when
302 * nodes are used across sets, etc.
303 */
304 static interface Node extends Reclaimable {
305 /**
306 * Returns the key established during the creation of this node.
307 * Note: This method is named "get" rather than "getKey"
308 * to simplify usage of Reference keys.
309 * @return the key
310 */
311 Object get();
312
313 /**
314 * Returns the locator established during the creation of this node.
315 * @return the locator
316 */
317 int getLocator();
318
319 /**
320 * Returns the value established during the creation of this
321 * node or, if since updated, the value set by the most
322 * recent call to setValue, or throws an exception if
323 * value could not be computed.
324 * @return the value
325 * @throws RuntimeException or Error if computeValue failed
326 */
327 Object getValue();
328
329 /**
330 * Nodes the value to be returned by the next call to getValue.
331 * @param value the value
332 */
333 void setValue(Object value);
334
335 /**
336 * Returns the linkage established during the creation of this
337 * node or, if since updated, the linkage set by the most
338 * recent call to setLinkage.
339 * @return the linkage
340 */
341 Node getLinkage();
342
343 /**
344 * Records the linkage to be returned by the next call to getLinkage.
345 * @param linkage the linkage
346 */
347 void setLinkage(Node linkage);
348 }
349
350 /**
351 * Each Segment holds a count and table corresponding to a segment
352 * of the table. This class contains only those methods for
353 * directly assigning these fields, which must only be called
354 * while holding locks.
355 */
356 static final class Segment extends ReentrantLock {
357 volatile Node[] table;
358 int count;
359
360 final void decrementCount() {
361 if (--count == 0)
362 table = null;
363 }
364
365 final void clearCount() {
366 count = 0;
367 table = null;
368 }
369
370 final void incrementCount() {
371 ++count;
372 }
373
374 final Node[] getTableForTraversal() {
375 return table;
376 }
377
378 final Node[] getTableForAdd(CustomConcurrentHashMap cchm) {
379 int len;
380 Node[] tab = table;
381 if (tab == null || // 3/4 threshold
382 ((len = tab.length) - (len >>> 2)) < count)
383 return resizeTable(cchm);
384 else
385 return tab;
386 }
387
388 /**
389 * See the similar code in ConcurrentHashMap for explanation.
390 */
391 final Node[] resizeTable(CustomConcurrentHashMap cchm) {
392 Node[] oldTable = table;
393 if (oldTable == null)
394 return table = new Node[cchm.initialSegmentCapacity];
395
396 int oldCapacity = oldTable.length;
397 if (oldCapacity >= MAX_SEGMENT_CAPACITY)
398 return oldTable;
399 Node[] newTable = new Node[oldCapacity<<1];
400 int sizeMask = newTable.length - 1;
401 NodeFactory fac = cchm.factory;
402 for (int i = 0; i < oldCapacity ; i++) {
403 Node e = oldTable[i];
404
405 if (e != null) {
406 Node next = e.getLinkage();
407 int idx = e.getLocator() & sizeMask;
408
409 // Single node on list
410 if (next == null)
411 newTable[idx] = e;
412
413 else {
414 // Reuse trailing consecutive sequence at same slot
415 Node lastRun = e;
416 int lastIdx = idx;
417 for (Node last = next;
418 last != null;
419 last = last.getLinkage()) {
420 int k = last.getLocator() & sizeMask;
421 if (k != lastIdx) {
422 lastIdx = k;
423 lastRun = last;
424 }
425 }
426 newTable[lastIdx] = lastRun;
427
428 // Clone all remaining nodes
429 for (Node p = e; p != lastRun; p = p.getLinkage()) {
430 int ph = p.getLocator();
431 int k = ph & sizeMask;
432 Object pk = p.get();
433 Object pv;
434 if (pk == null ||
435 (pv = p.getValue()) == null)
436 --count;
437 else
438 newTable[k] =
439 fac.newNode(ph, pk, pv, cchm, newTable[k]);
440 }
441 }
442 }
443 }
444 return table = newTable;
445 }
446 }
447
448 // Hardwire 64 segments
449
450 static final int SEGMENT_BITS = 6;
451 static final int NSEGMENTS = 1 << SEGMENT_BITS;
452 static final int SEGMENT_MASK = NSEGMENTS - 1;
453 static final int SEGMENT_SHIFT = 32 - SEGMENT_BITS;
454 static final int MIN_SEGMENT_CAPACITY = 4;
455 static final int MAX_SEGMENT_CAPACITY = 1 << (32 - SEGMENT_BITS);
456
457 /**
458 * Applies a supplemental hash function to a given hashCode, which
459 * defends against poor quality hash functions. This is critical
460 * because we use power-of-two length hash tables, that otherwise
461 * encounter collisions for hashCodes that do not differ in lower
462 * or upper bits.
463 */
464 static int spreadHash(int h) {
465 // Spread bits to regularize both segment and index locations,
466 // using variant of single-word Wang/Jenkins hash.
467 h += (h << 15) ^ 0xffffcd7d;
468 h ^= (h >>> 10);
469 h += (h << 3);
470 h ^= (h >>> 6);
471 h += (h << 2) + (h << 14);
472 return h ^ (h >>> 16);
473 }
474
475 /**
476 * The segments, each of which acts as a hash table
477 */
478 transient volatile Segment[] segments;
479
480 /**
481 * The factory for this map
482 */
483 final NodeFactory factory;
484
485 /**
486 * Equivalence object for keys
487 */
488 final Equivalence<? super K> keyEquivalence;
489
490 /**
491 * Equivalence object for values
492 */
493 final Equivalence<? super V> valueEquivalence;
494
495 /**
496 * The initial size of Segment tables when they are first constructed
497 */
498 final int initialSegmentCapacity;
499
500 // Cached view objects
501 transient Set<K> keySet;
502 transient Set<Map.Entry<K,V>> entrySet;
503 transient Collection<V> values;
504
505 /**
506 * Internal constructor to set factory, equivalences and segment
507 * capacities, and to create segments array.
508 */
509 CustomConcurrentHashMap(String ks, Equivalence<? super K> keq,
510 String vs, Equivalence<? super V> veq,
511 int expectedSize) {
512 if (keq == null || veq == null)
513 throw new NullPointerException();
514 this.keyEquivalence = keq;
515 this.valueEquivalence = veq;
516 // Reflectively assemble factory name
517 String factoryName =
518 CustomConcurrentHashMap.class.getName() + "$" +
519 ks + "Key" +
520 vs + "ValueNodeFactory";
521 try {
522 this.factory = (NodeFactory)
523 (Class.forName(factoryName).newInstance());
524 } catch (Exception ex) {
525 throw new Error("Cannot instantiate " + factoryName);
526 }
527 int es = expectedSize;
528 if (es == 0)
529 this.initialSegmentCapacity = MIN_SEGMENT_CAPACITY;
530 else {
531 int sc = (int)((1L + (4L * es) / 3) >>> SEGMENT_BITS);
532 if (sc < MIN_SEGMENT_CAPACITY)
533 sc = MIN_SEGMENT_CAPACITY;
534 int capacity = MIN_SEGMENT_CAPACITY; // ensure power of two
535 while (capacity < sc)
536 capacity <<= 1;
537 if (capacity > MAX_SEGMENT_CAPACITY)
538 capacity = MAX_SEGMENT_CAPACITY;
539 this.initialSegmentCapacity = capacity;
540 }
541 this.segments = new Segment[NSEGMENTS];
542 }
543
544 /**
545 * Creates a new CustomConcurrentHashMap with the given parameters.
546 * @param keyStrength the strength for keys
547 * @param keyEquivalence the Equivalence to use for keys
548 * @param valueStrength the strength for values
549 * @param valueEquivalence the Equivalence to use for values
550 * @param expectedSize an estimate of the number of elements
551 * that will be held in the map. If no estimate is known,
552 * zero is an acceptable value.
553 */
554 public CustomConcurrentHashMap(Strength keyStrength,
555 Equivalence<? super K> keyEquivalence,
556 Strength valueStrength,
557 Equivalence<? super V> valueEquivalence,
558 int expectedSize) {
559 this(keyStrength.getName(), keyEquivalence,
560 valueStrength.getName(), valueEquivalence,
561 expectedSize);
562 }
563
564 /**
565 * Creates a new CustomConcurrentHashMap with strong keys and
566 * values, and equality-based equivalence.
567 */
568 public CustomConcurrentHashMap() {
569 this(STRONG, EQUALS, STRONG, EQUALS, 0);
570 }
571
572 /**
573 * Returns a new map using Integer keys and the given value
574 * parameters.
575 * @param valueStrength the strength for values
576 * @param valueEquivalence the Equivalence to use for values
577 * @param expectedSize an estimate of the number of elements
578 * that will be held in the map. If no estimate is known,
579 * zero is an acceptable value.
580 * @return the map
581 */
582 public static <ValueType> CustomConcurrentHashMap<Integer, ValueType>
583 newIntKeyMap(Strength valueStrength,
584 Equivalence<? super ValueType> valueEquivalence,
585 int expectedSize) {
586 return new CustomConcurrentHashMap<Integer, ValueType>
587 (INT_STRING, EQUALS, valueStrength.getName(), valueEquivalence,
588 expectedSize);
589 }
590
591 /**
592 * Returns a new map using the given key parameters and Integer values.
593 * @param keyStrength the strength for keys
594 * @param keyEquivalence the Equivalence to use for keys
595 * @param expectedSize an estimate of the number of elements
596 * that will be held in the map. If no estimate is known,
597 * zero is an acceptable value.
598 * @return the map
599 */
600 public static <KeyType> CustomConcurrentHashMap<KeyType, Integer>
601 newIntValueMap(Strength keyStrength,
602 Equivalence<? super KeyType> keyEquivalence,
603 int expectedSize) {
604 return new CustomConcurrentHashMap<KeyType, Integer>
605 (keyStrength.getName(), keyEquivalence, INT_STRING, EQUALS,
606 expectedSize);
607 }
608
609 /**
610 * Returns a new map using Integer keys and values.
611 * @param expectedSize an estimate of the number of elements
612 * that will be held in the map. If no estimate is known,
613 * zero is an acceptable value.
614 * @return the map
615 */
616 public static CustomConcurrentHashMap<Integer, Integer>
617 newIntKeyIntValueMap(int expectedSize) {
618 return new CustomConcurrentHashMap<Integer, Integer>
619 (INT_STRING, EQUALS, INT_STRING, EQUALS,
620 expectedSize);
621 }
622
623 /**
624 * Returns the segment for traversing table for key with given hash.
625 * @param hash the hash code for the key
626 * @return the segment, or null if not yet initialized
627 */
628 final Segment getSegmentForTraversal(int hash) {
629 return segments[(hash >>> SEGMENT_SHIFT) & SEGMENT_MASK];
630 }
631
632 /**
633 * Returns the segment for possibly inserting into the table
634 * associated with given hash, constructing it if necessary.
635 * @param hash the hash code for the key
636 * @return the segment
637 */
638 final Segment getSegmentForAdd(int hash) {
639 Segment[] segs = segments;
640 int index = (hash >>> SEGMENT_SHIFT) & SEGMENT_MASK;
641 Segment seg = segs[index];
642 if (seg == null) {
643 synchronized (segs) {
644 seg = segs[index];
645 if (seg == null) {
646 seg = new Segment();
647 // Fences.preStoreFence(seg);
648 // segs[index] = seg;
649 storeSegment(segs, index, seg);
650 }
651 }
652 }
653 return seg;
654 }
655
656 /**
657 * Returns node for key, or null if none.
658 */
659 final Node findNode(Object key, int hash, Segment seg) {
660 if (seg != null) {
661 Node[] tab = seg.getTableForTraversal();
662 if (tab != null) {
663 Node p = tab[hash & (tab.length - 1)];
664 while (p != null) {
665 Object k = p.get();
666 if (k == key ||
667 (k != null &&
668 p.getLocator() == hash &&
669 keyEquivalence.equal((K)k, key)))
670 return p;
671 p = p.getLinkage();
672 }
673 }
674 }
675 return null;
676 }
677
678 /**
679 * Returns {@code true} if this map contains a key equivalent to
680 * the given key with respect to this map's key Equivalence.
681 *
682 * @param key possible key
683 * @return {@code true} if this map contains the specified key
684 * @throws NullPointerException if the specified key is null
685 */
686 public boolean containsKey(Object key) {
687 if (key == null)
688 throw new NullPointerException();
689 int hash = spreadHash(keyEquivalence.hash(key));
690 Segment seg = getSegmentForTraversal(hash);
691 Node r = findNode(key, hash, seg);
692 return r != null && r.getValue() != null;
693 }
694
695 /**
696 * Returns the value associated with a key equivalent to the given
697 * key with respect to this map's key Equivalence, or {@code null}
698 * if no such mapping exists.
699 *
700 * @param key possible key
701 * @return the value associated with the key or {@code null} if
702 * there is no mapping
703 * @throws NullPointerException if the specified key is null
704 */
705 public V get(Object key) {
706 if (key == null)
707 throw new NullPointerException();
708 int hash = spreadHash(keyEquivalence.hash(key));
709 Segment seg = getSegmentForTraversal(hash);
710 Node r = findNode(key, hash, seg);
711 if (r == null)
712 return null;
713 return (V)(r.getValue());
714 }
715
716 /**
717 * Shared implementation for put, putIfAbsent
718 */
719 final V doPut(K key, V value, boolean onlyIfNull) {
720 if (key == null || value == null)
721 throw new NullPointerException();
722 V oldValue = null;
723 int hash = spreadHash(keyEquivalence.hash(key));
724 Segment seg = getSegmentForAdd(hash);
725 seg.lock();
726 try {
727 Node r = findNode(key, hash, seg);
728 if (r != null) {
729 oldValue = (V)(r.getValue());
730 if (!onlyIfNull || oldValue == null)
731 r.setValue(value);
732 }
733 else {
734 Node[] tab = seg.getTableForAdd(this);
735 int i = hash & (tab.length - 1);
736 r = factory.newNode(hash, key, value, this, tab[i]);
737 // Fences.preStoreFence(r);
738 // tab[i] = r;
739 storeNode(tab, i, r);
740 seg.incrementCount();
741 }
742 } finally {
743 seg.unlock();
744 }
745 return oldValue;
746 }
747
748 /**
749 * Maps the specified key to the specified value in this map.
750 *
751 * @param key key with which the specified value is to be associated
752 * @param value value to be associated with the specified key
753 * @return the previous value associated with {@code key}, or
754 * {@code null} if there was no mapping for {@code key}
755 * @throws NullPointerException if the specified key or value is null
756 */
757 public V put(K key, V value) {
758 return doPut(key, value, false);
759 }
760
761 /**
762 * {@inheritDoc}
763 *
764 * @return the previous value associated with the specified key,
765 * or {@code null} if there was no mapping for the key
766 * @throws NullPointerException if the specified key or value is null
767 */
768 public V putIfAbsent(K key, V value) {
769 return doPut(key, value, true);
770 }
771
772 /**
773 * Copies all of the mappings from the specified map to this one.
774 * These mappings replace any mappings that this map had for any
775 * of the keys currently in the specified map.
776 *
777 * @param m mappings to be stored in this map
778 */
779 public void putAll(Map<? extends K, ? extends V> m) {
780 for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
781 put(e.getKey(), e.getValue());
782 }
783
784 /**
785 * {@inheritDoc}
786 *
787 * @throws NullPointerException if any of the arguments are null
788 */
789 public V replace(K key, V value) {
790 if (key == null || value == null)
791 throw new NullPointerException();
792 V oldValue = null;
793 int hash = spreadHash(keyEquivalence.hash(key));
794 Segment seg = getSegmentForTraversal(hash);
795 if (seg != null) {
796 seg.lock();
797 try {
798 Node r = findNode(key, hash, seg);
799 if (r != null) {
800 oldValue = (V)(r.getValue());
801 r.setValue(value);
802 }
803 } finally {
804 seg.unlock();
805 }
806 }
807 return oldValue;
808 }
809
810 /**
811 * {@inheritDoc}
812 *
813 * @return the previous value associated with the specified key,
814 * or {@code null} if there was no mapping for the key
815 * @throws NullPointerException if the specified key or value is null
816 */
817 public boolean replace(K key, V oldValue, V newValue) {
818 if (key == null || oldValue == null || newValue == null)
819 throw new NullPointerException();
820 boolean replaced = false;
821 int hash = spreadHash(keyEquivalence.hash(key));
822 Segment seg = getSegmentForTraversal(hash);
823 if (seg != null) {
824 seg.lock();
825 try {
826 Node r = findNode(key, hash, seg);
827 if (r != null) {
828 V v = (V)(r.getValue());
829 if (v == oldValue ||
830 (v != null && valueEquivalence.equal(v, oldValue))) {
831 r.setValue(newValue);
832 replaced = true;
833 }
834 }
835 } finally {
836 seg.unlock();
837 }
838 }
839 return replaced;
840 }
841
842 /**
843 * Removes the mapping for the specified key.
844 *
845 * @param key the key to remove
846 * @return the previous value associated with {@code key}, or
847 * {@code null} if there was no mapping for {@code key}
848 * @throws NullPointerException if the specified key is null
849 */
850 public V remove(Object key) {
851 if (key == null)
852 throw new NullPointerException();
853 V oldValue = null;
854 int hash = spreadHash(keyEquivalence.hash(key));
855 Segment seg = getSegmentForTraversal(hash);
856 if (seg != null) {
857 seg.lock();
858 try {
859 Node[] tab = seg.getTableForTraversal();
860 if (tab != null) {
861 int i = hash & (tab.length - 1);
862 Node pred = null;
863 Node p = tab[i];
864 while (p != null) {
865 Node n = p.getLinkage();
866 Object k = p.get();
867 if (k == key ||
868 (k != null &&
869 p.getLocator() == hash &&
870 keyEquivalence.equal((K)k, key))) {
871 oldValue = (V)(p.getValue());
872 if (pred == null)
873 tab[i] = n;
874 else
875 pred.setLinkage(n);
876 seg.decrementCount();
877 break;
878 }
879 pred = p;
880 p = n;
881 }
882 }
883 } finally {
884 seg.unlock();
885 }
886 }
887 return oldValue;
888 }
889
890 /**
891 * {@inheritDoc}
892 *
893 * @throws NullPointerException if the specified key is null
894 */
895 public boolean remove(Object key, Object value) {
896 if (key == null)
897 throw new NullPointerException();
898 if (value == null)
899 return false;
900 boolean removed = false;
901 int hash = spreadHash(keyEquivalence.hash(key));
902 Segment seg = getSegmentForTraversal(hash);
903 if (seg != null) {
904 seg.lock();
905 try {
906 Node[] tab = seg.getTableForTraversal();
907 if (tab != null) {
908 int i = hash & (tab.length - 1);
909 Node pred = null;
910 Node p = tab[i];
911 while (p != null) {
912 Node n = p.getLinkage();
913 Object k = p.get();
914 if (k == key ||
915 (k != null &&
916 p.getLocator() == hash &&
917 keyEquivalence.equal((K)k, key))) {
918 V v = (V)(p.getValue());
919 if (v == value ||
920 (v != null &&
921 valueEquivalence.equal(v, value))) {
922 if (pred == null)
923 tab[i] = n;
924 else
925 pred.setLinkage(n);
926 seg.decrementCount();
927 removed = true;
928 }
929 break;
930 }
931 pred = p;
932 p = n;
933 }
934 }
935 } finally {
936 seg.unlock();
937 }
938 }
939 return removed;
940 }
941
942 /**
943 * Removes node if its key or value are null.
944 */
945 final void removeIfReclaimed(Node r) {
946 int hash = r.getLocator();
947 Segment seg = getSegmentForTraversal(hash);
948 if (seg != null) {
949 seg.lock();
950 try {
951 Node[] tab = seg.getTableForTraversal();
952 if (tab != null) {
953 // remove all reclaimed in list
954 int i = hash & (tab.length - 1);
955 Node pred = null;
956 Node p = tab[i];
957 while (p != null) {
958 Node n = p.getLinkage();
959 if (p.get() != null && p.getValue() != null) {
960 pred = p;
961 p = n;
962 }
963 else {
964 if (pred == null)
965 tab[i] = n;
966 else
967 pred.setLinkage(n);
968 seg.decrementCount();
969 p = n;
970 }
971 }
972 }
973 } finally {
974 seg.unlock();
975 }
976 }
977 }
978
979 /**
980 * Returns {@code true} if this map contains no key-value mappings.
981 *
982 * @return {@code true} if this map contains no key-value mappings
983 */
984 public final boolean isEmpty() {
985 final Segment[] segs = this.segments;
986 for (int i = 0; i < segs.length; ++i) {
987 Segment seg = segs[i];
988 if (seg != null &&
989 seg.getTableForTraversal() != null &&
990 seg.count != 0)
991 return false;
992 }
993 return true;
994 }
995
996 /**
997 * Returns the number of key-value mappings in this map. If the
998 * map contains more than {@code Integer.MAX_VALUE} elements, returns
999 * {@code Integer.MAX_VALUE}.
1000 *
1001 * @return the number of key-value mappings in this map
1002 */
1003 public final int size() {
1004 long sum = 0;
1005 final Segment[] segs = this.segments;
1006 for (int i = 0; i < segs.length; ++i) {
1007 Segment seg = segs[i];
1008 if (seg != null && seg.getTableForTraversal() != null)
1009 sum += seg.count;
1010 }
1011 return (sum >= Integer.MAX_VALUE) ? Integer.MAX_VALUE : (int) sum;
1012 }
1013
1014 /**
1015 * Returns {@code true} if this map maps one or more keys to a
1016 * value equivalent to the given value with respect to this map's
1017 * value Equivalence. Note: This method requires a full internal
1018 * traversal of the hash table, and so is much slower than method
1019 * {@code containsKey}.
1020 *
1021 * @param value value whose presence in this map is to be tested
1022 * @return {@code true} if this map maps one or more keys to the
1023 * specified value
1024 * @throws NullPointerException if the specified value is null
1025 */
1026 public final boolean containsValue(Object value) {
1027 if (value == null)
1028 throw new NullPointerException();
1029 Segment[] segs = this.segments;
1030 for (int i = 0; i < segs.length; ++i) {
1031 Segment seg = segs[i];
1032 Node[] tab;
1033 if (seg != null && (tab = seg.getTableForTraversal()) != null) {
1034 for (int j = 0; j < tab.length; ++j) {
1035 for (Node p = tab[j];
1036 p != null;
1037 p = p.getLinkage()) {
1038 V v = (V)(p.getValue());
1039 if (v == value ||
1040 (v != null && valueEquivalence.equal(v, value)))
1041 return true;
1042 }
1043 }
1044 }
1045 }
1046 return false;
1047 }
1048
1049 /**
1050 * Removes all of the mappings from this map.
1051 */
1052 public final void clear() {
1053 Segment[] segs = this.segments;
1054 for (int i = 0; i < segs.length; ++i) {
1055 Segment seg = segs[i];
1056 if (seg != null) {
1057 seg.lock();
1058 try {
1059 seg.clearCount();
1060 } finally {
1061 seg.unlock();
1062 }
1063 }
1064 }
1065 }
1066
1067 /**
1068 * If the specified key is not already associated with a value,
1069 * computes its value using the given mappingFunction, and if
1070 * non-null, enters it into the map. This is equivalent to
1071 *
1072 * <pre>
1073 * if (map.containsKey(key))
1074 * return map.get(key);
1075 * value = mappingFunction.map(key);
1076 * if (value != null)
1077 * return map.put(key, value);
1078 * else
1079 * return null;
1080 * </pre>
1081 *
1082 * except that the action is performed atomically. Some
1083 * attempted operations on this map by other threads may be
1084 * blocked while computation is in progress. Because this function
1085 * is invoked within atomicity control, the computation should be
1086 * short and simple. The most common usage is to construct a new
1087 * object serving as an initial mapped value, or memoized result.
1088 *
1089 * @param key key with which the specified value is to be associated
1090 * @param mappingFunction the function to compute a value
1091 * @return the current (existing or computed) value associated with
1092 * the specified key, or {@code null} if the computation
1093 * returned {@code null}
1094 * @throws NullPointerException if the specified key or mappingFunction
1095 * is null
1096 * @throws RuntimeException or Error if the mappingFunction does so,
1097 * in which case the mapping is left unestablished
1098 */
1099 public V computeIfAbsent(K key, MappingFunction<? super K, ? extends V> mappingFunction) {
1100 if (key == null || mappingFunction == null)
1101 throw new NullPointerException();
1102 int hash = spreadHash(keyEquivalence.hash(key));
1103 Segment seg = getSegmentForTraversal(hash);
1104 Node r = findNode(key, hash, seg);
1105 V v = null;
1106 if (r == null) {
1107 if (seg == null)
1108 seg = getSegmentForAdd(hash);
1109 seg.lock();
1110 try {
1111 r = findNode(key, hash, seg);
1112 if (r == null || (v = (V)(r.getValue())) == null) {
1113 // Map is OK if function throws exception
1114 v = mappingFunction.map(key);
1115 if (v != null) {
1116 if (r != null)
1117 r.setValue(v);
1118 else {
1119 Node[] tab = seg.getTableForAdd(this);
1120 int i = hash & (tab.length - 1);
1121 r = factory.newNode(hash, key, v, this, tab[i]);
1122 // Fences.preStoreFence(r);
1123 // tab[i] = r;
1124 storeNode(tab, i, r);
1125 seg.incrementCount();
1126 }
1127 }
1128 }
1129 } finally {
1130 seg.unlock();
1131 }
1132 }
1133 if (r != null && v == null)
1134 removeIfReclaimed(r);
1135 return v;
1136 }
1137
1138 /**
1139 * Updates the mapping for the given key with the result of the
1140 * given remappingFunction. This is equivalent to
1141 *
1142 * <pre>
1143 * value = remappingFunction.remap(key, get(key));
1144 * if (value != null)
1145 * return put(key, value):
1146 * else
1147 * return remove(key);
1148 * </pre>
1149 *
1150 * except that the action is performed atomically. Some attempted
1151 * operations on this map by other threads may be blocked while
1152 * computation is in progress.
1153 *
1154 * <p>Sample Usage. A remapping function can be used to
1155 * perform frequency counting of words using code such as:
1156 * <pre>
1157 * map.compute(word, new RemappingFunction&lt;String,Integer&gt;() {
1158 * public Integer remap(String k, Integer v) {
1159 * return (v == null) ? 1 : v + 1;
1160 * }});
1161 * </pre>
1162 *
1163 * @param key key with which the specified value is to be associated
1164 * @param remappingFunction the function to compute a value
1165 * @return the updated value or
1166 * {@code null} if the computation returned {@code null}
1167 * @throws NullPointerException if the specified key or remappingFunction
1168 * is null
1169 * @throws RuntimeException or Error if the remappingFunction does so,
1170 * in which case the mapping is left in its previous state
1171 */
1172 public V compute(K key, RemappingFunction<? super K, V> remappingFunction) {
1173 if (key == null || remappingFunction == null)
1174 throw new NullPointerException();
1175 int hash = spreadHash(keyEquivalence.hash(key));
1176 V value = null;
1177 Segment seg = getSegmentForAdd(hash);
1178 seg.lock();
1179 try {
1180 Node[] tab = seg.getTableForAdd(this);
1181 int i = hash & (tab.length - 1);
1182 Node pred = null;
1183 Node p = tab[i];
1184 while (p != null) {
1185 K k = (K)(p.get());
1186 if (k == key ||
1187 (k != null &&
1188 p.getLocator() == hash &&
1189 keyEquivalence.equal(k, key))) {
1190 value = (V)(p.getValue());
1191 break;
1192 }
1193 pred = p;
1194 p = p.getLinkage();
1195 }
1196 value = remappingFunction.remap(key, value);
1197 if (p != null) {
1198 if (value != null)
1199 p.setValue(value);
1200 else {
1201 Node n = p.getLinkage();
1202 if (pred == null)
1203 tab[i] = n;
1204 else
1205 pred.setLinkage(n);
1206 seg.decrementCount();
1207 }
1208 }
1209 else if (value != null) {
1210 Node r =
1211 factory.newNode(hash, key, value, this, tab[i]);
1212 // Fences.preStoreFence(r);
1213 // tab[i] = r;
1214 storeNode(tab, i, r);
1215 seg.incrementCount();
1216 }
1217 } finally {
1218 seg.unlock();
1219 }
1220 return value;
1221 }
1222
1223 abstract class HashIterator {
1224 int nextSegmentIndex;
1225 int nextTableIndex;
1226 Node[] currentTable;
1227 Node nextNode;
1228 Object nextKey; // key of nextNode
1229 Object nextValue; // value of nextNode
1230 Object lastKey; // for remove()
1231
1232 HashIterator() {
1233 nextSegmentIndex = segments.length - 1;
1234 nextTableIndex = -1;
1235 advance();
1236 }
1237
1238 public final boolean hasNext() { return nextNode != null; }
1239
1240 final void advance() {
1241 lastKey = nextKey;
1242 if (nextNode != null)
1243 nextNode = nextNode.getLinkage();
1244 for (;;) {
1245 if (nextNode != null) {
1246 if ((nextKey = nextNode.get()) != null &&
1247 (nextValue = nextNode.getValue()) != null)
1248 return;
1249 Node n = nextNode.getLinkage();
1250 removeIfReclaimed(nextNode);
1251 nextNode = n;
1252 }
1253 else if (nextTableIndex >= 0) {
1254 nextNode = currentTable[nextTableIndex--];
1255 }
1256 else if (nextSegmentIndex >= 0) {
1257 Segment seg = segments[nextSegmentIndex--];
1258 Node[] t;
1259 if (seg != null &&
1260 (t = seg.getTableForTraversal()) != null) {
1261 currentTable = t;
1262 nextTableIndex = t.length - 1;
1263 }
1264 }
1265 else {
1266 nextKey = null;
1267 nextValue = null;
1268 return;
1269 }
1270 }
1271 }
1272
1273 final K nextKey() {
1274 if (nextNode == null)
1275 throw new NoSuchElementException();
1276 Object k = nextKey;
1277 advance();
1278 return (K)k;
1279 }
1280
1281 final V nextValue() {
1282 if (nextNode == null)
1283 throw new NoSuchElementException();
1284 Object v = nextValue;
1285 advance();
1286 return (V)v;
1287 }
1288
1289 final Map.Entry<K,V> nextEntry() {
1290 if (nextNode == null)
1291 throw new NoSuchElementException();
1292 WriteThroughEntry e = new WriteThroughEntry((K)nextKey,
1293 (V)nextValue);
1294 advance();
1295 return e;
1296 }
1297
1298 public void remove() {
1299 if (lastKey == null)
1300 throw new IllegalStateException();
1301 CustomConcurrentHashMap.this.remove(lastKey);
1302 lastKey = null;
1303 }
1304 }
1305
1306 final class WriteThroughEntry implements Map.Entry<K,V>, Serializable {
1307 private static final long serialVersionUID = 7249069346764182397L;
1308 final K key;
1309 V value;
1310 WriteThroughEntry(K key, V value) {
1311 this.key = key;
1312 this.value = value;
1313 }
1314 public K getKey() { return key; }
1315 public V getValue() { return value; }
1316 public V setValue(V value) {
1317 if (value == null) throw new NullPointerException();
1318 V v = this.value;
1319 this.value = value;
1320 CustomConcurrentHashMap.this.doPut(key, value, false);
1321 return v;
1322 }
1323 public int hashCode() {
1324 return keyEquivalence.hash(key) ^ valueEquivalence.hash(value);
1325 }
1326 public boolean equals(Object o) {
1327 if (!(o instanceof Map.Entry))
1328 return false;
1329 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1330 return (keyEquivalence.equal(key, e.getKey()) &&
1331 valueEquivalence.equal(value, e.getValue()));
1332 }
1333 }
1334
1335 final class KeyIterator extends HashIterator
1336 implements Iterator<K> {
1337 public K next() {
1338 return super.nextKey();
1339 }
1340 }
1341
1342 final KeyIterator keyIterator() { // needed by Set
1343 return new KeyIterator();
1344 }
1345
1346 final class ValueIterator extends HashIterator
1347 implements Iterator<V> {
1348 public V next() {
1349 return super.nextValue();
1350 }
1351 }
1352
1353 final class EntryIterator extends HashIterator
1354 implements Iterator<Map.Entry<K,V>> {
1355 public Map.Entry<K,V> next() {
1356 return super.nextEntry();
1357 }
1358 }
1359
1360 final class KeySetView extends AbstractSet<K> {
1361 public Iterator<K> iterator() {
1362 return new KeyIterator();
1363 }
1364 public int size() {
1365 return CustomConcurrentHashMap.this.size();
1366 }
1367 public boolean isEmpty() {
1368 return CustomConcurrentHashMap.this.isEmpty();
1369 }
1370 public boolean contains(Object o) {
1371 return CustomConcurrentHashMap.this.containsKey(o);
1372 }
1373 public boolean remove(Object o) {
1374 return CustomConcurrentHashMap.this.remove(o) != null;
1375 }
1376 public void clear() {
1377 CustomConcurrentHashMap.this.clear();
1378 }
1379 }
1380
1381 final class Values extends AbstractCollection<V> {
1382 public Iterator<V> iterator() {
1383 return new ValueIterator();
1384 }
1385 public int size() {
1386 return CustomConcurrentHashMap.this.size();
1387 }
1388 public boolean isEmpty() {
1389 return CustomConcurrentHashMap.this.isEmpty();
1390 }
1391 public boolean contains(Object o) {
1392 return CustomConcurrentHashMap.this.containsValue(o);
1393 }
1394 public void clear() {
1395 CustomConcurrentHashMap.this.clear();
1396 }
1397 }
1398
1399 final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
1400 public Iterator<Map.Entry<K,V>> iterator() {
1401 return new EntryIterator();
1402 }
1403 public boolean contains(Object o) {
1404 if (!(o instanceof Map.Entry))
1405 return false;
1406 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1407 V v = CustomConcurrentHashMap.this.get(e.getKey());
1408 return v != null &&
1409 valueEquivalence.equal(v, e.getValue());
1410 }
1411 public boolean remove(Object o) {
1412 if (!(o instanceof Map.Entry))
1413 return false;
1414 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
1415 return CustomConcurrentHashMap.this.remove(e.getKey(),
1416 e.getValue());
1417 }
1418 public int size() {
1419 return CustomConcurrentHashMap.this.size();
1420 }
1421 public boolean isEmpty() {
1422 return CustomConcurrentHashMap.this.isEmpty();
1423 }
1424 public void clear() {
1425 CustomConcurrentHashMap.this.clear();
1426 }
1427 }
1428
1429 /**
1430 * Returns a {@link Set} view of the keys contained in this map.
1431 * The set is backed by the map, so changes to the map are
1432 * reflected in the set, and vice-versa. The set supports element
1433 * removal, which removes the corresponding mapping from this map,
1434 * via the {@code Iterator.remove}, {@code Set.remove},
1435 * {@code removeAll}, {@code retainAll}, and {@code clear}
1436 * operations. It does not support the {@code add} or
1437 * {@code addAll} operations.
1438 *
1439 * <p>The view's {@code iterator} is a "weakly consistent" iterator
1440 * that will never throw {@link ConcurrentModificationException},
1441 * and guarantees to traverse elements as they existed upon
1442 * construction of the iterator, and may (but is not guaranteed to)
1443 * reflect any modifications subsequent to construction.
1444 */
1445 public Set<K> keySet() {
1446 Set<K> ks = keySet;
1447 return (ks != null) ? ks : (keySet = new KeySetView());
1448 }
1449
1450 /**
1451 * Returns a {@link Collection} view of the values contained in this map.
1452 * The collection is backed by the map, so changes to the map are
1453 * reflected in the collection, and vice-versa. The collection
1454 * supports element removal, which removes the corresponding
1455 * mapping from this map, via the {@code Iterator.remove},
1456 * {@code Collection.remove}, {@code removeAll},
1457 * {@code retainAll}, and {@code clear} operations. It does not
1458 * support the {@code add} or {@code addAll} operations.
1459 *
1460 * <p>The view's {@code iterator} is a "weakly consistent" iterator
1461 * that will never throw {@link ConcurrentModificationException},
1462 * and guarantees to traverse elements as they existed upon
1463 * construction of the iterator, and may (but is not guaranteed to)
1464 * reflect any modifications subsequent to construction.
1465 */
1466 public Collection<V> values() {
1467 Collection<V> vs = values;
1468 return (vs != null) ? vs : (values = new Values());
1469 }
1470
1471 /**
1472 * Returns a {@link Set} view of the mappings contained in this map.
1473 * The set is backed by the map, so changes to the map are
1474 * reflected in the set, and vice-versa. The set supports element
1475 * removal, which removes the corresponding mapping from the map,
1476 * via the {@code Iterator.remove}, {@code Set.remove},
1477 * {@code removeAll}, {@code retainAll}, and {@code clear}
1478 * operations. It does not support the {@code add} or
1479 * {@code addAll} operations.
1480 *
1481 * <p>The view's {@code iterator} is a "weakly consistent" iterator
1482 * that will never throw {@link ConcurrentModificationException},
1483 * and guarantees to traverse elements as they existed upon
1484 * construction of the iterator, and may (but is not guaranteed to)
1485 * reflect any modifications subsequent to construction.
1486 */
1487 public Set<Map.Entry<K,V>> entrySet() {
1488 Set<Map.Entry<K,V>> es = entrySet;
1489 return (es != null) ? es : (entrySet = new EntrySet());
1490 }
1491
1492 // overridden AbstractMap methods
1493
1494 /**
1495 * Compares the specified object with this map for equality.
1496 * Returns {@code true} if the given object is also a map of the
1497 * same size, holding keys that are equal using this Map's key
1498 * Equivalence, and which map to values that are equal according
1499 * to this Map's value equivalence.
1500 *
1501 * @param o object to be compared for equality with this map
1502 * @return {@code true} if the specified object is equal to this map
1503 */
1504 public boolean equals(Object o) {
1505 if (o == this)
1506 return true;
1507
1508 if (!(o instanceof Map))
1509 return false;
1510 Map<K,V> m = (Map<K,V>) o;
1511 if (m.size() != size())
1512 return false;
1513
1514 try {
1515 Iterator<Entry<K,V>> i = entrySet().iterator();
1516 while (i.hasNext()) {
1517 Entry<K,V> e = i.next();
1518 K key = e.getKey();
1519 V value = e.getValue();
1520 if (value != null) {
1521 V mv = m.get(key);
1522 if (mv == null)
1523 return false;
1524 if (!valueEquivalence.equal(mv, value))
1525 return false;
1526 }
1527 }
1528 } catch (ClassCastException unused) {
1529 return false;
1530 } catch (NullPointerException unused) {
1531 return false;
1532 }
1533
1534 return true;
1535 }
1536
1537 /**
1538 * Returns the sum of the hash codes of each entry in this map's
1539 * {@code entrySet()} view, which in turn are the hash codes
1540 * computed using key and value Equivalences for this Map.
1541 * @return the hash code
1542 */
1543 public int hashCode() {
1544 int h = 0;
1545 Iterator<Entry<K,V>> i = entrySet().iterator();
1546 while (i.hasNext())
1547 h += i.next().hashCode();
1548 return h;
1549 }
1550
1551 /**
1552 * Saves the state of the instance to a stream (i.e., serializes it).
1553 *
1554 * @param s the stream
1555 * @serialData
1556 * the key (Object) and value (Object)
1557 * for each key-value mapping, followed by a null pair.
1558 * The key-value mappings are emitted in no particular order.
1559 */
1560 private void writeObject(java.io.ObjectOutputStream s) throws IOException {
1561 s.defaultWriteObject();
1562 for (Map.Entry<K,V> e : entrySet()) {
1563 s.writeObject(e.getKey());
1564 s.writeObject(e.getValue());
1565 }
1566 s.writeObject(null);
1567 s.writeObject(null);
1568 }
1569
1570 /**
1571 * Reconstitutes the instance from a stream (that is, deserializes it).
1572 * @param s the stream
1573 */
1574 private void readObject(java.io.ObjectInputStream s)
1575 throws IOException, ClassNotFoundException {
1576 s.defaultReadObject();
1577 this.segments = new Segment[NSEGMENTS];
1578 for (;;) {
1579 K key = (K) s.readObject();
1580 V value = (V) s.readObject();
1581 if (key == null)
1582 break;
1583 put(key, value);
1584 }
1585 }
1586
1587 /**
1588 * A hash-based set with properties identical to those of
1589 * {@code Collections.newSetFromMap} applied to a
1590 * {@code CustomConcurrentHashMap}, but possibly more
1591 * space-efficient. The set does not permit null elements. The
1592 * set is serializable; however, serializing a set that uses soft
1593 * or weak references can give unpredictable results.
1594 */
1595 public static class KeySet<K> extends AbstractSet<K>
1596 implements Set<K>, Serializable {
1597
1598 final CustomConcurrentHashMap<K,K> cchm;
1599
1600 /**
1601 * Creates a set with the given parameters.
1602 * @param strength the strength of elements
1603 * @param equivalence the Equivalence to use
1604 * @param expectedSize an estimate of the number of elements
1605 * that will be held in the set. If no estimate is known, zero
1606 * is an acceptable value.
1607 */
1608 public KeySet(Strength strength,
1609 Equivalence<? super K> equivalence,
1610 int expectedSize) {
1611 this.cchm = new CustomConcurrentHashMap<K,K>
1612 (strength.getName(), equivalence,
1613 SELF_STRING, equivalence, expectedSize);
1614 }
1615
1616 /**
1617 * Returns an element equivalent to the given element with
1618 * respect to this set's Equivalence, if such an element
1619 * exists, else adds and returns the given element.
1620 *
1621 * @param e the element
1622 * @return e, or an element equivalent to e
1623 */
1624 public K intern(K e) {
1625 K oldElement = cchm.doPut(e, e, true);
1626 return (oldElement != null) ? oldElement : e;
1627 }
1628
1629 /**
1630 * Returns {@code true} if this set contains an
1631 * element equivalent to the given element with respect
1632 * to this set's Equivalence.
1633 * @param o element whose presence in this set is to be tested
1634 * @return {@code true} if this set contains the specified element
1635 */
1636 public boolean contains(Object o) {
1637 return cchm.containsKey(o);
1638 }
1639
1640 /**
1641 * Returns a <i>weakly consistent iterator</i> over the
1642 * elements in this set, that may reflect some, all or none of
1643 * the changes made to the set after the iterator was created.
1644 *
1645 * @return an Iterator over the elements in this set
1646 */
1647 public Iterator<K> iterator() {
1648 return cchm.keyIterator();
1649 }
1650
1651 /**
1652 * Adds the specified element to this set if there is not
1653 * already an element equivalent to the given element with
1654 * respect to this set's Equivalence.
1655 *
1656 * @param e element to be added to this set
1657 * @return {@code true} if this set did not already contain
1658 * the specified element
1659 */
1660 public boolean add(K e) {
1661 return cchm.doPut(e, e, true) != null;
1662 }
1663
1664 /**
1665 * Removes an element equivalent to the given element with
1666 * respect to this set's Equivalence, if one is present.
1667 *
1668 * @param o object to be removed from this set, if present
1669 * @return {@code true} if the set contained the specified element
1670 */
1671 public boolean remove(Object o) {
1672 return cchm.remove(o) != null;
1673 }
1674
1675 /**
1676 * Returns {@code true} if this set contains no elements.
1677 *
1678 * @return {@code true} if this set contains no elements
1679 */
1680 public boolean isEmpty() {
1681 return cchm.isEmpty();
1682 }
1683
1684 /**
1685 * Returns the number of elements in this set (its cardinality).
1686 *
1687 * @return the number of elements in this set (its cardinality)
1688 */
1689 public int size() {
1690 return cchm.size();
1691 }
1692
1693 /**
1694 * Removes all of the elements from this set.
1695 */
1696 public void clear() {
1697 cchm.clear();
1698 }
1699
1700 /**
1701 * Returns the sum of the hash codes of each element, as
1702 * computed by this set's Equivalence.
1703 * @return the hash code
1704 */
1705 public int hashCode() {
1706 int h = 0;
1707 Iterator<K> i = iterator();
1708 while (i.hasNext())
1709 h += cchm.keyEquivalence.hash(i.next());
1710 return h;
1711 }
1712 }
1713
1714 // Reference queue mechanics for reclaimable nodes
1715
1716 static volatile ReferenceQueue<Object> refQueue;
1717
1718 /**
1719 * Returns a queue that may be used as the ReferenceQueue argument
1720 * to {@link java.lang.ref.Reference} constructors to arrange
1721 * removal of reclaimed nodes from maps via a background thread.
1722 * @return the reference queue associated with the background
1723 * cleanup thread
1724 */
1725 static ReferenceQueue<Object> getReclamationQueue() {
1726 ReferenceQueue<Object> q = refQueue;
1727 if (q != null)
1728 return q;
1729 else
1730 return startReclamation();
1731 }
1732
1733 static synchronized ReferenceQueue<Object> startReclamation() {
1734 ReferenceQueue<Object> q = refQueue;
1735 if (q == null) {
1736 refQueue = q = new ReferenceQueue<Object>();
1737 new ReclamationThread(q).start();
1738 }
1739 return q;
1740 }
1741
1742 static final class ReclamationThread extends Thread {
1743 final ReferenceQueue<Object> queue;
1744 ReclamationThread(ReferenceQueue<Object> q) {
1745 this.queue = q;
1746 setDaemon(true);
1747 }
1748 public void run() {
1749 ReferenceQueue<Object> q = queue;
1750 for (;;) {
1751 try {
1752 Reference<?> r = q.remove();
1753 if (r instanceof Reclaimable)
1754 ((Reclaimable)r).onReclamation();
1755 } catch (InterruptedException e) {
1756 /* ignore */
1757 }
1758 }
1759 }
1760 }
1761
1762 // classes extending Weak/soft refs embedded in reclaimable nodes
1763
1764 static class EmbeddedWeakReference extends WeakReference
1765 implements Reclaimable {
1766 final Reclaimable outer;
1767 EmbeddedWeakReference(Object x, Reclaimable outer) {
1768 super(x, getReclamationQueue());
1769 this.outer = outer;
1770 }
1771 public final void onReclamation() {
1772 clear();
1773 outer.onReclamation();
1774 }
1775 }
1776
1777 static class EmbeddedSoftReference extends SoftReference
1778 implements Reclaimable {
1779 final Reclaimable outer;
1780 EmbeddedSoftReference(Object x, Reclaimable outer) {
1781 super(x, getReclamationQueue());
1782 this.outer = outer;
1783 }
1784 public final void onReclamation() {
1785 clear();
1786 outer.onReclamation();
1787 }
1788 }
1789
1790 // builtin mapping node classes
1791
1792 // Strong Keys
1793
1794 abstract static class StrongKeyNode implements Node {
1795 final Object key;
1796 final int locator;
1797 StrongKeyNode(int locator, Object key) {
1798 this.locator = locator;
1799 this.key = key;
1800 }
1801 public final Object get() { return key; }
1802 public final int getLocator() { return locator; }
1803 }
1804
1805
1806 abstract static class StrongKeySelfValueNode
1807 extends StrongKeyNode {
1808 StrongKeySelfValueNode(int locator, Object key) {
1809 super(locator, key);
1810 }
1811 public final Object getValue() { return key; }
1812 public final void setValue(Object value) { }
1813 public final void onReclamation() { }
1814 }
1815
1816 static final class TerminalStrongKeySelfValueNode
1817 extends StrongKeySelfValueNode {
1818 TerminalStrongKeySelfValueNode(int locator, Object key) {
1819 super(locator, key);
1820 }
1821 public final Node getLinkage() { return null; }
1822 public final void setLinkage(Node linkage) { }
1823 }
1824
1825 static final class LinkedStrongKeySelfValueNode
1826 extends StrongKeySelfValueNode {
1827 volatile Node linkage;
1828 LinkedStrongKeySelfValueNode(int locator, Object key,
1829 Node linkage) {
1830 super(locator, key);
1831 this.linkage = linkage;
1832 }
1833 public final Node getLinkage() { return linkage; }
1834 public final void setLinkage(Node linkage) { this.linkage = linkage; }
1835 }
1836
1837 static final class StrongKeySelfValueNodeFactory
1838 implements NodeFactory, Serializable {
1839 private static final long serialVersionUID = 7249069346764182397L;
1840 public final Node newNode(int locator,
1841 Object key, Object value,
1842 CustomConcurrentHashMap cchm,
1843 Node linkage) {
1844 if (linkage == null)
1845 return new TerminalStrongKeySelfValueNode
1846 (locator, key);
1847 else
1848 return new LinkedStrongKeySelfValueNode
1849 (locator, key, linkage);
1850 }
1851 }
1852
1853 abstract static class StrongKeyStrongValueNode
1854 extends StrongKeyNode {
1855 volatile Object value;
1856 StrongKeyStrongValueNode(int locator, Object key, Object value) {
1857 super(locator, key);
1858 this.value = value;
1859 }
1860 public final Object getValue() { return value; }
1861 public final void setValue(Object value) { this.value = value; }
1862 public final void onReclamation() { }
1863 }
1864
1865 static final class TerminalStrongKeyStrongValueNode
1866 extends StrongKeyStrongValueNode {
1867 TerminalStrongKeyStrongValueNode(int locator,
1868 Object key, Object value) {
1869 super(locator, key, value);
1870 }
1871 public final Node getLinkage() { return null; }
1872 public final void setLinkage(Node linkage) { }
1873 }
1874
1875 static final class LinkedStrongKeyStrongValueNode
1876 extends StrongKeyStrongValueNode {
1877 volatile Node linkage;
1878 LinkedStrongKeyStrongValueNode(int locator,
1879 Object key, Object value,
1880 Node linkage) {
1881 super(locator, key, value);
1882 this.linkage = linkage;
1883 }
1884 public final Node getLinkage() { return linkage; }
1885 public final void setLinkage(Node linkage) { this.linkage = linkage; }
1886 }
1887
1888 static final class StrongKeyStrongValueNodeFactory
1889 implements NodeFactory, Serializable {
1890 private static final long serialVersionUID = 7249069346764182397L;
1891 public final Node newNode(int locator,
1892 Object key, Object value,
1893 CustomConcurrentHashMap cchm,
1894 Node linkage) {
1895 if (linkage == null)
1896 return new TerminalStrongKeyStrongValueNode
1897 (locator, key, value);
1898 else
1899 return new LinkedStrongKeyStrongValueNode
1900 (locator, key, value, linkage);
1901 }
1902 }
1903
1904 // ...
1905
1906 abstract static class StrongKeyIntValueNode
1907 extends StrongKeyNode {
1908 volatile int value;
1909 StrongKeyIntValueNode(int locator, Object key, Object value) {
1910 super(locator, key);
1911 this.value = ((Integer)value).intValue();
1912 }
1913 public final Object getValue() { return Integer.valueOf(value); }
1914 public final void setValue(Object value) {
1915 this.value = ((Integer)value).intValue();
1916 }
1917 public final void onReclamation() { }
1918 }
1919
1920 static final class TerminalStrongKeyIntValueNode
1921 extends StrongKeyIntValueNode {
1922 TerminalStrongKeyIntValueNode(int locator,
1923 Object key, Object value) {
1924 super(locator, key, value);
1925 }
1926 public final Node getLinkage() { return null; }
1927 public final void setLinkage(Node linkage) { }
1928 }
1929
1930 static final class LinkedStrongKeyIntValueNode
1931 extends StrongKeyIntValueNode {
1932 volatile Node linkage;
1933 LinkedStrongKeyIntValueNode(int locator,
1934 Object key, Object value,
1935 Node linkage) {
1936 super(locator, key, value);
1937 this.linkage = linkage;
1938 }
1939 public final Node getLinkage() { return linkage; }
1940 public final void setLinkage(Node linkage) { this.linkage = linkage; }
1941 }
1942
1943 static final class StrongKeyIntValueNodeFactory
1944 implements NodeFactory, Serializable {
1945 private static final long serialVersionUID = 7249069346764182397L;
1946 public final Node newNode(int locator,
1947 Object key, Object value,
1948 CustomConcurrentHashMap cchm,
1949 Node linkage) {
1950 if (linkage == null)
1951 return new TerminalStrongKeyIntValueNode
1952 (locator, key, value);
1953 else
1954 return new LinkedStrongKeyIntValueNode
1955 (locator, key, value, linkage);
1956 }
1957 }
1958
1959 // ...
1960
1961 abstract static class StrongKeyWeakValueNode
1962 extends StrongKeyNode {
1963 volatile EmbeddedWeakReference valueRef;
1964 final CustomConcurrentHashMap cchm;
1965 StrongKeyWeakValueNode(int locator, Object key, Object value,
1966 CustomConcurrentHashMap cchm) {
1967 super(locator, key);
1968 this.cchm = cchm;
1969 if (value != null)
1970 this.valueRef = new EmbeddedWeakReference(value, this);
1971 }
1972 public final void onReclamation() {
1973 cchm.removeIfReclaimed(this);
1974 }
1975 public final Object getValue() {
1976 EmbeddedWeakReference vr = valueRef;
1977 return (vr == null) ? null : vr.get();
1978 }
1979 public final void setValue(Object value) {
1980 if (value == null)
1981 valueRef = null;
1982 else
1983 valueRef = new EmbeddedWeakReference(value, this);
1984 }
1985 }
1986
1987 static final class TerminalStrongKeyWeakValueNode
1988 extends StrongKeyWeakValueNode {
1989 TerminalStrongKeyWeakValueNode(int locator,
1990 Object key, Object value,
1991 CustomConcurrentHashMap cchm) {
1992 super(locator, key, value, cchm);
1993 }
1994 public final Node getLinkage() { return null; }
1995 public final void setLinkage(Node linkage) { }
1996 }
1997
1998 static final class LinkedStrongKeyWeakValueNode
1999 extends StrongKeyWeakValueNode {
2000 volatile Node linkage;
2001 LinkedStrongKeyWeakValueNode(int locator,
2002 Object key, Object value,
2003 CustomConcurrentHashMap cchm,
2004 Node linkage) {
2005 super(locator, key, value, cchm);
2006 this.linkage = linkage;
2007 }
2008 public final Node getLinkage() { return linkage; }
2009 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2010 }
2011
2012 static final class StrongKeyWeakValueNodeFactory
2013 implements NodeFactory, Serializable {
2014 private static final long serialVersionUID = 7249069346764182397L;
2015 public final Node newNode(int locator,
2016 Object key, Object value,
2017 CustomConcurrentHashMap cchm,
2018 Node linkage) {
2019 if (linkage == null)
2020 return new TerminalStrongKeyWeakValueNode
2021 (locator, key, value, cchm);
2022 else
2023 return new LinkedStrongKeyWeakValueNode
2024 (locator, key, value, cchm, linkage);
2025 }
2026 }
2027
2028
2029 abstract static class StrongKeySoftValueNode
2030 extends StrongKeyNode {
2031 volatile EmbeddedSoftReference valueRef;
2032 final CustomConcurrentHashMap cchm;
2033 StrongKeySoftValueNode(int locator, Object key, Object value,
2034 CustomConcurrentHashMap cchm) {
2035 super(locator, key);
2036 this.cchm = cchm;
2037 if (value != null)
2038 this.valueRef = new EmbeddedSoftReference(value, this);
2039 }
2040 public final void onReclamation() {
2041 cchm.removeIfReclaimed(this);
2042 }
2043 public final Object getValue() {
2044 EmbeddedSoftReference vr = valueRef;
2045 return (vr == null) ? null : vr.get();
2046 }
2047 public final void setValue(Object value) {
2048 if (value == null)
2049 valueRef = null;
2050 else
2051 valueRef = new EmbeddedSoftReference(value, this);
2052 }
2053 }
2054
2055 static final class TerminalStrongKeySoftValueNode
2056 extends StrongKeySoftValueNode {
2057 TerminalStrongKeySoftValueNode(int locator,
2058 Object key, Object value,
2059 CustomConcurrentHashMap cchm) {
2060 super(locator, key, value, cchm);
2061 }
2062 public final Node getLinkage() { return null; }
2063 public final void setLinkage(Node linkage) { }
2064 }
2065
2066 static final class LinkedStrongKeySoftValueNode
2067 extends StrongKeySoftValueNode {
2068 volatile Node linkage;
2069 LinkedStrongKeySoftValueNode(int locator,
2070 Object key, Object value,
2071 CustomConcurrentHashMap cchm,
2072 Node linkage) {
2073 super(locator, key, value, cchm);
2074 this.linkage = linkage;
2075 }
2076 public final Node getLinkage() { return linkage; }
2077 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2078 }
2079
2080 static final class StrongKeySoftValueNodeFactory
2081 implements NodeFactory, Serializable {
2082 private static final long serialVersionUID = 7249069346764182397L;
2083 public final Node newNode(int locator,
2084 Object key, Object value,
2085 CustomConcurrentHashMap cchm,
2086 Node linkage) {
2087 if (linkage == null)
2088 return new TerminalStrongKeySoftValueNode
2089 (locator, key, value, cchm);
2090 else
2091 return new LinkedStrongKeySoftValueNode
2092 (locator, key, value, cchm, linkage);
2093 }
2094 }
2095
2096 // Weak keys
2097
2098 abstract static class WeakKeyNode extends WeakReference
2099 implements Node {
2100 final int locator;
2101 final CustomConcurrentHashMap cchm;
2102 WeakKeyNode(int locator, Object key, CustomConcurrentHashMap cchm) {
2103 super(key, getReclamationQueue());
2104 this.locator = locator;
2105 this.cchm = cchm;
2106 }
2107 public final int getLocator() { return locator; }
2108 public final void onReclamation() {
2109 clear();
2110 cchm.removeIfReclaimed(this);
2111 }
2112 }
2113
2114 abstract static class WeakKeySelfValueNode
2115 extends WeakKeyNode {
2116 WeakKeySelfValueNode(int locator, Object key,
2117 CustomConcurrentHashMap cchm) {
2118 super(locator, key, cchm);
2119 }
2120 public final Object getValue() { return get(); }
2121 public final void setValue(Object value) { }
2122 }
2123
2124 static final class TerminalWeakKeySelfValueNode
2125 extends WeakKeySelfValueNode {
2126 TerminalWeakKeySelfValueNode(int locator, Object key,
2127 CustomConcurrentHashMap cchm) {
2128 super(locator, key, cchm);
2129 }
2130 public final Node getLinkage() { return null; }
2131 public final void setLinkage(Node linkage) { }
2132 }
2133
2134 static final class LinkedWeakKeySelfValueNode
2135 extends WeakKeySelfValueNode {
2136 volatile Node linkage;
2137 LinkedWeakKeySelfValueNode(int locator, Object key,
2138 CustomConcurrentHashMap cchm,
2139 Node linkage) {
2140 super(locator, key, cchm);
2141 this.linkage = linkage;
2142 }
2143 public final Node getLinkage() { return linkage; }
2144 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2145 }
2146
2147 static final class WeakKeySelfValueNodeFactory
2148 implements NodeFactory, Serializable {
2149 private static final long serialVersionUID = 7249069346764182397L;
2150 public final Node newNode(int locator,
2151 Object key, Object value,
2152 CustomConcurrentHashMap cchm,
2153 Node linkage) {
2154 if (linkage == null)
2155 return new TerminalWeakKeySelfValueNode
2156 (locator, key, cchm);
2157 else
2158 return new LinkedWeakKeySelfValueNode
2159 (locator, key, cchm, linkage);
2160 }
2161 }
2162
2163
2164 abstract static class WeakKeyStrongValueNode
2165 extends WeakKeyNode {
2166 volatile Object value;
2167 WeakKeyStrongValueNode(int locator, Object key, Object value,
2168 CustomConcurrentHashMap cchm) {
2169 super(locator, key, cchm);
2170 this.value = value;
2171 }
2172 public final Object getValue() { return value; }
2173 public final void setValue(Object value) { this.value = value; }
2174 }
2175
2176 static final class TerminalWeakKeyStrongValueNode
2177 extends WeakKeyStrongValueNode {
2178 TerminalWeakKeyStrongValueNode(int locator,
2179 Object key, Object value,
2180 CustomConcurrentHashMap cchm) {
2181 super(locator, key, value, cchm);
2182 }
2183 public final Node getLinkage() { return null; }
2184 public final void setLinkage(Node linkage) { }
2185 }
2186
2187 static final class LinkedWeakKeyStrongValueNode
2188 extends WeakKeyStrongValueNode {
2189 volatile Node linkage;
2190 LinkedWeakKeyStrongValueNode(int locator,
2191 Object key, Object value,
2192 CustomConcurrentHashMap cchm,
2193 Node linkage) {
2194 super(locator, key, value, cchm);
2195 this.linkage = linkage;
2196 }
2197 public final Node getLinkage() { return linkage; }
2198 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2199 }
2200
2201 static final class WeakKeyStrongValueNodeFactory
2202 implements NodeFactory, Serializable {
2203 private static final long serialVersionUID = 7249069346764182397L;
2204 public final Node newNode(int locator,
2205 Object key, Object value,
2206 CustomConcurrentHashMap cchm,
2207 Node linkage) {
2208 if (linkage == null)
2209 return new TerminalWeakKeyStrongValueNode
2210 (locator, key, value, cchm);
2211 else
2212 return new LinkedWeakKeyStrongValueNode
2213 (locator, key, value, cchm, linkage);
2214 }
2215 }
2216
2217 abstract static class WeakKeyIntValueNode
2218 extends WeakKeyNode {
2219 volatile int value;
2220 WeakKeyIntValueNode(int locator, Object key, Object value,
2221 CustomConcurrentHashMap cchm) {
2222 super(locator, key, cchm);
2223 this.value = ((Integer)value).intValue();
2224 }
2225 public final Object getValue() { return Integer.valueOf(value); }
2226 public final void setValue(Object value) {
2227 this.value = ((Integer)value).intValue();
2228 }
2229 }
2230
2231 static final class TerminalWeakKeyIntValueNode
2232 extends WeakKeyIntValueNode {
2233 TerminalWeakKeyIntValueNode(int locator,
2234 Object key, Object value,
2235 CustomConcurrentHashMap cchm) {
2236 super(locator, key, value, cchm);
2237 }
2238 public final Node getLinkage() { return null; }
2239 public final void setLinkage(Node linkage) { }
2240 }
2241
2242 static final class LinkedWeakKeyIntValueNode
2243 extends WeakKeyIntValueNode {
2244 volatile Node linkage;
2245 LinkedWeakKeyIntValueNode(int locator,
2246 Object key, Object value,
2247 CustomConcurrentHashMap cchm,
2248 Node linkage) {
2249 super(locator, key, value, cchm);
2250 this.linkage = linkage;
2251 }
2252 public final Node getLinkage() { return linkage; }
2253 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2254 }
2255
2256 static final class WeakKeyIntValueNodeFactory
2257 implements NodeFactory, Serializable {
2258 private static final long serialVersionUID = 7249069346764182397L;
2259 public final Node newNode(int locator,
2260 Object key, Object value,
2261 CustomConcurrentHashMap cchm,
2262 Node linkage) {
2263 if (linkage == null)
2264 return new TerminalWeakKeyIntValueNode
2265 (locator, key, value, cchm);
2266 else
2267 return new LinkedWeakKeyIntValueNode
2268 (locator, key, value, cchm, linkage);
2269 }
2270 }
2271
2272 abstract static class WeakKeyWeakValueNode
2273 extends WeakKeyNode {
2274 volatile EmbeddedWeakReference valueRef;
2275 WeakKeyWeakValueNode(int locator, Object key, Object value,
2276 CustomConcurrentHashMap cchm) {
2277 super(locator, key, cchm);
2278 if (value != null)
2279 this.valueRef = new EmbeddedWeakReference(value, this);
2280 }
2281 public final Object getValue() {
2282 EmbeddedWeakReference vr = valueRef;
2283 return (vr == null) ? null : vr.get();
2284 }
2285 public final void setValue(Object value) {
2286 if (value == null)
2287 valueRef = null;
2288 else
2289 valueRef = new EmbeddedWeakReference(value, this);
2290 }
2291 }
2292
2293 static final class TerminalWeakKeyWeakValueNode
2294 extends WeakKeyWeakValueNode {
2295 TerminalWeakKeyWeakValueNode(int locator,
2296 Object key, Object value,
2297 CustomConcurrentHashMap cchm) {
2298 super(locator, key, value, cchm);
2299 }
2300 public final Node getLinkage() { return null; }
2301 public final void setLinkage(Node linkage) { }
2302 }
2303
2304 static final class LinkedWeakKeyWeakValueNode
2305 extends WeakKeyWeakValueNode {
2306 volatile Node linkage;
2307 LinkedWeakKeyWeakValueNode(int locator,
2308 Object key, Object value,
2309 CustomConcurrentHashMap cchm,
2310 Node linkage) {
2311 super(locator, key, value, cchm);
2312 this.linkage = linkage;
2313 }
2314 public final Node getLinkage() { return linkage; }
2315 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2316 }
2317
2318 static final class WeakKeyWeakValueNodeFactory
2319 implements NodeFactory, Serializable {
2320 private static final long serialVersionUID = 7249069346764182397L;
2321 public final Node newNode(int locator,
2322 Object key, Object value,
2323 CustomConcurrentHashMap cchm,
2324 Node linkage) {
2325 if (linkage == null)
2326 return new TerminalWeakKeyWeakValueNode
2327 (locator, key, value, cchm);
2328 else
2329 return new LinkedWeakKeyWeakValueNode
2330 (locator, key, value, cchm, linkage);
2331 }
2332 }
2333
2334
2335 abstract static class WeakKeySoftValueNode
2336 extends WeakKeyNode {
2337 volatile EmbeddedSoftReference valueRef;
2338 WeakKeySoftValueNode(int locator, Object key, Object value,
2339 CustomConcurrentHashMap cchm) {
2340 super(locator, key, cchm);
2341 if (value != null)
2342 this.valueRef = new EmbeddedSoftReference(value, this);
2343 }
2344 public final Object getValue() {
2345 EmbeddedSoftReference vr = valueRef;
2346 return (vr == null) ? null : vr.get();
2347 }
2348 public final void setValue(Object value) {
2349 if (value == null)
2350 valueRef = null;
2351 else
2352 valueRef = new EmbeddedSoftReference(value, this);
2353 }
2354 }
2355
2356 static final class TerminalWeakKeySoftValueNode
2357 extends WeakKeySoftValueNode {
2358 TerminalWeakKeySoftValueNode(int locator,
2359 Object key, Object value,
2360 CustomConcurrentHashMap cchm) {
2361 super(locator, key, value, cchm);
2362 }
2363 public final Node getLinkage() { return null; }
2364 public final void setLinkage(Node linkage) { }
2365 }
2366
2367 static final class LinkedWeakKeySoftValueNode
2368 extends WeakKeySoftValueNode {
2369 volatile Node linkage;
2370 LinkedWeakKeySoftValueNode(int locator,
2371 Object key, Object value,
2372 CustomConcurrentHashMap cchm,
2373 Node linkage) {
2374 super(locator, key, value, cchm);
2375 this.linkage = linkage;
2376 }
2377 public final Node getLinkage() { return linkage; }
2378 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2379 }
2380
2381 static final class WeakKeySoftValueNodeFactory
2382 implements NodeFactory, Serializable {
2383 private static final long serialVersionUID = 7249069346764182397L;
2384 public final Node newNode(int locator,
2385 Object key, Object value,
2386 CustomConcurrentHashMap cchm,
2387 Node linkage) {
2388 if (linkage == null)
2389 return new TerminalWeakKeySoftValueNode
2390 (locator, key, value, cchm);
2391 else
2392 return new LinkedWeakKeySoftValueNode
2393 (locator, key, value, cchm, linkage);
2394 }
2395 }
2396
2397 // Soft keys
2398
2399 abstract static class SoftKeyNode extends SoftReference
2400 implements Node {
2401 final int locator;
2402 final CustomConcurrentHashMap cchm;
2403 SoftKeyNode(int locator, Object key, CustomConcurrentHashMap cchm) {
2404 super(key, getReclamationQueue());
2405 this.locator = locator;
2406 this.cchm = cchm;
2407 }
2408 public final int getLocator() { return locator; }
2409 public final void onReclamation() {
2410 clear();
2411 cchm.removeIfReclaimed(this);
2412 }
2413 }
2414
2415 abstract static class SoftKeySelfValueNode
2416 extends SoftKeyNode {
2417 SoftKeySelfValueNode(int locator, Object key,
2418 CustomConcurrentHashMap cchm) {
2419 super(locator, key, cchm);
2420 }
2421 public final Object getValue() { return get(); }
2422 public final void setValue(Object value) { }
2423 }
2424
2425 static final class TerminalSoftKeySelfValueNode
2426 extends SoftKeySelfValueNode {
2427 TerminalSoftKeySelfValueNode(int locator, Object key,
2428 CustomConcurrentHashMap cchm) {
2429 super(locator, key, cchm);
2430 }
2431 public final Node getLinkage() { return null; }
2432 public final void setLinkage(Node linkage) { }
2433 }
2434
2435 static final class LinkedSoftKeySelfValueNode
2436 extends SoftKeySelfValueNode {
2437 volatile Node linkage;
2438 LinkedSoftKeySelfValueNode(int locator, Object key,
2439 CustomConcurrentHashMap cchm,
2440 Node linkage) {
2441 super(locator, key, cchm);
2442 this.linkage = linkage;
2443 }
2444 public final Node getLinkage() { return linkage; }
2445 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2446 }
2447
2448 static final class SoftKeySelfValueNodeFactory
2449 implements NodeFactory, Serializable {
2450 private static final long serialVersionUID = 7249069346764182397L;
2451 public final Node newNode(int locator,
2452 Object key, Object value,
2453 CustomConcurrentHashMap cchm,
2454 Node linkage) {
2455 if (linkage == null)
2456 return new TerminalSoftKeySelfValueNode
2457 (locator, key, cchm);
2458 else
2459 return new LinkedSoftKeySelfValueNode
2460 (locator, key, cchm, linkage);
2461 }
2462 }
2463
2464
2465 abstract static class SoftKeyStrongValueNode
2466 extends SoftKeyNode {
2467 volatile Object value;
2468 SoftKeyStrongValueNode(int locator, Object key, Object value,
2469 CustomConcurrentHashMap cchm) {
2470 super(locator, key, cchm);
2471 this.value = value;
2472 }
2473 public final Object getValue() { return value; }
2474 public final void setValue(Object value) { this.value = value; }
2475 }
2476
2477 static final class TerminalSoftKeyStrongValueNode
2478 extends SoftKeyStrongValueNode {
2479 TerminalSoftKeyStrongValueNode(int locator,
2480 Object key, Object value,
2481 CustomConcurrentHashMap cchm) {
2482 super(locator, key, value, cchm);
2483 }
2484 public final Node getLinkage() { return null; }
2485 public final void setLinkage(Node linkage) { }
2486 }
2487
2488 static final class LinkedSoftKeyStrongValueNode
2489 extends SoftKeyStrongValueNode {
2490 volatile Node linkage;
2491 LinkedSoftKeyStrongValueNode(int locator,
2492 Object key, Object value,
2493 CustomConcurrentHashMap cchm,
2494 Node linkage) {
2495 super(locator, key, value, cchm);
2496 this.linkage = linkage;
2497 }
2498 public final Node getLinkage() { return linkage; }
2499 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2500 }
2501
2502 static final class SoftKeyStrongValueNodeFactory
2503 implements NodeFactory, Serializable {
2504 private static final long serialVersionUID = 7249069346764182397L;
2505 public final Node newNode(int locator,
2506 Object key, Object value,
2507 CustomConcurrentHashMap cchm,
2508 Node linkage) {
2509 if (linkage == null)
2510 return new TerminalSoftKeyStrongValueNode
2511 (locator, key, value, cchm);
2512 else
2513 return new LinkedSoftKeyStrongValueNode
2514 (locator, key, value, cchm, linkage);
2515 }
2516 }
2517
2518 abstract static class SoftKeyIntValueNode
2519 extends SoftKeyNode {
2520 volatile int value;
2521 SoftKeyIntValueNode(int locator, Object key, Object value,
2522 CustomConcurrentHashMap cchm) {
2523 super(locator, key, cchm);
2524 this.value = ((Integer)value).intValue();
2525 }
2526 public final Object getValue() { return Integer.valueOf(value); }
2527 public final void setValue(Object value) {
2528 this.value = ((Integer)value).intValue();
2529 }
2530 }
2531
2532 static final class TerminalSoftKeyIntValueNode
2533 extends SoftKeyIntValueNode {
2534 TerminalSoftKeyIntValueNode(int locator,
2535 Object key, Object value,
2536 CustomConcurrentHashMap cchm) {
2537 super(locator, key, value, cchm);
2538 }
2539 public final Node getLinkage() { return null; }
2540 public final void setLinkage(Node linkage) { }
2541 }
2542
2543 static final class LinkedSoftKeyIntValueNode
2544 extends SoftKeyIntValueNode {
2545 volatile Node linkage;
2546 LinkedSoftKeyIntValueNode(int locator,
2547 Object key, Object value,
2548 CustomConcurrentHashMap cchm,
2549 Node linkage) {
2550 super(locator, key, value, cchm);
2551 this.linkage = linkage;
2552 }
2553 public final Node getLinkage() { return linkage; }
2554 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2555 }
2556
2557 static final class SoftKeyIntValueNodeFactory
2558 implements NodeFactory, Serializable {
2559 private static final long serialVersionUID = 7249069346764182397L;
2560 public final Node newNode(int locator,
2561 Object key, Object value,
2562 CustomConcurrentHashMap cchm,
2563 Node linkage) {
2564 if (linkage == null)
2565 return new TerminalSoftKeyIntValueNode
2566 (locator, key, value, cchm);
2567 else
2568 return new LinkedSoftKeyIntValueNode
2569 (locator, key, value, cchm, linkage);
2570 }
2571 }
2572
2573 abstract static class SoftKeyWeakValueNode
2574 extends SoftKeyNode {
2575 volatile EmbeddedWeakReference valueRef;
2576 SoftKeyWeakValueNode(int locator, Object key, Object value,
2577 CustomConcurrentHashMap cchm) {
2578 super(locator, key, cchm);
2579 if (value != null)
2580 this.valueRef = new EmbeddedWeakReference(value, this);
2581 }
2582 public final Object getValue() {
2583 EmbeddedWeakReference vr = valueRef;
2584 return (vr == null) ? null : vr.get();
2585 }
2586 public final void setValue(Object value) {
2587 if (value == null)
2588 valueRef = null;
2589 else
2590 valueRef = new EmbeddedWeakReference(value, this);
2591 }
2592 }
2593
2594 static final class TerminalSoftKeyWeakValueNode
2595 extends SoftKeyWeakValueNode {
2596 TerminalSoftKeyWeakValueNode(int locator,
2597 Object key, Object value,
2598 CustomConcurrentHashMap cchm) {
2599 super(locator, key, value, cchm);
2600 }
2601 public final Node getLinkage() { return null; }
2602 public final void setLinkage(Node linkage) { }
2603 }
2604
2605 static final class LinkedSoftKeyWeakValueNode
2606 extends SoftKeyWeakValueNode {
2607 volatile Node linkage;
2608 LinkedSoftKeyWeakValueNode(int locator,
2609 Object key, Object value,
2610 CustomConcurrentHashMap cchm,
2611 Node linkage) {
2612 super(locator, key, value, cchm);
2613 this.linkage = linkage;
2614 }
2615 public final Node getLinkage() { return linkage; }
2616 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2617 }
2618
2619 static final class SoftKeyWeakValueNodeFactory
2620 implements NodeFactory, Serializable {
2621 private static final long serialVersionUID = 7249069346764182397L;
2622 public final Node newNode(int locator,
2623 Object key, Object value,
2624 CustomConcurrentHashMap cchm,
2625 Node linkage) {
2626 if (linkage == null)
2627 return new TerminalSoftKeyWeakValueNode
2628 (locator, key, value, cchm);
2629 else
2630 return new LinkedSoftKeyWeakValueNode
2631 (locator, key, value, cchm, linkage);
2632 }
2633 }
2634
2635
2636 abstract static class SoftKeySoftValueNode
2637 extends SoftKeyNode {
2638 volatile EmbeddedSoftReference valueRef;
2639 SoftKeySoftValueNode(int locator, Object key, Object value,
2640 CustomConcurrentHashMap cchm) {
2641 super(locator, key, cchm);
2642 if (value != null)
2643 this.valueRef = new EmbeddedSoftReference(value, this);
2644 }
2645 public final Object getValue() {
2646 EmbeddedSoftReference vr = valueRef;
2647 return (vr == null) ? null : vr.get();
2648 }
2649 public final void setValue(Object value) {
2650 if (value == null)
2651 valueRef = null;
2652 else
2653 valueRef = new EmbeddedSoftReference(value, this);
2654 }
2655 }
2656
2657 static final class TerminalSoftKeySoftValueNode
2658 extends SoftKeySoftValueNode {
2659 TerminalSoftKeySoftValueNode(int locator,
2660 Object key, Object value,
2661 CustomConcurrentHashMap cchm) {
2662 super(locator, key, value, cchm);
2663 }
2664 public final Node getLinkage() { return null; }
2665 public final void setLinkage(Node linkage) { }
2666 }
2667
2668 static final class LinkedSoftKeySoftValueNode
2669 extends SoftKeySoftValueNode {
2670 volatile Node linkage;
2671 LinkedSoftKeySoftValueNode(int locator,
2672 Object key, Object value,
2673 CustomConcurrentHashMap cchm,
2674 Node linkage) {
2675 super(locator, key, value, cchm);
2676 this.linkage = linkage;
2677 }
2678 public final Node getLinkage() { return linkage; }
2679 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2680 }
2681
2682 static final class SoftKeySoftValueNodeFactory
2683 implements NodeFactory, Serializable {
2684 private static final long serialVersionUID = 7249069346764182397L;
2685 public final Node newNode(int locator,
2686 Object key, Object value,
2687 CustomConcurrentHashMap cchm,
2688 Node linkage) {
2689 if (linkage == null)
2690 return new TerminalSoftKeySoftValueNode
2691 (locator, key, value, cchm);
2692 else
2693 return new LinkedSoftKeySoftValueNode
2694 (locator, key, value, cchm, linkage);
2695 }
2696 }
2697
2698 abstract static class IntKeyNode implements Node {
2699 final int key;
2700 IntKeyNode(int locator, Object key) {
2701 this.key = ((Integer)key).intValue();
2702 }
2703 public final Object get() { return Integer.valueOf(key); }
2704 public final int getLocator() { return spreadHash(key); }
2705 }
2706
2707
2708 abstract static class IntKeySelfValueNode
2709 extends IntKeyNode {
2710 IntKeySelfValueNode(int locator, Object key) {
2711 super(locator, key);
2712 }
2713 public final Object getValue() { return Integer.valueOf(key); }
2714 public final void setValue(Object value) { }
2715 public final void onReclamation() { }
2716 }
2717
2718 static final class TerminalIntKeySelfValueNode
2719 extends IntKeySelfValueNode {
2720 TerminalIntKeySelfValueNode(int locator, Object key) {
2721 super(locator, key);
2722 }
2723 public final Node getLinkage() { return null; }
2724 public final void setLinkage(Node linkage) { }
2725 }
2726
2727 static final class LinkedIntKeySelfValueNode
2728 extends IntKeySelfValueNode {
2729 volatile Node linkage;
2730 LinkedIntKeySelfValueNode(int locator, Object key,
2731 Node linkage) {
2732 super(locator, key);
2733 this.linkage = linkage;
2734 }
2735 public final Node getLinkage() { return linkage; }
2736 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2737 }
2738
2739 static final class IntKeySelfValueNodeFactory
2740 implements NodeFactory, Serializable {
2741 private static final long serialVersionUID = 7249069346764182397L;
2742 public final Node newNode(int locator,
2743 Object key, Object value,
2744 CustomConcurrentHashMap cchm,
2745 Node linkage) {
2746 if (linkage == null)
2747 return new TerminalIntKeySelfValueNode
2748 (locator, key);
2749 else
2750 return new LinkedIntKeySelfValueNode
2751 (locator, key, linkage);
2752 }
2753 }
2754
2755 abstract static class IntKeyStrongValueNode
2756 extends IntKeyNode {
2757 volatile Object value;
2758 IntKeyStrongValueNode(int locator, Object key, Object value) {
2759 super(locator, key);
2760 this.value = value;
2761 }
2762 public final Object getValue() { return value; }
2763 public final void setValue(Object value) { this.value = value; }
2764 public final void onReclamation() { }
2765 }
2766
2767 static final class TerminalIntKeyStrongValueNode
2768 extends IntKeyStrongValueNode {
2769 TerminalIntKeyStrongValueNode(int locator,
2770 Object key, Object value) {
2771 super(locator, key, value);
2772 }
2773 public final Node getLinkage() { return null; }
2774 public final void setLinkage(Node linkage) { }
2775 }
2776
2777 static final class LinkedIntKeyStrongValueNode
2778 extends IntKeyStrongValueNode {
2779 volatile Node linkage;
2780 LinkedIntKeyStrongValueNode(int locator,
2781 Object key, Object value,
2782 Node linkage) {
2783 super(locator, key, value);
2784 this.linkage = linkage;
2785 }
2786 public final Node getLinkage() { return linkage; }
2787 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2788 }
2789
2790 static final class IntKeyStrongValueNodeFactory
2791 implements NodeFactory, Serializable {
2792 private static final long serialVersionUID = 7249069346764182397L;
2793 public final Node newNode(int locator,
2794 Object key, Object value,
2795 CustomConcurrentHashMap cchm,
2796 Node linkage) {
2797 if (linkage == null)
2798 return new TerminalIntKeyStrongValueNode
2799 (locator, key, value);
2800 else
2801 return new LinkedIntKeyStrongValueNode
2802 (locator, key, value, linkage);
2803 }
2804 }
2805
2806 abstract static class IntKeyIntValueNode
2807 extends IntKeyNode {
2808 volatile int value;
2809 IntKeyIntValueNode(int locator, Object key, Object value) {
2810 super(locator, key);
2811 this.value = ((Integer)value).intValue();
2812 }
2813 public final Object getValue() { return Integer.valueOf(value); }
2814 public final void setValue(Object value) {
2815 this.value = ((Integer)value).intValue();
2816 }
2817 public final void onReclamation() { }
2818 }
2819
2820 static final class TerminalIntKeyIntValueNode
2821 extends IntKeyIntValueNode {
2822 TerminalIntKeyIntValueNode(int locator,
2823 Object key, Object value) {
2824 super(locator, key, value);
2825 }
2826 public final Node getLinkage() { return null; }
2827 public final void setLinkage(Node linkage) { }
2828 }
2829
2830 static final class LinkedIntKeyIntValueNode
2831 extends IntKeyIntValueNode {
2832 volatile Node linkage;
2833 LinkedIntKeyIntValueNode(int locator,
2834 Object key, Object value,
2835 Node linkage) {
2836 super(locator, key, value);
2837 this.linkage = linkage;
2838 }
2839 public final Node getLinkage() { return linkage; }
2840 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2841 }
2842
2843 static final class IntKeyIntValueNodeFactory
2844 implements NodeFactory, Serializable {
2845 private static final long serialVersionUID = 7249069346764182397L;
2846 public final Node newNode(int locator,
2847 Object key, Object value,
2848 CustomConcurrentHashMap cchm,
2849 Node linkage) {
2850 if (linkage == null)
2851 return new TerminalIntKeyIntValueNode
2852 (locator, key, value);
2853 else
2854 return new LinkedIntKeyIntValueNode
2855 (locator, key, value, linkage);
2856 }
2857 }
2858
2859 abstract static class IntKeyWeakValueNode
2860 extends IntKeyNode {
2861 volatile EmbeddedWeakReference valueRef;
2862 final CustomConcurrentHashMap cchm;
2863 IntKeyWeakValueNode(int locator, Object key, Object value,
2864 CustomConcurrentHashMap cchm) {
2865 super(locator, key);
2866 this.cchm = cchm;
2867 if (value != null)
2868 this.valueRef = new EmbeddedWeakReference(value, this);
2869 }
2870 public final void onReclamation() {
2871 cchm.removeIfReclaimed(this);
2872 }
2873 public final Object getValue() {
2874 EmbeddedWeakReference vr = valueRef;
2875 return (vr == null) ? null : vr.get();
2876 }
2877 public final void setValue(Object value) {
2878 if (value == null)
2879 valueRef = null;
2880 else
2881 valueRef = new EmbeddedWeakReference(value, this);
2882 }
2883 }
2884
2885 static final class TerminalIntKeyWeakValueNode
2886 extends IntKeyWeakValueNode {
2887 TerminalIntKeyWeakValueNode(int locator,
2888 Object key, Object value,
2889 CustomConcurrentHashMap cchm) {
2890 super(locator, key, value, cchm);
2891 }
2892 public final Node getLinkage() { return null; }
2893 public final void setLinkage(Node linkage) { }
2894 }
2895
2896 static final class LinkedIntKeyWeakValueNode
2897 extends IntKeyWeakValueNode {
2898 volatile Node linkage;
2899 LinkedIntKeyWeakValueNode(int locator,
2900 Object key, Object value,
2901 CustomConcurrentHashMap cchm,
2902 Node linkage) {
2903 super(locator, key, value, cchm);
2904 this.linkage = linkage;
2905 }
2906 public final Node getLinkage() { return linkage; }
2907 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2908 }
2909
2910 static final class IntKeyWeakValueNodeFactory
2911 implements NodeFactory, Serializable {
2912 private static final long serialVersionUID = 7249069346764182397L;
2913 public final Node newNode(int locator,
2914 Object key, Object value,
2915 CustomConcurrentHashMap cchm,
2916 Node linkage) {
2917 if (linkage == null)
2918 return new TerminalIntKeyWeakValueNode
2919 (locator, key, value, cchm);
2920 else
2921 return new LinkedIntKeyWeakValueNode
2922 (locator, key, value, cchm, linkage);
2923 }
2924 }
2925
2926
2927 abstract static class IntKeySoftValueNode
2928 extends IntKeyNode {
2929 volatile EmbeddedSoftReference valueRef;
2930 final CustomConcurrentHashMap cchm;
2931 IntKeySoftValueNode(int locator, Object key, Object value,
2932 CustomConcurrentHashMap cchm) {
2933 super(locator, key);
2934 this.cchm = cchm;
2935 if (value != null)
2936 this.valueRef = new EmbeddedSoftReference(value, this);
2937 }
2938 public final void onReclamation() {
2939 cchm.removeIfReclaimed(this);
2940 }
2941 public final Object getValue() {
2942 EmbeddedSoftReference vr = valueRef;
2943 return (vr == null) ? null : vr.get();
2944 }
2945 public final void setValue(Object value) {
2946 if (value == null)
2947 valueRef = null;
2948 else
2949 valueRef = new EmbeddedSoftReference(value, this);
2950 }
2951 }
2952
2953 static final class TerminalIntKeySoftValueNode
2954 extends IntKeySoftValueNode {
2955 TerminalIntKeySoftValueNode(int locator,
2956 Object key, Object value,
2957 CustomConcurrentHashMap cchm) {
2958 super(locator, key, value, cchm);
2959 }
2960 public final Node getLinkage() { return null; }
2961 public final void setLinkage(Node linkage) { }
2962 }
2963
2964 static final class LinkedIntKeySoftValueNode
2965 extends IntKeySoftValueNode {
2966 volatile Node linkage;
2967 LinkedIntKeySoftValueNode(int locator,
2968 Object key, Object value,
2969 CustomConcurrentHashMap cchm,
2970 Node linkage) {
2971 super(locator, key, value, cchm);
2972 this.linkage = linkage;
2973 }
2974 public final Node getLinkage() { return linkage; }
2975 public final void setLinkage(Node linkage) { this.linkage = linkage; }
2976 }
2977
2978 static final class IntKeySoftValueNodeFactory
2979 implements NodeFactory, Serializable {
2980 private static final long serialVersionUID = 7249069346764182397L;
2981 public final Node newNode(int locator,
2982 Object key, Object value,
2983 CustomConcurrentHashMap cchm,
2984 Node linkage) {
2985 if (linkage == null)
2986 return new TerminalIntKeySoftValueNode
2987 (locator, key, value, cchm);
2988 else
2989 return new LinkedIntKeySoftValueNode
2990 (locator, key, value, cchm, linkage);
2991 }
2992 }
2993
2994
2995
2996 // Temporary Unsafe mechanics for preliminary release
2997
2998 static final Unsafe UNSAFE;
2999 static final long tableBase;
3000 static final int tableShift;
3001 static final long segmentsBase;
3002 static final int segmentsShift;
3003
3004 static {
3005 try {
3006 UNSAFE = getUnsafe();
3007 tableBase = UNSAFE.arrayBaseOffset(Node[].class);
3008 int scale = UNSAFE.arrayIndexScale(Node[].class);
3009 if ((scale & (scale - 1)) != 0)
3010 throw new Error("data type scale not a power of two");
3011 tableShift = 31 - Integer.numberOfLeadingZeros(scale);
3012 segmentsBase = UNSAFE.arrayBaseOffset(Segment[].class);
3013 scale = UNSAFE.arrayIndexScale(Segment[].class);
3014 if ((scale & (scale - 1)) != 0)
3015 throw new Error("data type scale not a power of two");
3016 segmentsShift = 31 - Integer.numberOfLeadingZeros(scale);
3017 } catch (Throwable e) {
3018 throw new RuntimeException("Could not initialize intrinsics", e);
3019 }
3020 }
3021
3022 // Fenced store into segment table array. Unneeded when we have Fences
3023 static final void storeNode(Node[] table,
3024 int i, Node r) {
3025 long nodeOffset = ((long) i << tableShift) + tableBase;
3026 UNSAFE.putOrderedObject(table, nodeOffset, r);
3027 }
3028
3029 static final void storeSegment(Segment[] segs,
3030 int i, Segment s) {
3031 long segmentOffset = ((long) i << segmentsShift) + segmentsBase;
3032 UNSAFE.putOrderedObject(segs, segmentOffset, s);
3033 }
3034
3035 /**
3036 * Returns a sun.misc.Unsafe. Suitable for use in a 3rd party package.
3037 * Replace with a simple call to Unsafe.getUnsafe when integrating
3038 * into a jdk.
3039 *
3040 * @return a sun.misc.Unsafe
3041 */
3042 private static sun.misc.Unsafe getUnsafe() {
3043 try {
3044 return sun.misc.Unsafe.getUnsafe();
3045 } catch (SecurityException tryReflectionInstead) {}
3046 try {
3047 return java.security.AccessController.doPrivileged
3048 (new java.security.PrivilegedExceptionAction<sun.misc.Unsafe>() {
3049 public sun.misc.Unsafe run() throws Exception {
3050 Class<sun.misc.Unsafe> k = sun.misc.Unsafe.class;
3051 for (java.lang.reflect.Field f : k.getDeclaredFields()) {
3052 f.setAccessible(true);
3053 Object x = f.get(null);
3054 if (k.isInstance(x))
3055 return k.cast(x);
3056 }
3057 throw new NoSuchFieldError("the Unsafe");
3058 }});
3059 } catch (java.security.PrivilegedActionException e) {
3060 throw new RuntimeException("Could not initialize intrinsics",
3061 e.getCause());
3062 }
3063 }
3064 }