ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.37
Committed: Sun Sep 13 16:28:13 2015 UTC (8 years, 7 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.36: +13 -13 lines
Log Message:
consistent style for <li> tags, removing </li> end tags

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