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

# User Rev Content
1 dl 1.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