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