ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.3
Committed: Wed Jul 22 17:50:01 2009 UTC (14 years, 9 months ago) by jsr166
Branch: MAIN
Changes since 1.2: +244 -245 lines
Log Message:
whitespace

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