ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.1
Committed: Mon Apr 6 10:30:04 2009 UTC (15 years, 1 month ago) by dl
Branch: MAIN
Log Message:
Initial checkin for discussion

File Contents

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