ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.10
Committed: Fri Feb 12 12:38:25 2010 UTC (14 years, 3 months ago) by dl
Branch: MAIN
Changes since 1.9: +2 -2 lines
Log Message:
Ensure reclamation queue initialization

File Contents

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