ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.19
Committed: Tue Oct 25 18:46:37 2011 UTC (12 years, 6 months ago) by jsr166
Branch: MAIN
Changes since 1.18: +2 -2 lines
Log Message:
tidy javadoc of readObject/writeObject methods

File Contents

# Content
1 /*
2 * Written by Doug Lea with assistance from members of JCP JSR-166
3 * Expert Group and released to the public domain, as explained at
4 * http://creativecommons.org/publicdomain/zero/1.0/
5 */
6
7 package extra166y;
8 import java.lang.ref.*;
9 import java.lang.reflect.*;
10 import java.io.*;
11 import java.util.*;
12 import java.util.concurrent.*;
13 import java.util.concurrent.locks.*;
14 import sun.misc.Unsafe;
15
16 /**
17 * A {@link java.util.ConcurrentMap} supporting user-defined
18 * equivalence comparisons, soft, weak, or strong keys and values, and
19 * user-supplied computational methods for setting and updating
20 * values. In particular: <ul>
21 *
22 * <li> Identity-based, Equality-based or User-definable {@link
23 * Equivalence}-based comparisons controlling membership.
24 *
25 * <li> {@linkplain SoftReference Soft}, {@linkplain
26 * WeakReference weak} or strong (regular) keys and values.
27 *
28 * <li> User-definable <code>MappingFunctions</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 (non-null) key
240 * @return a value, or null if none
241 */
242 V map(K key);
243 }
244
245 /**
246 * A function computing a new mapping from the given key and its
247 * current value to a new value, or <code>null</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 * non-null, 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(),
1418 e.getValue());
1419 }
1420 public int size() {
1421 return CustomConcurrentHashMap.this.size();
1422 }
1423 public boolean isEmpty() {
1424 return CustomConcurrentHashMap.this.isEmpty();
1425 }
1426 public void clear() {
1427 CustomConcurrentHashMap.this.clear();
1428 }
1429 }
1430
1431 /**
1432 * Returns a {@link Set} view of the keys contained in this map.
1433 * The set is backed by the map, so changes to the map are
1434 * reflected in the set, and vice-versa. The set supports element
1435 * removal, which removes the corresponding mapping from this map,
1436 * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
1437 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
1438 * operations. It does not support the <tt>add</tt> or
1439 * <tt>addAll</tt> operations.
1440 *
1441 * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
1442 * that will never throw {@link ConcurrentModificationException},
1443 * and guarantees to traverse elements as they existed upon
1444 * construction of the iterator, and may (but is not guaranteed to)
1445 * reflect any modifications subsequent to construction.
1446 */
1447 public Set<K> keySet() {
1448 Set<K> ks = keySet;
1449 return (ks != null) ? ks : (keySet = new KeySetView());
1450 }
1451
1452 /**
1453 * Returns a {@link Collection} view of the values contained in this map.
1454 * The collection is backed by the map, so changes to the map are
1455 * reflected in the collection, and vice-versa. The collection
1456 * supports element removal, which removes the corresponding
1457 * mapping from this map, via the <tt>Iterator.remove</tt>,
1458 * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
1459 * <tt>retainAll</tt>, and <tt>clear</tt> operations. It does not
1460 * support the <tt>add</tt> or <tt>addAll</tt> operations.
1461 *
1462 * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
1463 * that will never throw {@link ConcurrentModificationException},
1464 * and guarantees to traverse elements as they existed upon
1465 * construction of the iterator, and may (but is not guaranteed to)
1466 * reflect any modifications subsequent to construction.
1467 */
1468 public Collection<V> values() {
1469 Collection<V> vs = values;
1470 return (vs != null) ? vs : (values = new Values());
1471 }
1472
1473 /**
1474 * Returns a {@link Set} view of the mappings contained in this map.
1475 * The set is backed by the map, so changes to the map are
1476 * reflected in the set, and vice-versa. The set supports element
1477 * removal, which removes the corresponding mapping from the map,
1478 * via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
1479 * <tt>removeAll</tt>, <tt>retainAll</tt>, and <tt>clear</tt>
1480 * operations. It does not support the <tt>add</tt> or
1481 * <tt>addAll</tt> operations.
1482 *
1483 * <p>The view's <tt>iterator</tt> is a "weakly consistent" iterator
1484 * that will never throw {@link ConcurrentModificationException},
1485 * and guarantees to traverse elements as they existed upon
1486 * construction of the iterator, and may (but is not guaranteed to)
1487 * reflect any modifications subsequent to construction.
1488 */
1489 public Set<Map.Entry<K,V>> entrySet() {
1490 Set<Map.Entry<K,V>> es = entrySet;
1491 return (es != null) ? es : (entrySet = new EntrySet());
1492 }
1493
1494 // overridden AbstractMap methods
1495
1496 /**
1497 * Compares the specified object with this map for equality.
1498 * Returns <tt>true</tt> if the given object is also a map of the
1499 * same size, holding keys that are equal using this Map's key
1500 * Equivalence, and which map to values that are equal according
1501 * to this Map's value equivalence.
1502 *
1503 * @param o object to be compared for equality with this map
1504 * @return <tt>true</tt> if the specified object is equal to this map
1505 */
1506 public boolean equals(Object o) {
1507 if (o == this)
1508 return true;
1509
1510 if (!(o instanceof Map))
1511 return false;
1512 Map<K,V> m = (Map<K,V>) o;
1513 if (m.size() != size())
1514 return false;
1515
1516 try {
1517 Iterator<Entry<K,V>> i = entrySet().iterator();
1518 while (i.hasNext()) {
1519 Entry<K,V> e = i.next();
1520 K key = e.getKey();
1521 V value = e.getValue();
1522 if (value != null) {
1523 V mv = m.get(key);
1524 if (mv == null)
1525 return false;
1526 if (!valueEquivalence.equal(mv, value))
1527 return false;
1528 }
1529 }
1530 } catch (ClassCastException unused) {
1531 return false;
1532 } catch (NullPointerException unused) {
1533 return false;
1534 }
1535
1536 return true;
1537 }
1538
1539 /**
1540 * Returns the sum of the hash codes of each entry in this map's
1541 * <tt>entrySet()</tt> view, which in turn are the hash codes
1542 * computed using key and value Equivalences for this Map.
1543 * @return the hash code
1544 */
1545 public int hashCode() {
1546 int h = 0;
1547 Iterator<Entry<K,V>> i = entrySet().iterator();
1548 while (i.hasNext())
1549 h += i.next().hashCode();
1550 return h;
1551 }
1552
1553 /**
1554 * Saves the state of the instance to a stream (i.e., serializes it).
1555 *
1556 * @param s the stream
1557 * @serialData
1558 * the key (Object) and value (Object)
1559 * for each key-value mapping, followed by a null pair.
1560 * The key-value mappings are emitted in no particular order.
1561 */
1562 private void writeObject(java.io.ObjectOutputStream s) throws IOException {
1563 s.defaultWriteObject();
1564 for (Map.Entry<K,V> e : entrySet()) {
1565 s.writeObject(e.getKey());
1566 s.writeObject(e.getValue());
1567 }
1568 s.writeObject(null);
1569 s.writeObject(null);
1570 }
1571
1572 /**
1573 * Reconstitutes the instance from a stream (that is, deserializes it).
1574 * @param s the stream
1575 */
1576 private void readObject(java.io.ObjectInputStream s)
1577 throws IOException, ClassNotFoundException {
1578 s.defaultReadObject();
1579 this.segments = (Segment[])(new Segment[NSEGMENTS]);
1580 for (;;) {
1581 K key = (K) s.readObject();
1582 V value = (V) s.readObject();
1583 if (key == null)
1584 break;
1585 put(key, value);
1586 }
1587 }
1588
1589 /**
1590 * A hash-based set with properties identical to those of
1591 * <code>Collections.newSetFromMap</code> applied to a
1592 * <code>CustomConcurrentHashMap</code>, but possibly more
1593 * space-efficient. The set does not permit null elements. The
1594 * set is serializable; however, serializing a set that uses soft
1595 * or weak references can give unpredictable results.
1596 */
1597 public static class KeySet<K> extends AbstractSet<K>
1598 implements Set<K>, Serializable {
1599
1600 final CustomConcurrentHashMap<K,K> cchm;
1601
1602 /**
1603 * Creates a set with the given parameters
1604 * @param strength the strength of elements
1605 * @param equivalence the Equivalence to use
1606 * @param expectedSize an estimate of the number of elements
1607 * that will be held in the set. If no estimate is known, zero
1608 * is an acceptable value.
1609 */
1610 public KeySet(Strength strength,
1611 Equivalence<? super K> equivalence,
1612 int expectedSize) {
1613 this.cchm = new CustomConcurrentHashMap<K,K>
1614 (strength.getName(), equivalence,
1615 SELF_STRING, equivalence, expectedSize);
1616 }
1617
1618 /**
1619 * Returns an element equivalent to the given element with
1620 * respect to this set's Equivalence, if such an element
1621 * exists, else adds and returns the given element.
1622 *
1623 * @param e the element
1624 * @return e, or an element equivalent to e.
1625 */
1626 public K intern(K e) {
1627 K oldElement = cchm.doPut(e, e, true);
1628 return (oldElement != null) ? oldElement : e;
1629 }
1630
1631 /**
1632 * Returns <tt>true</tt> if this set contains an
1633 * element equivalent to the given element with respect
1634 * to this set's Equivalence.
1635 * @param o element whose presence in this set is to be tested
1636 * @return <tt>true</tt> if this set contains the specified element
1637 */
1638 public boolean contains(Object o) {
1639 return cchm.containsKey(o);
1640 }
1641
1642 /**
1643 * Returns a <i>weakly consistent iterator</i> over the
1644 * elements in this set, that may reflect some, all or none of
1645 * the changes made to the set after the iterator was created.
1646 *
1647 * @return an Iterator over the elements in this set
1648 */
1649 public Iterator<K> iterator() {
1650 return cchm.keyIterator();
1651 }
1652
1653 /**
1654 * Adds the specified element to this set if there is not
1655 * already an element equivalent to the given element with
1656 * respect to this set's Equivalence.
1657 *
1658 * @param e element to be added to this set
1659 * @return <tt>true</tt> if this set did not already contain
1660 * the specified element
1661 */
1662 public boolean add(K e) {
1663 return cchm.doPut(e, e, true) != null;
1664 }
1665
1666 /**
1667 * Removes an element equivalent to the given element with
1668 * respect to this set's Equivalence, if one is present.
1669 *
1670 * @param o object to be removed from this set, if present
1671 * @return <tt>true</tt> if the set contained the specified element
1672 */
1673 public boolean remove(Object o) {
1674 return cchm.remove(o) != null;
1675 }
1676
1677 /**
1678 * Returns <tt>true</tt> if this set contains no elements.
1679 *
1680 * @return <tt>true</tt> if this set contains no elements
1681 */
1682 public boolean isEmpty() {
1683 return cchm.isEmpty();
1684 }
1685
1686 /**
1687 * Returns the number of elements in this set (its cardinality).
1688 *
1689 * @return the number of elements in this set (its cardinality)
1690 */
1691 public int size() {
1692 return cchm.size();
1693 }
1694
1695 /**
1696 * Removes all of the elements from this set.
1697 */
1698 public void clear() {
1699 cchm.clear();
1700 }
1701
1702 /**
1703 * Returns the sum of the hash codes of each element, as
1704 * computed by this set's Equivalence.
1705 * @return the hash code
1706 */
1707 public int hashCode() {
1708 int h = 0;
1709 Iterator<K> i = iterator();
1710 while (i.hasNext())
1711 h += cchm.keyEquivalence.hash(i.next());
1712 return h;
1713 }
1714 }
1715
1716 // Reference queue mechanics for reclaimable nodes
1717
1718 static volatile ReferenceQueue<Object> refQueue;
1719
1720 /**
1721 * Returns a queue that may be used as the ReferenceQueue argument
1722 * to {@link java.lang.ref.Reference} constructors to arrange
1723 * removal of reclaimed nodes from maps via a background thread.
1724 * @return the reference queue associated with the background
1725 * cleanup thread.
1726 */
1727 static ReferenceQueue<Object> getReclamationQueue() {
1728 ReferenceQueue<Object> q = refQueue;
1729 if (q != null)
1730 return q;
1731 else
1732 return startReclamation();
1733 }
1734
1735 static synchronized ReferenceQueue<Object> startReclamation() {
1736 ReferenceQueue<Object> q = refQueue;
1737 if (q == null) {
1738 refQueue = q = new ReferenceQueue<Object>();
1739 new ReclamationThread(q).start();
1740 }
1741 return q;
1742 }
1743
1744 static final class ReclamationThread extends Thread {
1745 final ReferenceQueue<Object> queue;
1746 ReclamationThread(ReferenceQueue<Object> q) {
1747 this.queue = q;
1748 setDaemon(true);
1749 }
1750 public void run() {
1751 ReferenceQueue<Object> q = queue;
1752 for (;;) {
1753 try {
1754 Reference<?> r = q.remove();
1755 if (r instanceof Reclaimable)
1756 ((Reclaimable)r).onReclamation();
1757 } catch (InterruptedException e) {
1758 /* ignore */
1759 }
1760 }
1761 }
1762 }
1763
1764 // classes extending Weak/soft refs embedded in reclaimable nodes
1765
1766 static class EmbeddedWeakReference extends WeakReference
1767 implements Reclaimable {
1768 final Reclaimable outer;
1769 EmbeddedWeakReference(Object x, Reclaimable outer) {
1770 super(x, getReclamationQueue());
1771 this.outer = outer;
1772 }
1773 public final void onReclamation() {
1774 clear();
1775 outer.onReclamation();
1776 }
1777 }
1778
1779 static class EmbeddedSoftReference extends SoftReference
1780 implements Reclaimable {
1781 final Reclaimable outer;
1782 EmbeddedSoftReference(Object x, Reclaimable outer) {
1783 super(x, getReclamationQueue());
1784 this.outer = outer;
1785 }
1786 public final void onReclamation() {
1787 clear();
1788 outer.onReclamation();
1789 }
1790 }
1791
1792 // builtin mapping node classes
1793
1794 // Strong Keys
1795
1796 static abstract class StrongKeyNode implements Node {
1797 final Object key;
1798 final int locator;
1799 StrongKeyNode(int locator, Object key) {
1800 this.locator = locator;
1801 this.key = key;
1802 }
1803 public final Object get() { return key; }
1804 public final int getLocator() { return locator; }
1805 }
1806
1807
1808 static abstract class StrongKeySelfValueNode
1809 extends StrongKeyNode {
1810 StrongKeySelfValueNode(int locator, Object key) {
1811 super(locator, key);
1812 }
1813 public final Object getValue() { return key; }
1814 public final void setValue(Object value) { }
1815 public final void onReclamation() { }
1816 }
1817
1818 static final class TerminalStrongKeySelfValueNode
1819 extends StrongKeySelfValueNode {
1820 TerminalStrongKeySelfValueNode(int locator, Object key) {
1821 super(locator, key);
1822 }
1823 public final Node getLinkage() { return null; }
1824 public final void setLinkage(Node r) { }
1825 }
1826
1827 static final class LinkedStrongKeySelfValueNode
1828 extends StrongKeySelfValueNode {
1829 volatile Node linkage;
1830 LinkedStrongKeySelfValueNode(int locator, Object key,
1831 Node linkage) {
1832 super(locator, key);
1833 this.linkage = linkage;
1834 }
1835 public final Node getLinkage() { return linkage; }
1836 public final void setLinkage(Node r) { linkage = r; }
1837 }
1838
1839 static final class StrongKeySelfValueNodeFactory
1840 implements NodeFactory, Serializable {
1841 private static final long serialVersionUID = 7249069346764182397L;
1842 public final Node newNode(int locator,
1843 Object key, Object value,
1844 CustomConcurrentHashMap cchm,
1845 Node linkage) {
1846 if (linkage == null)
1847 return new TerminalStrongKeySelfValueNode
1848 (locator, key);
1849 else
1850 return new LinkedStrongKeySelfValueNode
1851 (locator, key, linkage);
1852 }
1853 }
1854
1855 static abstract class StrongKeyStrongValueNode
1856 extends StrongKeyNode {
1857 volatile Object value;
1858 StrongKeyStrongValueNode(int locator, Object key, Object value) {
1859 super(locator, key);
1860 this.value = value;
1861 }
1862 public final Object getValue() { return value; }
1863 public final void setValue(Object value) { this.value = value; }
1864 public final void onReclamation() { }
1865 }
1866
1867 static final class TerminalStrongKeyStrongValueNode
1868 extends StrongKeyStrongValueNode {
1869 TerminalStrongKeyStrongValueNode(int locator,
1870 Object key, Object value) {
1871 super(locator, key, value);
1872 }
1873 public final Node getLinkage() { return null; }
1874 public final void setLinkage(Node r) { }
1875 }
1876
1877 static final class LinkedStrongKeyStrongValueNode
1878 extends StrongKeyStrongValueNode {
1879 volatile Node linkage;
1880 LinkedStrongKeyStrongValueNode(int locator,
1881 Object key, Object value,
1882 Node linkage) {
1883 super(locator, key, value);
1884 this.linkage = linkage;
1885 }
1886 public final Node getLinkage() { return linkage; }
1887 public final void setLinkage(Node r) { linkage = r; }
1888 }
1889
1890 static final class StrongKeyStrongValueNodeFactory
1891 implements NodeFactory, Serializable {
1892 private static final long serialVersionUID = 7249069346764182397L;
1893 public final Node newNode(int locator,
1894 Object key, Object value,
1895 CustomConcurrentHashMap cchm,
1896 Node linkage) {
1897 if (linkage == null)
1898 return new TerminalStrongKeyStrongValueNode
1899 (locator, key, value);
1900 else
1901 return new LinkedStrongKeyStrongValueNode
1902 (locator, key, value, linkage);
1903 }
1904 }
1905
1906 // ...
1907
1908 static abstract class StrongKeyIntValueNode
1909 extends StrongKeyNode {
1910 volatile int value;
1911 StrongKeyIntValueNode(int locator, Object key, Object value) {
1912 super(locator, key);
1913 this.value = ((Integer)value).intValue();
1914 }
1915 public final Object getValue() { return Integer.valueOf(value); }
1916 public final void setValue(Object value) {
1917 this.value = ((Integer)value).intValue();
1918 }
1919 public final void onReclamation() { }
1920 }
1921
1922 static final class TerminalStrongKeyIntValueNode
1923 extends StrongKeyIntValueNode {
1924 TerminalStrongKeyIntValueNode(int locator,
1925 Object key, Object value) {
1926 super(locator, key, value);
1927 }
1928 public final Node getLinkage() { return null; }
1929 public final void setLinkage(Node r) { }
1930 }
1931
1932 static final class LinkedStrongKeyIntValueNode
1933 extends StrongKeyIntValueNode {
1934 volatile Node linkage;
1935 LinkedStrongKeyIntValueNode(int locator,
1936 Object key, Object value,
1937 Node linkage) {
1938 super(locator, key, value);
1939 this.linkage = linkage;
1940 }
1941 public final Node getLinkage() { return linkage; }
1942 public final void setLinkage(Node r) { linkage = r; }
1943 }
1944
1945 static final class StrongKeyIntValueNodeFactory
1946 implements NodeFactory, Serializable {
1947 private static final long serialVersionUID = 7249069346764182397L;
1948 public final Node newNode(int locator,
1949 Object key, Object value,
1950 CustomConcurrentHashMap cchm,
1951 Node linkage) {
1952 if (linkage == null)
1953 return new TerminalStrongKeyIntValueNode
1954 (locator, key, value);
1955 else
1956 return new LinkedStrongKeyIntValueNode
1957 (locator, key, value, linkage);
1958 }
1959 }
1960
1961 // ...
1962
1963 static abstract class StrongKeyWeakValueNode
1964 extends StrongKeyNode {
1965 volatile EmbeddedWeakReference valueRef;
1966 final CustomConcurrentHashMap cchm;
1967 StrongKeyWeakValueNode(int locator, Object key, Object value,
1968 CustomConcurrentHashMap cchm) {
1969 super(locator, key);
1970 this.cchm = cchm;
1971 if (value != null)
1972 this.valueRef = new EmbeddedWeakReference(value, this);
1973 }
1974 public final void onReclamation() {
1975 cchm.removeIfReclaimed(this);
1976 }
1977 public final Object getValue() {
1978 EmbeddedWeakReference vr = valueRef;
1979 return (vr == null) ? null : vr.get();
1980 }
1981 public final void setValue(Object value) {
1982 if (value == null)
1983 valueRef = null;
1984 else
1985 valueRef = new EmbeddedWeakReference(value, this);
1986 }
1987 }
1988
1989 static final class TerminalStrongKeyWeakValueNode
1990 extends StrongKeyWeakValueNode {
1991 TerminalStrongKeyWeakValueNode(int locator,
1992 Object key, Object value,
1993 CustomConcurrentHashMap cchm) {
1994 super(locator, key, value, cchm);
1995 }
1996 public final Node getLinkage() { return null; }
1997 public final void setLinkage(Node r) { }
1998 }
1999
2000 static final class LinkedStrongKeyWeakValueNode
2001 extends StrongKeyWeakValueNode {
2002 volatile Node linkage;
2003 LinkedStrongKeyWeakValueNode(int locator,
2004 Object key, Object value,
2005 CustomConcurrentHashMap cchm,
2006 Node linkage) {
2007 super(locator, key, value, cchm);
2008 this.linkage = linkage;
2009 }
2010 public final Node getLinkage() { return linkage; }
2011 public final void setLinkage(Node r) { linkage = r; }
2012 }
2013
2014 static final class StrongKeyWeakValueNodeFactory
2015 implements NodeFactory, Serializable {
2016 private static final long serialVersionUID = 7249069346764182397L;
2017 public final Node newNode(int locator,
2018 Object key, Object value,
2019 CustomConcurrentHashMap cchm,
2020 Node linkage) {
2021 if (linkage == null)
2022 return new TerminalStrongKeyWeakValueNode
2023 (locator, key, value, cchm);
2024 else
2025 return new LinkedStrongKeyWeakValueNode
2026 (locator, key, value, cchm, linkage);
2027 }
2028 }
2029
2030
2031 static abstract class StrongKeySoftValueNode
2032 extends StrongKeyNode {
2033 volatile EmbeddedSoftReference valueRef;
2034 final CustomConcurrentHashMap cchm;
2035 StrongKeySoftValueNode(int locator, Object key, Object value,
2036 CustomConcurrentHashMap cchm) {
2037 super(locator, key);
2038 this.cchm = cchm;
2039 if (value != null)
2040 this.valueRef = new EmbeddedSoftReference(value, this);
2041 }
2042 public final void onReclamation() {
2043 cchm.removeIfReclaimed(this);
2044 }
2045 public final Object getValue() {
2046 EmbeddedSoftReference vr = valueRef;
2047 return (vr == null) ? null : vr.get();
2048 }
2049 public final void setValue(Object value) {
2050 if (value == null)
2051 valueRef = null;
2052 else
2053 valueRef = new EmbeddedSoftReference(value, this);
2054 }
2055 }
2056
2057 static final class TerminalStrongKeySoftValueNode
2058 extends StrongKeySoftValueNode {
2059 TerminalStrongKeySoftValueNode(int locator,
2060 Object key, Object value,
2061 CustomConcurrentHashMap cchm) {
2062 super(locator, key, value, cchm);
2063 }
2064 public final Node getLinkage() { return null; }
2065 public final void setLinkage(Node r) { }
2066 }
2067
2068 static final class LinkedStrongKeySoftValueNode
2069 extends StrongKeySoftValueNode {
2070 volatile Node linkage;
2071 LinkedStrongKeySoftValueNode(int locator,
2072 Object key, Object value,
2073 CustomConcurrentHashMap cchm,
2074 Node linkage) {
2075 super(locator, key, value, cchm);
2076 this.linkage = linkage;
2077 }
2078 public final Node getLinkage() { return linkage; }
2079 public final void setLinkage(Node r) { linkage = r; }
2080 }
2081
2082 static final class StrongKeySoftValueNodeFactory
2083 implements NodeFactory, Serializable {
2084 private static final long serialVersionUID = 7249069346764182397L;
2085 public final Node newNode(int locator,
2086 Object key, Object value,
2087 CustomConcurrentHashMap cchm,
2088 Node linkage) {
2089 if (linkage == null)
2090 return new TerminalStrongKeySoftValueNode
2091 (locator, key, value, cchm);
2092 else
2093 return new LinkedStrongKeySoftValueNode
2094 (locator, key, value, cchm, linkage);
2095 }
2096 }
2097
2098 // Weak keys
2099
2100 static abstract class WeakKeyNode extends WeakReference
2101 implements Node {
2102 final int locator;
2103 final CustomConcurrentHashMap cchm;
2104 WeakKeyNode(int locator, Object key, CustomConcurrentHashMap cchm) {
2105 super(key, getReclamationQueue());
2106 this.locator = locator;
2107 this.cchm = cchm;
2108 }
2109 public final int getLocator() { return locator; }
2110 public final void onReclamation() {
2111 clear();
2112 cchm.removeIfReclaimed(this);
2113 }
2114 }
2115
2116 static abstract class WeakKeySelfValueNode
2117 extends WeakKeyNode {
2118 WeakKeySelfValueNode(int locator, Object key,
2119 CustomConcurrentHashMap cchm) {
2120 super(locator, key, cchm);
2121 }
2122 public final Object getValue() { return get(); }
2123 public final void setValue(Object value) { }
2124 }
2125
2126 static final class TerminalWeakKeySelfValueNode
2127 extends WeakKeySelfValueNode {
2128 TerminalWeakKeySelfValueNode(int locator, Object key,
2129 CustomConcurrentHashMap cchm) {
2130 super(locator, key, cchm);
2131 }
2132 public final Node getLinkage() { return null; }
2133 public final void setLinkage(Node r) { }
2134 }
2135
2136 static final class LinkedWeakKeySelfValueNode
2137 extends WeakKeySelfValueNode {
2138 volatile Node linkage;
2139 LinkedWeakKeySelfValueNode(int locator, Object key,
2140 CustomConcurrentHashMap cchm,
2141 Node linkage) {
2142 super(locator, key, cchm);
2143 this.linkage = linkage;
2144 }
2145 public final Node getLinkage() { return linkage; }
2146 public final void setLinkage(Node r) { linkage = r; }
2147 }
2148
2149 static final class WeakKeySelfValueNodeFactory
2150 implements NodeFactory, Serializable {
2151 private static final long serialVersionUID = 7249069346764182397L;
2152 public final Node newNode(int locator,
2153 Object key, Object value,
2154 CustomConcurrentHashMap cchm,
2155 Node linkage) {
2156 if (linkage == null)
2157 return new TerminalWeakKeySelfValueNode
2158 (locator, key, cchm);
2159 else
2160 return new LinkedWeakKeySelfValueNode
2161 (locator, key, cchm, linkage);
2162 }
2163 }
2164
2165
2166 static abstract class WeakKeyStrongValueNode
2167 extends WeakKeyNode {
2168 volatile Object value;
2169 WeakKeyStrongValueNode(int locator, Object key, Object value,
2170 CustomConcurrentHashMap cchm) {
2171 super(locator, key, cchm);
2172 this.value = value;
2173 }
2174 public final Object getValue() { return value; }
2175 public final void setValue(Object value) { this.value = value; }
2176 }
2177
2178 static final class TerminalWeakKeyStrongValueNode
2179 extends WeakKeyStrongValueNode {
2180 TerminalWeakKeyStrongValueNode(int locator,
2181 Object key, Object value,
2182 CustomConcurrentHashMap cchm) {
2183 super(locator, key, value, cchm);
2184 }
2185 public final Node getLinkage() { return null; }
2186 public final void setLinkage(Node r) { }
2187 }
2188
2189 static final class LinkedWeakKeyStrongValueNode
2190 extends WeakKeyStrongValueNode {
2191 volatile Node linkage;
2192 LinkedWeakKeyStrongValueNode(int locator,
2193 Object key, Object value,
2194 CustomConcurrentHashMap cchm,
2195 Node linkage) {
2196 super(locator, key, value, cchm);
2197 this.linkage = linkage;
2198 }
2199 public final Node getLinkage() { return linkage; }
2200 public final void setLinkage(Node r) { linkage = r; }
2201 }
2202
2203 static final class WeakKeyStrongValueNodeFactory
2204 implements NodeFactory, Serializable {
2205 private static final long serialVersionUID = 7249069346764182397L;
2206 public final Node newNode(int locator,
2207 Object key, Object value,
2208 CustomConcurrentHashMap cchm,
2209 Node linkage) {
2210 if (linkage == null)
2211 return new TerminalWeakKeyStrongValueNode
2212 (locator, key, value, cchm);
2213 else
2214 return new LinkedWeakKeyStrongValueNode
2215 (locator, key, value, cchm, linkage);
2216 }
2217 }
2218
2219 static abstract class WeakKeyIntValueNode
2220 extends WeakKeyNode {
2221 volatile int value;
2222 WeakKeyIntValueNode(int locator, Object key, Object value,
2223 CustomConcurrentHashMap cchm) {
2224 super(locator, key, cchm);
2225 this.value = ((Integer)value).intValue();
2226 }
2227 public final Object getValue() { return Integer.valueOf(value); }
2228 public final void setValue(Object value) {
2229 this.value = ((Integer)value).intValue();
2230 }
2231 }
2232
2233 static final class TerminalWeakKeyIntValueNode
2234 extends WeakKeyIntValueNode {
2235 TerminalWeakKeyIntValueNode(int locator,
2236 Object key, Object value,
2237 CustomConcurrentHashMap cchm) {
2238 super(locator, key, value, cchm);
2239 }
2240 public final Node getLinkage() { return null; }
2241 public final void setLinkage(Node r) { }
2242 }
2243
2244 static final class LinkedWeakKeyIntValueNode
2245 extends WeakKeyIntValueNode {
2246 volatile Node linkage;
2247 LinkedWeakKeyIntValueNode(int locator,
2248 Object key, Object value,
2249 CustomConcurrentHashMap cchm,
2250 Node linkage) {
2251 super(locator, key, value, cchm);
2252 this.linkage = linkage;
2253 }
2254 public final Node getLinkage() { return linkage; }
2255 public final void setLinkage(Node r) { linkage = r; }
2256 }
2257
2258 static final class WeakKeyIntValueNodeFactory
2259 implements NodeFactory, Serializable {
2260 private static final long serialVersionUID = 7249069346764182397L;
2261 public final Node newNode(int locator,
2262 Object key, Object value,
2263 CustomConcurrentHashMap cchm,
2264 Node linkage) {
2265 if (linkage == null)
2266 return new TerminalWeakKeyIntValueNode
2267 (locator, key, value, cchm);
2268 else
2269 return new LinkedWeakKeyIntValueNode
2270 (locator, key, value, cchm, linkage);
2271 }
2272 }
2273
2274 static abstract class WeakKeyWeakValueNode
2275 extends WeakKeyNode {
2276 volatile EmbeddedWeakReference valueRef;
2277 WeakKeyWeakValueNode(int locator, Object key, Object value,
2278 CustomConcurrentHashMap cchm) {
2279 super(locator, key, cchm);
2280 if (value != null)
2281 this.valueRef = new EmbeddedWeakReference(value, this);
2282 }
2283 public final Object getValue() {
2284 EmbeddedWeakReference vr = valueRef;
2285 return (vr == null) ? null : vr.get();
2286 }
2287 public final void setValue(Object value) {
2288 if (value == null)
2289 valueRef = null;
2290 else
2291 valueRef = new EmbeddedWeakReference(value, this);
2292 }
2293 }
2294
2295 static final class TerminalWeakKeyWeakValueNode
2296 extends WeakKeyWeakValueNode {
2297 TerminalWeakKeyWeakValueNode(int locator,
2298 Object key, Object value,
2299 CustomConcurrentHashMap cchm) {
2300 super(locator, key, value, cchm);
2301 }
2302 public final Node getLinkage() { return null; }
2303 public final void setLinkage(Node r) { }
2304 }
2305
2306 static final class LinkedWeakKeyWeakValueNode
2307 extends WeakKeyWeakValueNode {
2308 volatile Node linkage;
2309 LinkedWeakKeyWeakValueNode(int locator,
2310 Object key, Object value,
2311 CustomConcurrentHashMap cchm,
2312 Node linkage) {
2313 super(locator, key, value, cchm);
2314 this.linkage = linkage;
2315 }
2316 public final Node getLinkage() { return linkage; }
2317 public final void setLinkage(Node r) { linkage = r; }
2318 }
2319
2320 static final class WeakKeyWeakValueNodeFactory
2321 implements NodeFactory, Serializable {
2322 private static final long serialVersionUID = 7249069346764182397L;
2323 public final Node newNode(int locator,
2324 Object key, Object value,
2325 CustomConcurrentHashMap cchm,
2326 Node linkage) {
2327 if (linkage == null)
2328 return new TerminalWeakKeyWeakValueNode
2329 (locator, key, value, cchm);
2330 else
2331 return new LinkedWeakKeyWeakValueNode
2332 (locator, key, value, cchm, linkage);
2333 }
2334 }
2335
2336
2337 static abstract class WeakKeySoftValueNode
2338 extends WeakKeyNode {
2339 volatile EmbeddedSoftReference valueRef;
2340 WeakKeySoftValueNode(int locator, Object key, Object value,
2341 CustomConcurrentHashMap cchm) {
2342 super(locator, key, cchm);
2343 if (value != null)
2344 this.valueRef = new EmbeddedSoftReference(value, this);
2345 }
2346 public final Object getValue() {
2347 EmbeddedSoftReference vr = valueRef;
2348 return (vr == null) ? null : vr.get();
2349 }
2350 public final void setValue(Object value) {
2351 if (value == null)
2352 valueRef = null;
2353 else
2354 valueRef = new EmbeddedSoftReference(value, this);
2355 }
2356 }
2357
2358 static final class TerminalWeakKeySoftValueNode
2359 extends WeakKeySoftValueNode {
2360 TerminalWeakKeySoftValueNode(int locator,
2361 Object key, Object value,
2362 CustomConcurrentHashMap cchm) {
2363 super(locator, key, value, cchm);
2364 }
2365 public final Node getLinkage() { return null; }
2366 public final void setLinkage(Node r) { }
2367 }
2368
2369 static final class LinkedWeakKeySoftValueNode
2370 extends WeakKeySoftValueNode {
2371 volatile Node linkage;
2372 LinkedWeakKeySoftValueNode(int locator,
2373 Object key, Object value,
2374 CustomConcurrentHashMap cchm,
2375 Node linkage) {
2376 super(locator, key, value, cchm);
2377 this.linkage = linkage;
2378 }
2379 public final Node getLinkage() { return linkage; }
2380 public final void setLinkage(Node r) { linkage = r; }
2381 }
2382
2383 static final class WeakKeySoftValueNodeFactory
2384 implements NodeFactory, Serializable {
2385 private static final long serialVersionUID = 7249069346764182397L;
2386 public final Node newNode(int locator,
2387 Object key, Object value,
2388 CustomConcurrentHashMap cchm,
2389 Node linkage) {
2390 if (linkage == null)
2391 return new TerminalWeakKeySoftValueNode
2392 (locator, key, value, cchm);
2393 else
2394 return new LinkedWeakKeySoftValueNode
2395 (locator, key, value, cchm, linkage);
2396 }
2397 }
2398
2399 // Soft keys
2400
2401 static abstract class SoftKeyNode extends SoftReference
2402 implements Node {
2403 final int locator;
2404 final CustomConcurrentHashMap cchm;
2405 SoftKeyNode(int locator, Object key, CustomConcurrentHashMap cchm) {
2406 super(key, getReclamationQueue());
2407 this.locator = locator;
2408 this.cchm = cchm;
2409 }
2410 public final int getLocator() { return locator; }
2411 public final void onReclamation() {
2412 clear();
2413 cchm.removeIfReclaimed(this);
2414 }
2415 }
2416
2417 static abstract class SoftKeySelfValueNode
2418 extends SoftKeyNode {
2419 SoftKeySelfValueNode(int locator, Object key,
2420 CustomConcurrentHashMap cchm) {
2421 super(locator, key, cchm);
2422 }
2423 public final Object getValue() { return get(); }
2424 public final void setValue(Object value) { }
2425 }
2426
2427 static final class TerminalSoftKeySelfValueNode
2428 extends SoftKeySelfValueNode {
2429 TerminalSoftKeySelfValueNode(int locator, Object key,
2430 CustomConcurrentHashMap cchm) {
2431 super(locator, key, cchm);
2432 }
2433 public final Node getLinkage() { return null; }
2434 public final void setLinkage(Node r) { }
2435 }
2436
2437 static final class LinkedSoftKeySelfValueNode
2438 extends SoftKeySelfValueNode {
2439 volatile Node linkage;
2440 LinkedSoftKeySelfValueNode(int locator, Object key,
2441 CustomConcurrentHashMap cchm,
2442 Node linkage) {
2443 super(locator, key, cchm);
2444 this.linkage = linkage;
2445 }
2446 public final Node getLinkage() { return linkage; }
2447 public final void setLinkage(Node r) { linkage = r; }
2448 }
2449
2450 static final class SoftKeySelfValueNodeFactory
2451 implements NodeFactory, Serializable {
2452 private static final long serialVersionUID = 7249069346764182397L;
2453 public final Node newNode(int locator,
2454 Object key, Object value,
2455 CustomConcurrentHashMap cchm,
2456 Node linkage) {
2457 if (linkage == null)
2458 return new TerminalSoftKeySelfValueNode
2459 (locator, key, cchm);
2460 else
2461 return new LinkedSoftKeySelfValueNode
2462 (locator, key, cchm, linkage);
2463 }
2464 }
2465
2466
2467 static abstract class SoftKeyStrongValueNode
2468 extends SoftKeyNode {
2469 volatile Object value;
2470 SoftKeyStrongValueNode(int locator, Object key, Object value,
2471 CustomConcurrentHashMap cchm) {
2472 super(locator, key, cchm);
2473 this.value = value;
2474 }
2475 public final Object getValue() { return value; }
2476 public final void setValue(Object value) { this.value = value; }
2477 }
2478
2479 static final class TerminalSoftKeyStrongValueNode
2480 extends SoftKeyStrongValueNode {
2481 TerminalSoftKeyStrongValueNode(int locator,
2482 Object key, Object value,
2483 CustomConcurrentHashMap cchm) {
2484 super(locator, key, value, cchm);
2485 }
2486 public final Node getLinkage() { return null; }
2487 public final void setLinkage(Node r) { }
2488 }
2489
2490 static final class LinkedSoftKeyStrongValueNode
2491 extends SoftKeyStrongValueNode {
2492 volatile Node linkage;
2493 LinkedSoftKeyStrongValueNode(int locator,
2494 Object key, Object value,
2495 CustomConcurrentHashMap cchm,
2496 Node linkage) {
2497 super(locator, key, value, cchm);
2498 this.linkage = linkage;
2499 }
2500 public final Node getLinkage() { return linkage; }
2501 public final void setLinkage(Node r) { linkage = r; }
2502 }
2503
2504 static final class SoftKeyStrongValueNodeFactory
2505 implements NodeFactory, Serializable {
2506 private static final long serialVersionUID = 7249069346764182397L;
2507 public final Node newNode(int locator,
2508 Object key, Object value,
2509 CustomConcurrentHashMap cchm,
2510 Node linkage) {
2511 if (linkage == null)
2512 return new TerminalSoftKeyStrongValueNode
2513 (locator, key, value, cchm);
2514 else
2515 return new LinkedSoftKeyStrongValueNode
2516 (locator, key, value, cchm, linkage);
2517 }
2518 }
2519
2520 static abstract class SoftKeyIntValueNode
2521 extends SoftKeyNode {
2522 volatile int value;
2523 SoftKeyIntValueNode(int locator, Object key, Object value,
2524 CustomConcurrentHashMap cchm) {
2525 super(locator, key, cchm);
2526 this.value = ((Integer)value).intValue();
2527 }
2528 public final Object getValue() { return Integer.valueOf(value); }
2529 public final void setValue(Object value) {
2530 this.value = ((Integer)value).intValue();
2531 }
2532 }
2533
2534 static final class TerminalSoftKeyIntValueNode
2535 extends SoftKeyIntValueNode {
2536 TerminalSoftKeyIntValueNode(int locator,
2537 Object key, Object value,
2538 CustomConcurrentHashMap cchm) {
2539 super(locator, key, value, cchm);
2540 }
2541 public final Node getLinkage() { return null; }
2542 public final void setLinkage(Node r) { }
2543 }
2544
2545 static final class LinkedSoftKeyIntValueNode
2546 extends SoftKeyIntValueNode {
2547 volatile Node linkage;
2548 LinkedSoftKeyIntValueNode(int locator,
2549 Object key, Object value,
2550 CustomConcurrentHashMap cchm,
2551 Node linkage) {
2552 super(locator, key, value, cchm);
2553 this.linkage = linkage;
2554 }
2555 public final Node getLinkage() { return linkage; }
2556 public final void setLinkage(Node r) { linkage = r; }
2557 }
2558
2559 static final class SoftKeyIntValueNodeFactory
2560 implements NodeFactory, Serializable {
2561 private static final long serialVersionUID = 7249069346764182397L;
2562 public final Node newNode(int locator,
2563 Object key, Object value,
2564 CustomConcurrentHashMap cchm,
2565 Node linkage) {
2566 if (linkage == null)
2567 return new TerminalSoftKeyIntValueNode
2568 (locator, key, value, cchm);
2569 else
2570 return new LinkedSoftKeyIntValueNode
2571 (locator, key, value, cchm, linkage);
2572 }
2573 }
2574
2575 static abstract class SoftKeyWeakValueNode
2576 extends SoftKeyNode {
2577 volatile EmbeddedWeakReference valueRef;
2578 SoftKeyWeakValueNode(int locator, Object key, Object value,
2579 CustomConcurrentHashMap cchm) {
2580 super(locator, key, cchm);
2581 if (value != null)
2582 this.valueRef = new EmbeddedWeakReference(value, this);
2583 }
2584 public final Object getValue() {
2585 EmbeddedWeakReference vr = valueRef;
2586 return (vr == null) ? null : vr.get();
2587 }
2588 public final void setValue(Object value) {
2589 if (value == null)
2590 valueRef = null;
2591 else
2592 valueRef = new EmbeddedWeakReference(value, this);
2593 }
2594 }
2595
2596 static final class TerminalSoftKeyWeakValueNode
2597 extends SoftKeyWeakValueNode {
2598 TerminalSoftKeyWeakValueNode(int locator,
2599 Object key, Object value,
2600 CustomConcurrentHashMap cchm) {
2601 super(locator, key, value, cchm);
2602 }
2603 public final Node getLinkage() { return null; }
2604 public final void setLinkage(Node r) { }
2605 }
2606
2607 static final class LinkedSoftKeyWeakValueNode
2608 extends SoftKeyWeakValueNode {
2609 volatile Node linkage;
2610 LinkedSoftKeyWeakValueNode(int locator,
2611 Object key, Object value,
2612 CustomConcurrentHashMap cchm,
2613 Node linkage) {
2614 super(locator, key, value, cchm);
2615 this.linkage = linkage;
2616 }
2617 public final Node getLinkage() { return linkage; }
2618 public final void setLinkage(Node r) { linkage = r; }
2619 }
2620
2621 static final class SoftKeyWeakValueNodeFactory
2622 implements NodeFactory, Serializable {
2623 private static final long serialVersionUID = 7249069346764182397L;
2624 public final Node newNode(int locator,
2625 Object key, Object value,
2626 CustomConcurrentHashMap cchm,
2627 Node linkage) {
2628 if (linkage == null)
2629 return new TerminalSoftKeyWeakValueNode
2630 (locator, key, value, cchm);
2631 else
2632 return new LinkedSoftKeyWeakValueNode
2633 (locator, key, value, cchm, linkage);
2634 }
2635 }
2636
2637
2638 static abstract class SoftKeySoftValueNode
2639 extends SoftKeyNode {
2640 volatile EmbeddedSoftReference valueRef;
2641 SoftKeySoftValueNode(int locator, Object key, Object value,
2642 CustomConcurrentHashMap cchm) {
2643 super(locator, key, cchm);
2644 if (value != null)
2645 this.valueRef = new EmbeddedSoftReference(value, this);
2646 }
2647 public final Object getValue() {
2648 EmbeddedSoftReference vr = valueRef;
2649 return (vr == null) ? null : vr.get();
2650 }
2651 public final void setValue(Object value) {
2652 if (value == null)
2653 valueRef = null;
2654 else
2655 valueRef = new EmbeddedSoftReference(value, this);
2656 }
2657 }
2658
2659 static final class TerminalSoftKeySoftValueNode
2660 extends SoftKeySoftValueNode {
2661 TerminalSoftKeySoftValueNode(int locator,
2662 Object key, Object value,
2663 CustomConcurrentHashMap cchm) {
2664 super(locator, key, value, cchm);
2665 }
2666 public final Node getLinkage() { return null; }
2667 public final void setLinkage(Node r) { }
2668 }
2669
2670 static final class LinkedSoftKeySoftValueNode
2671 extends SoftKeySoftValueNode {
2672 volatile Node linkage;
2673 LinkedSoftKeySoftValueNode(int locator,
2674 Object key, Object value,
2675 CustomConcurrentHashMap cchm,
2676 Node linkage) {
2677 super(locator, key, value, cchm);
2678 this.linkage = linkage;
2679 }
2680 public final Node getLinkage() { return linkage; }
2681 public final void setLinkage(Node r) { linkage = r; }
2682 }
2683
2684 static final class SoftKeySoftValueNodeFactory
2685 implements NodeFactory, Serializable {
2686 private static final long serialVersionUID = 7249069346764182397L;
2687 public final Node newNode(int locator,
2688 Object key, Object value,
2689 CustomConcurrentHashMap cchm,
2690 Node linkage) {
2691 if (linkage == null)
2692 return new TerminalSoftKeySoftValueNode
2693 (locator, key, value, cchm);
2694 else
2695 return new LinkedSoftKeySoftValueNode
2696 (locator, key, value, cchm, linkage);
2697 }
2698 }
2699
2700 static abstract class IntKeyNode implements Node {
2701 final int key;
2702 IntKeyNode(int locator, Object key) {
2703 this.key = ((Integer)key).intValue();
2704 }
2705 public final Object get() { return Integer.valueOf(key); }
2706 public final int getLocator() { return spreadHash(key); }
2707 }
2708
2709
2710 static abstract class IntKeySelfValueNode
2711 extends IntKeyNode {
2712 IntKeySelfValueNode(int locator, Object key) {
2713 super(locator, key);
2714 }
2715 public final Object getValue() { return Integer.valueOf(key); }
2716 public final void setValue(Object value) { }
2717 public final void onReclamation() { }
2718 }
2719
2720 static final class TerminalIntKeySelfValueNode
2721 extends IntKeySelfValueNode {
2722 TerminalIntKeySelfValueNode(int locator, Object key) {
2723 super(locator, key);
2724 }
2725 public final Node getLinkage() { return null; }
2726 public final void setLinkage(Node r) { }
2727 }
2728
2729 static final class LinkedIntKeySelfValueNode
2730 extends IntKeySelfValueNode {
2731 volatile Node linkage;
2732 LinkedIntKeySelfValueNode(int locator, Object key,
2733 Node linkage) {
2734 super(locator, key);
2735 this.linkage = linkage;
2736 }
2737 public final Node getLinkage() { return linkage; }
2738 public final void setLinkage(Node r) { linkage = r; }
2739 }
2740
2741 static final class IntKeySelfValueNodeFactory
2742 implements NodeFactory, Serializable {
2743 private static final long serialVersionUID = 7249069346764182397L;
2744 public final Node newNode(int locator,
2745 Object key, Object value,
2746 CustomConcurrentHashMap cchm,
2747 Node linkage) {
2748 if (linkage == null)
2749 return new TerminalIntKeySelfValueNode
2750 (locator, key);
2751 else
2752 return new LinkedIntKeySelfValueNode
2753 (locator, key, linkage);
2754 }
2755 }
2756
2757 static abstract class IntKeyStrongValueNode
2758 extends IntKeyNode {
2759 volatile Object value;
2760 IntKeyStrongValueNode(int locator, Object key, Object value) {
2761 super(locator, key);
2762 this.value = value;
2763 }
2764 public final Object getValue() { return value; }
2765 public final void setValue(Object value) { this.value = value; }
2766 public final void onReclamation() { }
2767 }
2768
2769 static final class TerminalIntKeyStrongValueNode
2770 extends IntKeyStrongValueNode {
2771 TerminalIntKeyStrongValueNode(int locator,
2772 Object key, Object value) {
2773 super(locator, key, value);
2774 }
2775 public final Node getLinkage() { return null; }
2776 public final void setLinkage(Node r) { }
2777 }
2778
2779 static final class LinkedIntKeyStrongValueNode
2780 extends IntKeyStrongValueNode {
2781 volatile Node linkage;
2782 LinkedIntKeyStrongValueNode(int locator,
2783 Object key, Object value,
2784 Node linkage) {
2785 super(locator, key, value);
2786 this.linkage = linkage;
2787 }
2788 public final Node getLinkage() { return linkage; }
2789 public final void setLinkage(Node r) { linkage = r; }
2790 }
2791
2792 static final class IntKeyStrongValueNodeFactory
2793 implements NodeFactory, Serializable {
2794 private static final long serialVersionUID = 7249069346764182397L;
2795 public final Node newNode(int locator,
2796 Object key, Object value,
2797 CustomConcurrentHashMap cchm,
2798 Node linkage) {
2799 if (linkage == null)
2800 return new TerminalIntKeyStrongValueNode
2801 (locator, key, value);
2802 else
2803 return new LinkedIntKeyStrongValueNode
2804 (locator, key, value, linkage);
2805 }
2806 }
2807
2808 static abstract class IntKeyIntValueNode
2809 extends IntKeyNode {
2810 volatile int value;
2811 IntKeyIntValueNode(int locator, Object key, Object value) {
2812 super(locator, key);
2813 this.value = ((Integer)value).intValue();
2814 }
2815 public final Object getValue() { return Integer.valueOf(value); }
2816 public final void setValue(Object value) {
2817 this.value = ((Integer)value).intValue();
2818 }
2819 public final void onReclamation() { }
2820 }
2821
2822 static final class TerminalIntKeyIntValueNode
2823 extends IntKeyIntValueNode {
2824 TerminalIntKeyIntValueNode(int locator,
2825 Object key, Object value) {
2826 super(locator, key, value);
2827 }
2828 public final Node getLinkage() { return null; }
2829 public final void setLinkage(Node r) { }
2830 }
2831
2832 static final class LinkedIntKeyIntValueNode
2833 extends IntKeyIntValueNode {
2834 volatile Node linkage;
2835 LinkedIntKeyIntValueNode(int locator,
2836 Object key, Object value,
2837 Node linkage) {
2838 super(locator, key, value);
2839 this.linkage = linkage;
2840 }
2841 public final Node getLinkage() { return linkage; }
2842 public final void setLinkage(Node r) { linkage = r; }
2843 }
2844
2845 static final class IntKeyIntValueNodeFactory
2846 implements NodeFactory, Serializable {
2847 private static final long serialVersionUID = 7249069346764182397L;
2848 public final Node newNode(int locator,
2849 Object key, Object value,
2850 CustomConcurrentHashMap cchm,
2851 Node linkage) {
2852 if (linkage == null)
2853 return new TerminalIntKeyIntValueNode
2854 (locator, key, value);
2855 else
2856 return new LinkedIntKeyIntValueNode
2857 (locator, key, value, linkage);
2858 }
2859 }
2860
2861 static abstract class IntKeyWeakValueNode
2862 extends IntKeyNode {
2863 volatile EmbeddedWeakReference valueRef;
2864 final CustomConcurrentHashMap cchm;
2865 IntKeyWeakValueNode(int locator, Object key, Object value,
2866 CustomConcurrentHashMap cchm) {
2867 super(locator, key);
2868 this.cchm = cchm;
2869 if (value != null)
2870 this.valueRef = new EmbeddedWeakReference(value, this);
2871 }
2872 public final void onReclamation() {
2873 cchm.removeIfReclaimed(this);
2874 }
2875 public final Object getValue() {
2876 EmbeddedWeakReference vr = valueRef;
2877 return (vr == null) ? null : vr.get();
2878 }
2879 public final void setValue(Object value) {
2880 if (value == null)
2881 valueRef = null;
2882 else
2883 valueRef = new EmbeddedWeakReference(value, this);
2884 }
2885 }
2886
2887 static final class TerminalIntKeyWeakValueNode
2888 extends IntKeyWeakValueNode {
2889 TerminalIntKeyWeakValueNode(int locator,
2890 Object key, Object value,
2891 CustomConcurrentHashMap cchm) {
2892 super(locator, key, value, cchm);
2893 }
2894 public final Node getLinkage() { return null; }
2895 public final void setLinkage(Node r) { }
2896 }
2897
2898 static final class LinkedIntKeyWeakValueNode
2899 extends IntKeyWeakValueNode {
2900 volatile Node linkage;
2901 LinkedIntKeyWeakValueNode(int locator,
2902 Object key, Object value,
2903 CustomConcurrentHashMap cchm,
2904 Node linkage) {
2905 super(locator, key, value, cchm);
2906 this.linkage = linkage;
2907 }
2908 public final Node getLinkage() { return linkage; }
2909 public final void setLinkage(Node r) { linkage = r; }
2910 }
2911
2912 static final class IntKeyWeakValueNodeFactory
2913 implements NodeFactory, Serializable {
2914 private static final long serialVersionUID = 7249069346764182397L;
2915 public final Node newNode(int locator,
2916 Object key, Object value,
2917 CustomConcurrentHashMap cchm,
2918 Node linkage) {
2919 if (linkage == null)
2920 return new TerminalIntKeyWeakValueNode
2921 (locator, key, value, cchm);
2922 else
2923 return new LinkedIntKeyWeakValueNode
2924 (locator, key, value, cchm, linkage);
2925 }
2926 }
2927
2928
2929 static abstract class IntKeySoftValueNode
2930 extends IntKeyNode {
2931 volatile EmbeddedSoftReference valueRef;
2932 final CustomConcurrentHashMap cchm;
2933 IntKeySoftValueNode(int locator, Object key, Object value,
2934 CustomConcurrentHashMap cchm) {
2935 super(locator, key);
2936 this.cchm = cchm;
2937 if (value != null)
2938 this.valueRef = new EmbeddedSoftReference(value, this);
2939 }
2940 public final void onReclamation() {
2941 cchm.removeIfReclaimed(this);
2942 }
2943 public final Object getValue() {
2944 EmbeddedSoftReference vr = valueRef;
2945 return (vr == null) ? null : vr.get();
2946 }
2947 public final void setValue(Object value) {
2948 if (value == null)
2949 valueRef = null;
2950 else
2951 valueRef = new EmbeddedSoftReference(value, this);
2952 }
2953 }
2954
2955 static final class TerminalIntKeySoftValueNode
2956 extends IntKeySoftValueNode {
2957 TerminalIntKeySoftValueNode(int locator,
2958 Object key, Object value,
2959 CustomConcurrentHashMap cchm) {
2960 super(locator, key, value, cchm);
2961 }
2962 public final Node getLinkage() { return null; }
2963 public final void setLinkage(Node r) { }
2964 }
2965
2966 static final class LinkedIntKeySoftValueNode
2967 extends IntKeySoftValueNode {
2968 volatile Node linkage;
2969 LinkedIntKeySoftValueNode(int locator,
2970 Object key, Object value,
2971 CustomConcurrentHashMap cchm,
2972 Node linkage) {
2973 super(locator, key, value, cchm);
2974 this.linkage = linkage;
2975 }
2976 public final Node getLinkage() { return linkage; }
2977 public final void setLinkage(Node r) { linkage = r; }
2978 }
2979
2980 static final class IntKeySoftValueNodeFactory
2981 implements NodeFactory, Serializable {
2982 private static final long serialVersionUID = 7249069346764182397L;
2983 public final Node newNode(int locator,
2984 Object key, Object value,
2985 CustomConcurrentHashMap cchm,
2986 Node linkage) {
2987 if (linkage == null)
2988 return new TerminalIntKeySoftValueNode
2989 (locator, key, value, cchm);
2990 else
2991 return new LinkedIntKeySoftValueNode
2992 (locator, key, value, cchm, linkage);
2993 }
2994 }
2995
2996
2997
2998 // Temporary Unsafe mechanics for preliminary release
2999
3000 static final Unsafe UNSAFE;
3001 static final long tableBase;
3002 static final int tableShift;
3003 static final long segmentsBase;
3004 static final int segmentsShift;
3005
3006 private static Unsafe getUnsafe() throws Throwable {
3007 try {
3008 return Unsafe.getUnsafe();
3009 } catch (SecurityException se) {
3010 try {
3011 return java.security.AccessController.doPrivileged
3012 (new java.security.PrivilegedExceptionAction<Unsafe>() {
3013 public Unsafe run() throws Exception {
3014 return getUnsafePrivileged();
3015 }});
3016 } catch (java.security.PrivilegedActionException e) {
3017 throw e.getCause();
3018 }
3019 }
3020 }
3021
3022 private static Unsafe getUnsafePrivileged()
3023 throws NoSuchFieldException, IllegalAccessException {
3024 Field f = Unsafe.class.getDeclaredField("theUnsafe");
3025 f.setAccessible(true);
3026 return (Unsafe) f.get(null);
3027 }
3028
3029 static {
3030 try {
3031 UNSAFE = getUnsafe();
3032 tableBase = UNSAFE.arrayBaseOffset(Node[].class);
3033 int s = UNSAFE.arrayIndexScale(Node[].class);
3034 if ((s & (s-1)) != 0)
3035 throw new Error("data type scale not a power of two");
3036 tableShift = 31 - Integer.numberOfLeadingZeros(s);
3037 segmentsBase = UNSAFE.arrayBaseOffset(Segment[].class);
3038 s = UNSAFE.arrayIndexScale(Segment[].class);
3039 if ((s & (s-1)) != 0)
3040 throw new Error("data type scale not a power of two");
3041 segmentsShift = 31 - Integer.numberOfLeadingZeros(s);
3042 } catch (Throwable e) {
3043 throw new RuntimeException("Could not initialize intrinsics", e);
3044 }
3045 }
3046
3047 // Fenced store into segment table array. Unneeded when we have Fences
3048 static final void storeNode(Node[] table,
3049 int i, Node r) {
3050 long nodeOffset = ((long) i << tableShift) + tableBase;
3051 UNSAFE.putOrderedObject(table, nodeOffset, r);
3052 }
3053
3054 static final void storeSegment(Segment[] segs,
3055 int i, Segment s) {
3056 long segmentOffset = ((long) i << segmentsShift) + segmentsBase;
3057 UNSAFE.putOrderedObject(segs, segmentOffset, s);
3058 }
3059
3060
3061 }