ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.5
Committed: Tue Oct 6 19:02:48 2009 UTC (14 years, 7 months ago) by jsr166
Branch: MAIN
Changes since 1.4: +4 -2 lines
Log Message:
6888149: AtomicReferenceArray causes SIGSEGV -> SEGV_MAPERR error

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