ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.3
Committed: Wed Jul 22 17:50:01 2009 UTC (14 years, 9 months ago) by jsr166
Branch: MAIN
Changes since 1.2: +244 -245 lines
Log Message:
whitespace

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 jsr166 1.3 * replace values.
35 dl 1.1 *
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 jsr166 1.3 *
41 dl 1.1 * 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 jsr166 1.3 *
45 dl 1.1 * <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 jsr166 1.3 * public int hash(Object x) {
59 dl 1.1 * 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 jsr166 1.3 *
73 dl 1.1 * <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 jsr166 1.3 * modCounts etc).
130 dl 1.1 *
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 jsr166 1.3 public enum Strength {
142 dl 1.1 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 jsr166 1.3
149 dl 1.1 /** 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 jsr166 1.3 * Returns a hash value such that equal(a, b) implies
188 dl 1.1 * 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 jsr166 1.3 static final class EquivalenceUsingIdentity
198 dl 1.1 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 jsr166 1.3 static final class EquivalenceUsingEquals
205 dl 1.1 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 jsr166 1.3 public static final Equivalence<Object> IDENTITY =
216 dl 1.1 new EquivalenceUsingIdentity();
217 jsr166 1.3
218 dl 1.1 /**
219     * An Equivalence object performing {@link Object#equals} based comparisons
220     * and using {@link Object#hashCode} hashing
221     */
222 jsr166 1.3 public static final Equivalence<Object> EQUALS =
223 dl 1.1 new EquivalenceUsingEquals();
224    
225     /**
226     * A function computing a mapping from the given key to a value,
227 jsr166 1.3 * or <code>null</code> if there is no mapping.
228 dl 1.1 */
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 jsr166 1.3 * @parem key the (nonnull) immutable key
281 dl 1.1 * @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 jsr166 1.3 Node newNode(int locator, Object key, Object value,
286 dl 1.1 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 jsr166 1.3
359 dl 1.1 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 jsr166 1.3 Node[] newTable =
400 dl 1.1 (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 jsr166 1.3 newTable[k] =
440 dl 1.1 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 jsr166 1.3
481 dl 1.1 /**
482     * The factory for this map
483     */
484     final NodeFactory factory;
485 jsr166 1.3
486 dl 1.1 /**
487     * Equivalence object for keys
488     */
489     final Equivalence<? super K> keyEquivalence;
490 jsr166 1.3
491 dl 1.1 /**
492     * Equivalence object for values
493     */
494     final Equivalence<? super V> valueEquivalence;
495 jsr166 1.3
496 dl 1.1 /**
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 jsr166 1.3 String factoryName =
519     CustomConcurrentHashMap.class.getName() + "$" +
520     ks + "Key" +
521 dl 1.1 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 jsr166 1.3 this(keyStrength.getName(), keyEquivalence,
558 dl 1.1 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 jsr166 1.3 (keyStrength.getName(), keyEquivalence, INT_STRING, EQUALS,
604 dl 1.1 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 jsr166 1.3 (INT_STRING, EQUALS, INT_STRING, EQUALS,
618 dl 1.1 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 jsr166 1.3 (k != null &&
666     p.getLocator() == hash &&
667 dl 1.1 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 jsr166 1.3 if (v == oldValue ||
828 dl 1.1 (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 jsr166 1.3 p.getLocator() == hash &&
868 dl 1.1 keyEquivalence.equal((K)k, key))) {
869     oldValue = (V)(p.getValue());
870     if (pred == null)
871 jsr166 1.3 tab[i] = n;
872 dl 1.1 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 jsr166 1.3 p.getLocator() == hash &&
915 dl 1.1 keyEquivalence.equal((K)k, key))) {
916     V v = (V)(p.getValue());
917     if (v == value ||
918 jsr166 1.3 (v != null &&
919 dl 1.1 valueEquivalence.equal(v, value))) {
920     if (pred == null)
921 jsr166 1.3 tab[i] = n;
922 dl 1.1 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 jsr166 1.3 tab[i] = n;
960 dl 1.1 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 jsr166 1.3 if (seg != null &&
987     seg.getTableForTraversal() != null &&
988 dl 1.1 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 jsr166 1.3 for (Node p = tab[j];
1034     p != null;
1035 dl 1.1 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 jsr166 1.3 * @return the current (existing or computed) value associated with
1090 dl 1.1 * the specified key, or <tt>null</tt> if the computation
1091     * returned <tt>null</tt>.
1092 jsr166 1.3 * @throws NullPointerException if the specified key or mappingFunction
1093 dl 1.1 * 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 jsr166 1.3 if (r != null)
1115 dl 1.1 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 jsr166 1.3 *
1148 dl 1.1 * 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 jsr166 1.3 * <tt>null</tt> if the computation returned <tt>null</tt>
1165     * @throws NullPointerException if the specified key or remappingFunction
1166 dl 1.1 * 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 jsr166 1.3 p.getLocator() == hash &&
1187 dl 1.1 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 jsr166 1.3 if (value != null)
1197 dl 1.1 p.setValue(value);
1198     else {
1199     Node n = p.getLinkage();
1200     if (pred == null)
1201 jsr166 1.3 tab[i] = n;
1202 dl 1.1 else
1203     pred.setLinkage(n);
1204     seg.decrementCount();
1205     }
1206     }
1207     else if (value != null) {
1208 jsr166 1.3 Node r =
1209 dl 1.1 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 jsr166 1.3 if (seg != null &&
1258 dl 1.1 (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 jsr166 1.3 WriteThroughEntry e = new WriteThroughEntry((K)nextKey,
1291 dl 1.1 (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 jsr166 1.3 final class KeyIterator extends HashIterator
1334 dl 1.1 implements Iterator<K> {
1335 jsr166 1.3 public K next() {
1336     return super.nextKey();
1337 dl 1.1 }
1338     }
1339    
1340     final KeyIterator keyIterator() { // needed by Set
1341     return new KeyIterator();
1342     }
1343    
1344 jsr166 1.3 final class ValueIterator extends HashIterator
1345 dl 1.1 implements Iterator<V> {
1346 jsr166 1.3 public V next() {
1347     return super.nextValue();
1348 dl 1.1 }
1349     }
1350    
1351 jsr166 1.3 final class EntryIterator extends HashIterator
1352 dl 1.1 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 jsr166 1.3 return v != null &&
1407 dl 1.1 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 jsr166 1.3
1505 dl 1.1 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 jsr166 1.3 public KeySet(Strength strength,
1606 dl 1.1 Equivalence<? super K> equivalence,
1607     int expectedSize) {
1608     this.cchm = new CustomConcurrentHashMap<K,K>
1609 jsr166 1.3 (strength.getName(), equivalence,
1610 dl 1.1 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 jsr166 1.3 *
1618 dl 1.1 * @param e the element
1619     * @return e, or an element equivalent to e.
1620     */
1621     public K intern(K e) {
1622 dl 1.2 K oldElement = cchm.doPut(e, e, true);
1623 jsr166 1.3 return (oldElement != null) ? oldElement : e;
1624 dl 1.1 }
1625 jsr166 1.3
1626 dl 1.1 /**
1627     * Returns <tt>true</tt> if this set contains an
1628     * element equivalent to the given element with respect
1629     * to this set's Equivalence.
1630     * @param o element whose presence in this set is to be tested
1631     * @return <tt>true</tt> if this set contains the specified element
1632     */
1633     public boolean contains(Object o) {
1634     return cchm.containsKey(o);
1635     }
1636 jsr166 1.3
1637 dl 1.1 /**
1638     * Returns a <i>weakly consistent iterator</i> over the
1639     * elements in this set, that may reflect some, all or none of
1640     * the changes made to the set after the iterator was created.
1641     *
1642     * @return an Iterator over the elements in this set
1643     */
1644     public Iterator<K> iterator() {
1645     return cchm.keyIterator();
1646     }
1647 jsr166 1.3
1648 dl 1.1 /**
1649     * Adds the specified element to this set if there is not
1650     * already an element equivalent to the given element with
1651     * respect to this set's Equivalence.
1652     *
1653     * @param e element to be added to this set
1654     * @return <tt>true</tt> if this set did not already contain
1655     * the specified element
1656     */
1657     public boolean add(K e) {
1658     return cchm.doPut(e, e, true) != null;
1659     }
1660    
1661     /**
1662     * Removes an element equivalent to the given element with
1663     * respect to this set's Equivalence, if one is present.
1664     *
1665     * @param o object to be removed from this set, if present
1666     * @return <tt>true</tt> if the set contained the specified element
1667     */
1668     public boolean remove(Object o) {
1669     return cchm.remove(o) != null;
1670     }
1671    
1672     /**
1673     * Returns <tt>true</tt> if this set contains no elements.
1674     *
1675     * @return <tt>true</tt> if this set contains no elements
1676     */
1677     public boolean isEmpty() {
1678     return cchm.isEmpty();
1679     }
1680    
1681     /**
1682     * Returns the number of elements in this set (its cardinality).
1683     *
1684     * @return the number of elements in this set (its cardinality)
1685     */
1686     public int size() {
1687     return cchm.size();
1688     }
1689 jsr166 1.3
1690 dl 1.1 /**
1691     * Removes all of the elements from this set.
1692     */
1693     public void clear() {
1694     cchm.clear();
1695     }
1696    
1697     /**
1698     * Returns the sum of the hash codes of each element, as
1699     * computed by this set's Equivalence.
1700     * @return the hash code
1701     */
1702     public int hashCode() {
1703     int h = 0;
1704     Iterator<K> i = iterator();
1705     while (i.hasNext())
1706     h += cchm.keyEquivalence.hash(i.next());
1707     return h;
1708     }
1709     }
1710    
1711     // Reference queue mechanics for reclaimable nodes
1712    
1713     static volatile ReferenceQueue<Object> refQueue;
1714    
1715     /**
1716     * Returns a queue that may be used as the ReferenceQueue argument
1717     * to {@link java.lang.ref.Reference} constructors to arrange
1718     * removal of reclaimed nodes from maps via a background thread.
1719     * @return the reference queue associated with the background
1720     * cleanup thread.
1721     */
1722     static ReferenceQueue<Object> getReclamationQueue() {
1723     ReferenceQueue<Object> q = refQueue;
1724     if (q != null)
1725     return q;
1726     else
1727     return startReclamation();
1728     }
1729    
1730     static synchronized ReferenceQueue<Object> startReclamation() {
1731     ReferenceQueue<Object> q = refQueue;
1732     if (q == null) {
1733     refQueue = q = new ReferenceQueue<Object>();
1734     new ReclamationThread(q).start();
1735     }
1736     return q;
1737     }
1738    
1739     static final class ReclamationThread extends Thread {
1740     final ReferenceQueue<Object> queue;
1741     ReclamationThread(ReferenceQueue<Object> q) {
1742     this.queue = q;
1743     setDaemon(true);
1744     }
1745     public void run() {
1746     ReferenceQueue<Object> q = queue;
1747     for (;;) {
1748     try {
1749     Reference<?> r = q.remove();
1750     if (r instanceof Reclaimable)
1751     ((Reclaimable)r).onReclamation();
1752 jsr166 1.3 } catch (InterruptedException e) {
1753     /* ignore */
1754 dl 1.1 }
1755     }
1756     }
1757     }
1758    
1759     // classes extending Weak/soft refs embedded in reclaimable nodes
1760    
1761 jsr166 1.3 static class EmbeddedWeakReference extends WeakReference
1762 dl 1.1 implements Reclaimable {
1763     final Reclaimable outer;
1764     EmbeddedWeakReference(Object x, Reclaimable outer) {
1765     super(x, getReclamationQueue());
1766     this.outer = outer;
1767     }
1768 jsr166 1.3 public final void onReclamation() {
1769 dl 1.1 clear();
1770 jsr166 1.3 outer.onReclamation();
1771 dl 1.1 }
1772     }
1773    
1774 jsr166 1.3 static class EmbeddedSoftReference extends SoftReference
1775 dl 1.1 implements Reclaimable {
1776     final Reclaimable outer;
1777     EmbeddedSoftReference(Object x, Reclaimable outer) {
1778     super(x, getReclamationQueue());
1779     this.outer = outer;
1780     }
1781 jsr166 1.3 public final void onReclamation() {
1782 dl 1.1 clear();
1783 jsr166 1.3 outer.onReclamation();
1784 dl 1.1 }
1785     }
1786    
1787     // builtin mapping node classes
1788    
1789     // Strong Keys
1790    
1791     static abstract class StrongKeyNode implements Node {
1792     final Object key;
1793     final int locator;
1794     StrongKeyNode(int locator, Object key) {
1795     this.locator = locator;
1796     this.key = key;
1797     }
1798     public final Object get() { return key; }
1799     public final int getLocator() { return locator; }
1800     }
1801    
1802    
1803 jsr166 1.3 static abstract class StrongKeySelfValueNode
1804 dl 1.1 extends StrongKeyNode {
1805     StrongKeySelfValueNode(int locator, Object key) {
1806     super(locator, key);
1807     }
1808     public final Object getValue() { return key; }
1809     public final void setValue(Object value) { }
1810     public final void onReclamation() { }
1811     }
1812    
1813 jsr166 1.3 static final class TerminalStrongKeySelfValueNode
1814 dl 1.1 extends StrongKeySelfValueNode {
1815     TerminalStrongKeySelfValueNode(int locator, Object key) {
1816     super(locator, key);
1817     }
1818     public final Node getLinkage() { return null; }
1819     public final void setLinkage(Node r) { }
1820     }
1821    
1822 jsr166 1.3 static final class LinkedStrongKeySelfValueNode
1823 dl 1.1 extends StrongKeySelfValueNode {
1824     volatile Node linkage;
1825 jsr166 1.3 LinkedStrongKeySelfValueNode(int locator, Object key,
1826 dl 1.1 Node linkage) {
1827     super(locator, key);
1828     this.linkage = linkage;
1829     }
1830     public final Node getLinkage() { return linkage; }
1831     public final void setLinkage(Node r) { linkage = r; }
1832     }
1833    
1834     static final class StrongKeySelfValueNodeFactory
1835     implements NodeFactory, Serializable {
1836     private static final long serialVersionUID = 7249069346764182397L;
1837     public final Node newNode(int locator,
1838 jsr166 1.3 Object key, Object value,
1839 dl 1.1 CustomConcurrentHashMap cchm,
1840     Node linkage) {
1841     if (linkage == null)
1842     return new TerminalStrongKeySelfValueNode
1843     (locator, key);
1844     else
1845     return new LinkedStrongKeySelfValueNode
1846     (locator, key, linkage);
1847     }
1848 jsr166 1.3 }
1849 dl 1.1
1850 jsr166 1.3 static abstract class StrongKeyStrongValueNode
1851 dl 1.1 extends StrongKeyNode {
1852     volatile Object value;
1853     StrongKeyStrongValueNode(int locator, Object key, Object value) {
1854     super(locator, key);
1855     this.value = value;
1856     }
1857     public final Object getValue() { return value; }
1858     public final void setValue(Object value) { this.value = value; }
1859     public final void onReclamation() { }
1860     }
1861    
1862 jsr166 1.3 static final class TerminalStrongKeyStrongValueNode
1863 dl 1.1 extends StrongKeyStrongValueNode {
1864     TerminalStrongKeyStrongValueNode(int locator,
1865     Object key, Object value) {
1866     super(locator, key, value);
1867     }
1868     public final Node getLinkage() { return null; }
1869     public final void setLinkage(Node r) { }
1870     }
1871    
1872 jsr166 1.3 static final class LinkedStrongKeyStrongValueNode
1873 dl 1.1 extends StrongKeyStrongValueNode {
1874     volatile Node linkage;
1875     LinkedStrongKeyStrongValueNode(int locator,
1876 jsr166 1.3 Object key, Object value,
1877 dl 1.1 Node linkage) {
1878     super(locator, key, value);
1879     this.linkage = linkage;
1880     }
1881     public final Node getLinkage() { return linkage; }
1882     public final void setLinkage(Node r) { linkage = r; }
1883     }
1884    
1885 jsr166 1.3 static final class StrongKeyStrongValueNodeFactory
1886 dl 1.1 implements NodeFactory, Serializable {
1887     private static final long serialVersionUID = 7249069346764182397L;
1888     public final Node newNode(int locator,
1889 jsr166 1.3 Object key, Object value,
1890 dl 1.1 CustomConcurrentHashMap cchm,
1891     Node linkage) {
1892     if (linkage == null)
1893     return new TerminalStrongKeyStrongValueNode
1894     (locator, key, value);
1895     else
1896     return new LinkedStrongKeyStrongValueNode
1897     (locator, key, value, linkage);
1898     }
1899 jsr166 1.3 }
1900 dl 1.1
1901     // ...
1902    
1903 jsr166 1.3 static abstract class StrongKeyIntValueNode
1904 dl 1.1 extends StrongKeyNode {
1905     volatile int value;
1906     StrongKeyIntValueNode(int locator, Object key, Object value) {
1907     super(locator, key);
1908     this.value = ((Integer)value).intValue();
1909     }
1910     public final Object getValue() { return Integer.valueOf(value); }
1911 jsr166 1.3 public final void setValue(Object value) {
1912 dl 1.1 this.value = ((Integer)value).intValue();
1913     }
1914     public final void onReclamation() { }
1915     }
1916    
1917 jsr166 1.3 static final class TerminalStrongKeyIntValueNode
1918 dl 1.1 extends StrongKeyIntValueNode {
1919     TerminalStrongKeyIntValueNode(int locator,
1920     Object key, Object value) {
1921     super(locator, key, value);
1922     }
1923     public final Node getLinkage() { return null; }
1924     public final void setLinkage(Node r) { }
1925     }
1926    
1927 jsr166 1.3 static final class LinkedStrongKeyIntValueNode
1928 dl 1.1 extends StrongKeyIntValueNode {
1929     volatile Node linkage;
1930     LinkedStrongKeyIntValueNode(int locator,
1931 jsr166 1.3 Object key, Object value,
1932 dl 1.1 Node linkage) {
1933     super(locator, key, value);
1934     this.linkage = linkage;
1935     }
1936     public final Node getLinkage() { return linkage; }
1937     public final void setLinkage(Node r) { linkage = r; }
1938     }
1939    
1940 jsr166 1.3 static final class StrongKeyIntValueNodeFactory
1941 dl 1.1 implements NodeFactory, Serializable {
1942     private static final long serialVersionUID = 7249069346764182397L;
1943     public final Node newNode(int locator,
1944 jsr166 1.3 Object key, Object value,
1945 dl 1.1 CustomConcurrentHashMap cchm,
1946     Node linkage) {
1947     if (linkage == null)
1948     return new TerminalStrongKeyIntValueNode
1949     (locator, key, value);
1950     else
1951     return new LinkedStrongKeyIntValueNode
1952     (locator, key, value, linkage);
1953     }
1954 jsr166 1.3 }
1955 dl 1.1
1956     // ...
1957    
1958 jsr166 1.3 static abstract class StrongKeyWeakValueNode
1959 dl 1.1 extends StrongKeyNode {
1960     volatile EmbeddedWeakReference valueRef;
1961     final CustomConcurrentHashMap cchm;
1962 jsr166 1.3 StrongKeyWeakValueNode(int locator, Object key, Object value,
1963 dl 1.1 CustomConcurrentHashMap cchm) {
1964     super(locator, key);
1965     this.cchm = cchm;
1966     if (value != null)
1967     this.valueRef = new EmbeddedWeakReference(value, this);
1968     }
1969     public final void onReclamation() {
1970     cchm.removeIfReclaimed(this);
1971     }
1972     public final Object getValue() {
1973     EmbeddedWeakReference vr = valueRef;
1974     return vr == null? null : vr.get();
1975     }
1976     public final void setValue(Object value) {
1977     if (value == null)
1978     valueRef = null;
1979     else
1980     valueRef = new EmbeddedWeakReference(value, this);
1981     }
1982     }
1983    
1984 jsr166 1.3 static final class TerminalStrongKeyWeakValueNode
1985 dl 1.1 extends StrongKeyWeakValueNode {
1986     TerminalStrongKeyWeakValueNode(int locator,
1987 jsr166 1.3 Object key, Object value,
1988 dl 1.1 CustomConcurrentHashMap cchm) {
1989     super(locator, key, value, cchm);
1990     }
1991     public final Node getLinkage() { return null; }
1992     public final void setLinkage(Node r) { }
1993     }
1994    
1995 jsr166 1.3 static final class LinkedStrongKeyWeakValueNode
1996 dl 1.1 extends StrongKeyWeakValueNode {
1997     volatile Node linkage;
1998     LinkedStrongKeyWeakValueNode(int locator,
1999 jsr166 1.3 Object key, Object value,
2000 dl 1.1 CustomConcurrentHashMap cchm,
2001     Node linkage) {
2002     super(locator, key, value, cchm);
2003     this.linkage = linkage;
2004     }
2005     public final Node getLinkage() { return linkage; }
2006     public final void setLinkage(Node r) { linkage = r; }
2007     }
2008    
2009 jsr166 1.3 static final class StrongKeyWeakValueNodeFactory
2010 dl 1.1 implements NodeFactory, Serializable {
2011     private static final long serialVersionUID = 7249069346764182397L;
2012 jsr166 1.3 public final Node newNode(int locator,
2013     Object key, Object value,
2014 dl 1.1 CustomConcurrentHashMap cchm,
2015     Node linkage) {
2016     if (linkage == null)
2017     return new TerminalStrongKeyWeakValueNode
2018     (locator, key, value, cchm);
2019     else
2020     return new LinkedStrongKeyWeakValueNode
2021     (locator, key, value, cchm, linkage);
2022     }
2023 jsr166 1.3 }
2024 dl 1.1
2025    
2026 jsr166 1.3 static abstract class StrongKeySoftValueNode
2027 dl 1.1 extends StrongKeyNode {
2028     volatile EmbeddedSoftReference valueRef;
2029     final CustomConcurrentHashMap cchm;
2030 jsr166 1.3 StrongKeySoftValueNode(int locator, Object key, Object value,
2031 dl 1.1 CustomConcurrentHashMap cchm) {
2032     super(locator, key);
2033     this.cchm = cchm;
2034     if (value != null)
2035     this.valueRef = new EmbeddedSoftReference(value, this);
2036     }
2037     public final void onReclamation() {
2038     cchm.removeIfReclaimed(this);
2039     }
2040     public final Object getValue() {
2041     EmbeddedSoftReference vr = valueRef;
2042     return vr == null? null : vr.get();
2043     }
2044     public final void setValue(Object value) {
2045     if (value == null)
2046     valueRef = null;
2047     else
2048     valueRef = new EmbeddedSoftReference(value, this);
2049     }
2050     }
2051    
2052 jsr166 1.3 static final class TerminalStrongKeySoftValueNode
2053 dl 1.1 extends StrongKeySoftValueNode {
2054     TerminalStrongKeySoftValueNode(int locator,
2055 jsr166 1.3 Object key, Object value,
2056 dl 1.1 CustomConcurrentHashMap cchm) {
2057     super(locator, key, value, cchm);
2058     }
2059     public final Node getLinkage() { return null; }
2060     public final void setLinkage(Node r) { }
2061     }
2062    
2063 jsr166 1.3 static final class LinkedStrongKeySoftValueNode
2064 dl 1.1 extends StrongKeySoftValueNode {
2065     volatile Node linkage;
2066     LinkedStrongKeySoftValueNode(int locator,
2067 jsr166 1.3 Object key, Object value,
2068 dl 1.1 CustomConcurrentHashMap cchm,
2069     Node linkage) {
2070     super(locator, key, value, cchm);
2071     this.linkage = linkage;
2072     }
2073     public final Node getLinkage() { return linkage; }
2074     public final void setLinkage(Node r) { linkage = r; }
2075     }
2076    
2077 jsr166 1.3 static final class StrongKeySoftValueNodeFactory
2078 dl 1.1 implements NodeFactory, Serializable {
2079     private static final long serialVersionUID = 7249069346764182397L;
2080 jsr166 1.3 public final Node newNode(int locator,
2081     Object key, Object value,
2082 dl 1.1 CustomConcurrentHashMap cchm,
2083     Node linkage) {
2084     if (linkage == null)
2085     return new TerminalStrongKeySoftValueNode
2086     (locator, key, value, cchm);
2087     else
2088     return new LinkedStrongKeySoftValueNode
2089     (locator, key, value, cchm, linkage);
2090     }
2091 jsr166 1.3 }
2092 dl 1.1
2093     // Weak keys
2094    
2095     static abstract class WeakKeyNode extends WeakReference
2096     implements Node {
2097     final int locator;
2098     final CustomConcurrentHashMap cchm;
2099     WeakKeyNode(int locator, Object key, CustomConcurrentHashMap cchm) {
2100     super(key);
2101     this.locator = locator;
2102     this.cchm = cchm;
2103     }
2104     public final int getLocator() { return locator; }
2105 jsr166 1.3 public final void onReclamation() {
2106 dl 1.1 clear();
2107     cchm.removeIfReclaimed(this);
2108     }
2109     }
2110    
2111 jsr166 1.3 static abstract class WeakKeySelfValueNode
2112 dl 1.1 extends WeakKeyNode {
2113     WeakKeySelfValueNode(int locator, Object key, CustomConcurrentHashMap cchm) {
2114     super(locator, key, cchm);
2115     }
2116     public final Object getValue() { return get(); }
2117     public final void setValue(Object value) { }
2118     }
2119    
2120 jsr166 1.3 static final class TerminalWeakKeySelfValueNode
2121 dl 1.1 extends WeakKeySelfValueNode {
2122     TerminalWeakKeySelfValueNode(int locator, Object key, CustomConcurrentHashMap cchm) {
2123     super(locator, key, cchm);
2124     }
2125     public final Node getLinkage() { return null; }
2126     public final void setLinkage(Node r) { }
2127     }
2128    
2129 jsr166 1.3 static final class LinkedWeakKeySelfValueNode
2130 dl 1.1 extends WeakKeySelfValueNode {
2131     volatile Node linkage;
2132     LinkedWeakKeySelfValueNode(int locator, Object key, CustomConcurrentHashMap cchm,
2133     Node linkage) {
2134     super(locator, key, cchm);
2135     this.linkage = linkage;
2136     }
2137     public final Node getLinkage() { return linkage; }
2138     public final void setLinkage(Node r) { linkage = r; }
2139     }
2140    
2141     static final class WeakKeySelfValueNodeFactory
2142     implements NodeFactory, Serializable {
2143     private static final long serialVersionUID = 7249069346764182397L;
2144     public final Node newNode(int locator,
2145 jsr166 1.3 Object key, Object value,
2146 dl 1.1 CustomConcurrentHashMap cchm,
2147     Node linkage) {
2148     if (linkage == null)
2149     return new TerminalWeakKeySelfValueNode
2150     (locator, key, cchm);
2151     else
2152     return new LinkedWeakKeySelfValueNode
2153     (locator, key, cchm, linkage);
2154     }
2155 jsr166 1.3 }
2156 dl 1.1
2157    
2158 jsr166 1.3 static abstract class WeakKeyStrongValueNode
2159 dl 1.1 extends WeakKeyNode {
2160     volatile Object value;
2161     WeakKeyStrongValueNode(int locator, Object key, Object value, CustomConcurrentHashMap cchm) {
2162     super(locator, key, cchm);
2163     this.value = value;
2164     }
2165     public final Object getValue() { return value; }
2166     public final void setValue(Object value) { this.value = value; }
2167     }
2168    
2169 jsr166 1.3 static final class TerminalWeakKeyStrongValueNode
2170 dl 1.1 extends WeakKeyStrongValueNode {
2171     TerminalWeakKeyStrongValueNode(int locator,
2172     Object key, Object value, CustomConcurrentHashMap cchm) {
2173     super(locator, key, value, cchm);
2174     }
2175     public final Node getLinkage() { return null; }
2176     public final void setLinkage(Node r) { }
2177     }
2178    
2179 jsr166 1.3 static final class LinkedWeakKeyStrongValueNode
2180 dl 1.1 extends WeakKeyStrongValueNode {
2181     volatile Node linkage;
2182     LinkedWeakKeyStrongValueNode(int locator,
2183     Object key, Object value, CustomConcurrentHashMap cchm,
2184     Node linkage) {
2185     super(locator, key, value, cchm);
2186     this.linkage = linkage;
2187     }
2188     public final Node getLinkage() { return linkage; }
2189     public final void setLinkage(Node r) { linkage = r; }
2190     }
2191    
2192 jsr166 1.3 static final class WeakKeyStrongValueNodeFactory
2193 dl 1.1 implements NodeFactory, Serializable {
2194     private static final long serialVersionUID = 7249069346764182397L;
2195     public final Node newNode(int locator,
2196 jsr166 1.3 Object key, Object value,
2197 dl 1.1 CustomConcurrentHashMap cchm,
2198     Node linkage) {
2199     if (linkage == null)
2200     return new TerminalWeakKeyStrongValueNode
2201     (locator, key, value, cchm);
2202     else
2203     return new LinkedWeakKeyStrongValueNode
2204     (locator, key, value, cchm, linkage);
2205     }
2206 jsr166 1.3 }
2207 dl 1.1
2208 jsr166 1.3 static abstract class WeakKeyIntValueNode
2209 dl 1.1 extends WeakKeyNode {
2210     volatile int value;
2211     WeakKeyIntValueNode(int locator, Object key, Object value,
2212     CustomConcurrentHashMap cchm) {
2213     super(locator, key, cchm);
2214     this.value = ((Integer)value).intValue();
2215     }
2216     public final Object getValue() { return Integer.valueOf(value); }
2217 jsr166 1.3 public final void setValue(Object value) {
2218 dl 1.1 this.value = ((Integer)value).intValue();
2219     }
2220     }
2221    
2222 jsr166 1.3 static final class TerminalWeakKeyIntValueNode
2223 dl 1.1 extends WeakKeyIntValueNode {
2224     TerminalWeakKeyIntValueNode(int locator,
2225     Object key, Object value,
2226     CustomConcurrentHashMap cchm) {
2227     super(locator, key, value, cchm);
2228     }
2229     public final Node getLinkage() { return null; }
2230     public final void setLinkage(Node r) { }
2231     }
2232    
2233 jsr166 1.3 static final class LinkedWeakKeyIntValueNode
2234 dl 1.1 extends WeakKeyIntValueNode {
2235     volatile Node linkage;
2236     LinkedWeakKeyIntValueNode(int locator,
2237 jsr166 1.3 Object key, Object value,
2238 dl 1.1 CustomConcurrentHashMap cchm,
2239     Node linkage) {
2240     super(locator, key, value, cchm);
2241     this.linkage = linkage;
2242     }
2243     public final Node getLinkage() { return linkage; }
2244     public final void setLinkage(Node r) { linkage = r; }
2245     }
2246    
2247 jsr166 1.3 static final class WeakKeyIntValueNodeFactory
2248 dl 1.1 implements NodeFactory, Serializable {
2249     private static final long serialVersionUID = 7249069346764182397L;
2250     public final Node newNode(int locator,
2251 jsr166 1.3 Object key, Object value,
2252 dl 1.1 CustomConcurrentHashMap cchm,
2253     Node linkage) {
2254     if (linkage == null)
2255     return new TerminalWeakKeyIntValueNode
2256     (locator, key, value, cchm);
2257     else
2258     return new LinkedWeakKeyIntValueNode
2259     (locator, key, value, cchm, linkage);
2260     }
2261 jsr166 1.3 }
2262 dl 1.1
2263 jsr166 1.3 static abstract class WeakKeyWeakValueNode
2264 dl 1.1 extends WeakKeyNode {
2265     volatile EmbeddedWeakReference valueRef;
2266 jsr166 1.3 WeakKeyWeakValueNode(int locator, Object key, Object value,
2267 dl 1.1 CustomConcurrentHashMap cchm) {
2268     super(locator, key, cchm);
2269     if (value != null)
2270     this.valueRef = new EmbeddedWeakReference(value, this);
2271     }
2272     public final Object getValue() {
2273     EmbeddedWeakReference vr = valueRef;
2274     return vr == null? null : vr.get();
2275     }
2276     public final void setValue(Object value) {
2277     if (value == null)
2278     valueRef = null;
2279     else
2280     valueRef = new EmbeddedWeakReference(value, this);
2281     }
2282     }
2283    
2284 jsr166 1.3 static final class TerminalWeakKeyWeakValueNode
2285 dl 1.1 extends WeakKeyWeakValueNode {
2286     TerminalWeakKeyWeakValueNode(int locator,
2287 jsr166 1.3 Object key, Object value,
2288 dl 1.1 CustomConcurrentHashMap cchm) {
2289     super(locator, key, value, cchm);
2290     }
2291     public final Node getLinkage() { return null; }
2292     public final void setLinkage(Node r) { }
2293     }
2294    
2295 jsr166 1.3 static final class LinkedWeakKeyWeakValueNode
2296 dl 1.1 extends WeakKeyWeakValueNode {
2297     volatile Node linkage;
2298     LinkedWeakKeyWeakValueNode(int locator,
2299 jsr166 1.3 Object key, Object value,
2300 dl 1.1 CustomConcurrentHashMap cchm,
2301     Node linkage) {
2302     super(locator, key, value, cchm);
2303     this.linkage = linkage;
2304     }
2305     public final Node getLinkage() { return linkage; }
2306     public final void setLinkage(Node r) { linkage = r; }
2307     }
2308    
2309 jsr166 1.3 static final class WeakKeyWeakValueNodeFactory
2310 dl 1.1 implements NodeFactory, Serializable {
2311     private static final long serialVersionUID = 7249069346764182397L;
2312 jsr166 1.3 public final Node newNode(int locator,
2313     Object key, Object value,
2314 dl 1.1 CustomConcurrentHashMap cchm,
2315     Node linkage) {
2316     if (linkage == null)
2317     return new TerminalWeakKeyWeakValueNode
2318     (locator, key, value, cchm);
2319     else
2320     return new LinkedWeakKeyWeakValueNode
2321     (locator, key, value, cchm, linkage);
2322     }
2323 jsr166 1.3 }
2324 dl 1.1
2325    
2326 jsr166 1.3 static abstract class WeakKeySoftValueNode
2327 dl 1.1 extends WeakKeyNode {
2328     volatile EmbeddedSoftReference valueRef;
2329 jsr166 1.3 WeakKeySoftValueNode(int locator, Object key, Object value,
2330 dl 1.1 CustomConcurrentHashMap cchm) {
2331     super(locator, key, cchm);
2332     if (value != null)
2333     this.valueRef = new EmbeddedSoftReference(value, this);
2334     }
2335     public final Object getValue() {
2336     EmbeddedSoftReference vr = valueRef;
2337     return vr == null? null : vr.get();
2338     }
2339     public final void setValue(Object value) {
2340     if (value == null)
2341     valueRef = null;
2342     else
2343     valueRef = new EmbeddedSoftReference(value, this);
2344     }
2345     }
2346    
2347 jsr166 1.3 static final class TerminalWeakKeySoftValueNode
2348 dl 1.1 extends WeakKeySoftValueNode {
2349     TerminalWeakKeySoftValueNode(int locator,
2350 jsr166 1.3 Object key, Object value,
2351 dl 1.1 CustomConcurrentHashMap cchm) {
2352     super(locator, key, value, cchm);
2353     }
2354     public final Node getLinkage() { return null; }
2355     public final void setLinkage(Node r) { }
2356     }
2357    
2358 jsr166 1.3 static final class LinkedWeakKeySoftValueNode
2359 dl 1.1 extends WeakKeySoftValueNode {
2360     volatile Node linkage;
2361     LinkedWeakKeySoftValueNode(int locator,
2362 jsr166 1.3 Object key, Object value,
2363 dl 1.1 CustomConcurrentHashMap cchm,
2364     Node linkage) {
2365     super(locator, key, value, cchm);
2366     this.linkage = linkage;
2367     }
2368     public final Node getLinkage() { return linkage; }
2369     public final void setLinkage(Node r) { linkage = r; }
2370     }
2371    
2372 jsr166 1.3 static final class WeakKeySoftValueNodeFactory
2373 dl 1.1 implements NodeFactory, Serializable {
2374     private static final long serialVersionUID = 7249069346764182397L;
2375 jsr166 1.3 public final Node newNode(int locator,
2376     Object key, Object value,
2377 dl 1.1 CustomConcurrentHashMap cchm,
2378     Node linkage) {
2379     if (linkage == null)
2380     return new TerminalWeakKeySoftValueNode
2381     (locator, key, value, cchm);
2382     else
2383     return new LinkedWeakKeySoftValueNode
2384     (locator, key, value, cchm, linkage);
2385     }
2386 jsr166 1.3 }
2387 dl 1.1
2388     // Soft keys
2389    
2390     static abstract class SoftKeyNode extends SoftReference
2391     implements Node {
2392     final int locator;
2393     final CustomConcurrentHashMap cchm;
2394     SoftKeyNode(int locator, Object key, CustomConcurrentHashMap cchm) {
2395     super(key);
2396     this.locator = locator;
2397     this.cchm = cchm;
2398     }
2399     public final int getLocator() { return locator; }
2400 jsr166 1.3 public final void onReclamation() {
2401 dl 1.1 clear();
2402     cchm.removeIfReclaimed(this);
2403     }
2404     }
2405    
2406 jsr166 1.3 static abstract class SoftKeySelfValueNode
2407 dl 1.1 extends SoftKeyNode {
2408     SoftKeySelfValueNode(int locator, Object key, CustomConcurrentHashMap cchm) {
2409     super(locator, key, cchm);
2410     }
2411     public final Object getValue() { return get(); }
2412     public final void setValue(Object value) { }
2413     }
2414    
2415 jsr166 1.3 static final class TerminalSoftKeySelfValueNode
2416 dl 1.1 extends SoftKeySelfValueNode {
2417     TerminalSoftKeySelfValueNode(int locator, Object key, CustomConcurrentHashMap cchm) {
2418     super(locator, key, cchm);
2419     }
2420     public final Node getLinkage() { return null; }
2421     public final void setLinkage(Node r) { }
2422     }
2423    
2424 jsr166 1.3 static final class LinkedSoftKeySelfValueNode
2425 dl 1.1 extends SoftKeySelfValueNode {
2426     volatile Node linkage;
2427     LinkedSoftKeySelfValueNode(int locator, Object key, CustomConcurrentHashMap cchm,
2428     Node linkage) {
2429     super(locator, key, cchm);
2430     this.linkage = linkage;
2431     }
2432     public final Node getLinkage() { return linkage; }
2433     public final void setLinkage(Node r) { linkage = r; }
2434     }
2435    
2436     static final class SoftKeySelfValueNodeFactory
2437     implements NodeFactory, Serializable {
2438     private static final long serialVersionUID = 7249069346764182397L;
2439     public final Node newNode(int locator,
2440 jsr166 1.3 Object key, Object value,
2441 dl 1.1 CustomConcurrentHashMap cchm,
2442     Node linkage) {
2443     if (linkage == null)
2444     return new TerminalSoftKeySelfValueNode
2445     (locator, key, cchm);
2446     else
2447     return new LinkedSoftKeySelfValueNode
2448     (locator, key, cchm, linkage);
2449     }
2450 jsr166 1.3 }
2451 dl 1.1
2452    
2453 jsr166 1.3 static abstract class SoftKeyStrongValueNode
2454 dl 1.1 extends SoftKeyNode {
2455     volatile Object value;
2456     SoftKeyStrongValueNode(int locator, Object key, Object value, CustomConcurrentHashMap cchm) {
2457     super(locator, key, cchm);
2458     this.value = value;
2459     }
2460     public final Object getValue() { return value; }
2461     public final void setValue(Object value) { this.value = value; }
2462     }
2463    
2464 jsr166 1.3 static final class TerminalSoftKeyStrongValueNode
2465 dl 1.1 extends SoftKeyStrongValueNode {
2466     TerminalSoftKeyStrongValueNode(int locator,
2467     Object key, Object value, CustomConcurrentHashMap cchm) {
2468     super(locator, key, value, cchm);
2469     }
2470     public final Node getLinkage() { return null; }
2471     public final void setLinkage(Node r) { }
2472     }
2473    
2474 jsr166 1.3 static final class LinkedSoftKeyStrongValueNode
2475 dl 1.1 extends SoftKeyStrongValueNode {
2476     volatile Node linkage;
2477     LinkedSoftKeyStrongValueNode(int locator,
2478     Object key, Object value, CustomConcurrentHashMap cchm,
2479     Node linkage) {
2480     super(locator, key, value, cchm);
2481     this.linkage = linkage;
2482     }
2483     public final Node getLinkage() { return linkage; }
2484     public final void setLinkage(Node r) { linkage = r; }
2485     }
2486    
2487 jsr166 1.3 static final class SoftKeyStrongValueNodeFactory
2488 dl 1.1 implements NodeFactory, Serializable {
2489     private static final long serialVersionUID = 7249069346764182397L;
2490     public final Node newNode(int locator,
2491 jsr166 1.3 Object key, Object value,
2492 dl 1.1 CustomConcurrentHashMap cchm,
2493     Node linkage) {
2494     if (linkage == null)
2495     return new TerminalSoftKeyStrongValueNode
2496     (locator, key, value, cchm);
2497     else
2498     return new LinkedSoftKeyStrongValueNode
2499     (locator, key, value, cchm, linkage);
2500     }
2501 jsr166 1.3 }
2502 dl 1.1
2503 jsr166 1.3 static abstract class SoftKeyIntValueNode
2504 dl 1.1 extends SoftKeyNode {
2505     volatile int value;
2506     SoftKeyIntValueNode(int locator, Object key, Object value,
2507     CustomConcurrentHashMap cchm) {
2508     super(locator, key, cchm);
2509     this.value = ((Integer)value).intValue();
2510     }
2511     public final Object getValue() { return Integer.valueOf(value); }
2512 jsr166 1.3 public final void setValue(Object value) {
2513 dl 1.1 this.value = ((Integer)value).intValue();
2514     }
2515     }
2516    
2517 jsr166 1.3 static final class TerminalSoftKeyIntValueNode
2518 dl 1.1 extends SoftKeyIntValueNode {
2519     TerminalSoftKeyIntValueNode(int locator,
2520     Object key, Object value,
2521     CustomConcurrentHashMap cchm) {
2522     super(locator, key, value, cchm);
2523     }
2524     public final Node getLinkage() { return null; }
2525     public final void setLinkage(Node r) { }
2526     }
2527    
2528 jsr166 1.3 static final class LinkedSoftKeyIntValueNode
2529 dl 1.1 extends SoftKeyIntValueNode {
2530     volatile Node linkage;
2531     LinkedSoftKeyIntValueNode(int locator,
2532 jsr166 1.3 Object key, Object value,
2533 dl 1.1 CustomConcurrentHashMap cchm,
2534     Node linkage) {
2535     super(locator, key, value, cchm);
2536     this.linkage = linkage;
2537     }
2538     public final Node getLinkage() { return linkage; }
2539     public final void setLinkage(Node r) { linkage = r; }
2540     }
2541    
2542 jsr166 1.3 static final class SoftKeyIntValueNodeFactory
2543 dl 1.1 implements NodeFactory, Serializable {
2544     private static final long serialVersionUID = 7249069346764182397L;
2545     public final Node newNode(int locator,
2546 jsr166 1.3 Object key, Object value,
2547 dl 1.1 CustomConcurrentHashMap cchm,
2548     Node linkage) {
2549     if (linkage == null)
2550     return new TerminalSoftKeyIntValueNode
2551     (locator, key, value, cchm);
2552     else
2553     return new LinkedSoftKeyIntValueNode
2554     (locator, key, value, cchm, linkage);
2555     }
2556 jsr166 1.3 }
2557 dl 1.1
2558 jsr166 1.3 static abstract class SoftKeyWeakValueNode
2559 dl 1.1 extends SoftKeyNode {
2560     volatile EmbeddedWeakReference valueRef;
2561 jsr166 1.3 SoftKeyWeakValueNode(int locator, Object key, Object value,
2562 dl 1.1 CustomConcurrentHashMap cchm) {
2563     super(locator, key, cchm);
2564     if (value != null)
2565     this.valueRef = new EmbeddedWeakReference(value, this);
2566     }
2567     public final Object getValue() {
2568     EmbeddedWeakReference vr = valueRef;
2569     return vr == null? null : vr.get();
2570     }
2571     public final void setValue(Object value) {
2572     if (value == null)
2573     valueRef = null;
2574     else
2575     valueRef = new EmbeddedWeakReference(value, this);
2576     }
2577     }
2578    
2579 jsr166 1.3 static final class TerminalSoftKeyWeakValueNode
2580 dl 1.1 extends SoftKeyWeakValueNode {
2581     TerminalSoftKeyWeakValueNode(int locator,
2582 jsr166 1.3 Object key, Object value,
2583 dl 1.1 CustomConcurrentHashMap cchm) {
2584     super(locator, key, value, cchm);
2585     }
2586     public final Node getLinkage() { return null; }
2587     public final void setLinkage(Node r) { }
2588     }
2589    
2590 jsr166 1.3 static final class LinkedSoftKeyWeakValueNode
2591 dl 1.1 extends SoftKeyWeakValueNode {
2592     volatile Node linkage;
2593     LinkedSoftKeyWeakValueNode(int locator,
2594 jsr166 1.3 Object key, Object value,
2595 dl 1.1 CustomConcurrentHashMap cchm,
2596     Node linkage) {
2597     super(locator, key, value, cchm);
2598     this.linkage = linkage;
2599     }
2600     public final Node getLinkage() { return linkage; }
2601     public final void setLinkage(Node r) { linkage = r; }
2602     }
2603    
2604 jsr166 1.3 static final class SoftKeyWeakValueNodeFactory
2605 dl 1.1 implements NodeFactory, Serializable {
2606     private static final long serialVersionUID = 7249069346764182397L;
2607 jsr166 1.3 public final Node newNode(int locator,
2608     Object key, Object value,
2609 dl 1.1 CustomConcurrentHashMap cchm,
2610     Node linkage) {
2611     if (linkage == null)
2612     return new TerminalSoftKeyWeakValueNode
2613     (locator, key, value, cchm);
2614     else
2615     return new LinkedSoftKeyWeakValueNode
2616     (locator, key, value, cchm, linkage);
2617     }
2618 jsr166 1.3 }
2619 dl 1.1
2620    
2621 jsr166 1.3 static abstract class SoftKeySoftValueNode
2622 dl 1.1 extends SoftKeyNode {
2623     volatile EmbeddedSoftReference valueRef;
2624 jsr166 1.3 SoftKeySoftValueNode(int locator, Object key, Object value,
2625 dl 1.1 CustomConcurrentHashMap cchm) {
2626     super(locator, key, cchm);
2627     if (value != null)
2628     this.valueRef = new EmbeddedSoftReference(value, this);
2629     }
2630     public final Object getValue() {
2631     EmbeddedSoftReference vr = valueRef;
2632     return vr == null? null : vr.get();
2633     }
2634     public final void setValue(Object value) {
2635     if (value == null)
2636     valueRef = null;
2637     else
2638     valueRef = new EmbeddedSoftReference(value, this);
2639     }
2640     }
2641    
2642 jsr166 1.3 static final class TerminalSoftKeySoftValueNode
2643 dl 1.1 extends SoftKeySoftValueNode {
2644     TerminalSoftKeySoftValueNode(int locator,
2645 jsr166 1.3 Object key, Object value,
2646 dl 1.1 CustomConcurrentHashMap cchm) {
2647     super(locator, key, value, cchm);
2648     }
2649     public final Node getLinkage() { return null; }
2650     public final void setLinkage(Node r) { }
2651     }
2652    
2653 jsr166 1.3 static final class LinkedSoftKeySoftValueNode
2654 dl 1.1 extends SoftKeySoftValueNode {
2655     volatile Node linkage;
2656     LinkedSoftKeySoftValueNode(int locator,
2657 jsr166 1.3 Object key, Object value,
2658 dl 1.1 CustomConcurrentHashMap cchm,
2659     Node linkage) {
2660     super(locator, key, value, cchm);
2661     this.linkage = linkage;
2662     }
2663     public final Node getLinkage() { return linkage; }
2664     public final void setLinkage(Node r) { linkage = r; }
2665     }
2666    
2667 jsr166 1.3 static final class SoftKeySoftValueNodeFactory
2668 dl 1.1 implements NodeFactory, Serializable {
2669     private static final long serialVersionUID = 7249069346764182397L;
2670 jsr166 1.3 public final Node newNode(int locator,
2671     Object key, Object value,
2672 dl 1.1 CustomConcurrentHashMap cchm,
2673     Node linkage) {
2674     if (linkage == null)
2675     return new TerminalSoftKeySoftValueNode
2676     (locator, key, value, cchm);
2677     else
2678     return new LinkedSoftKeySoftValueNode
2679     (locator, key, value, cchm, linkage);
2680     }
2681 jsr166 1.3 }
2682 dl 1.1
2683     static abstract class IntKeyNode implements Node {
2684     final int key;
2685     IntKeyNode(int locator, Object key) {
2686     this.key = ((Integer)key).intValue();
2687     }
2688     public final Object get() { return Integer.valueOf(key); }
2689     public final int getLocator() { return spreadHash(key); }
2690     }
2691    
2692    
2693 jsr166 1.3 static abstract class IntKeySelfValueNode
2694 dl 1.1 extends IntKeyNode {
2695     IntKeySelfValueNode(int locator, Object key) {
2696     super(locator, key);
2697     }
2698     public final Object getValue() { return Integer.valueOf(key); }
2699     public final void setValue(Object value) { }
2700     public final void onReclamation() { }
2701     }
2702    
2703 jsr166 1.3 static final class TerminalIntKeySelfValueNode
2704 dl 1.1 extends IntKeySelfValueNode {
2705     TerminalIntKeySelfValueNode(int locator, Object key) {
2706     super(locator, key);
2707     }
2708     public final Node getLinkage() { return null; }
2709     public final void setLinkage(Node r) { }
2710     }
2711    
2712 jsr166 1.3 static final class LinkedIntKeySelfValueNode
2713 dl 1.1 extends IntKeySelfValueNode {
2714     volatile Node linkage;
2715 jsr166 1.3 LinkedIntKeySelfValueNode(int locator, Object key,
2716 dl 1.1 Node linkage) {
2717     super(locator, key);
2718     this.linkage = linkage;
2719     }
2720     public final Node getLinkage() { return linkage; }
2721     public final void setLinkage(Node r) { linkage = r; }
2722     }
2723    
2724     static final class IntKeySelfValueNodeFactory
2725     implements NodeFactory, Serializable {
2726     private static final long serialVersionUID = 7249069346764182397L;
2727     public final Node newNode(int locator,
2728 jsr166 1.3 Object key, Object value,
2729 dl 1.1 CustomConcurrentHashMap cchm,
2730     Node linkage) {
2731     if (linkage == null)
2732     return new TerminalIntKeySelfValueNode
2733     (locator, key);
2734     else
2735     return new LinkedIntKeySelfValueNode
2736     (locator, key, linkage);
2737     }
2738 jsr166 1.3 }
2739 dl 1.1
2740 jsr166 1.3 static abstract class IntKeyStrongValueNode
2741 dl 1.1 extends IntKeyNode {
2742     volatile Object value;
2743     IntKeyStrongValueNode(int locator, Object key, Object value) {
2744     super(locator, key);
2745     this.value = value;
2746     }
2747     public final Object getValue() { return value; }
2748     public final void setValue(Object value) { this.value = value; }
2749     public final void onReclamation() { }
2750     }
2751    
2752 jsr166 1.3 static final class TerminalIntKeyStrongValueNode
2753 dl 1.1 extends IntKeyStrongValueNode {
2754     TerminalIntKeyStrongValueNode(int locator,
2755     Object key, Object value) {
2756     super(locator, key, value);
2757     }
2758     public final Node getLinkage() { return null; }
2759     public final void setLinkage(Node r) { }
2760     }
2761    
2762 jsr166 1.3 static final class LinkedIntKeyStrongValueNode
2763 dl 1.1 extends IntKeyStrongValueNode {
2764     volatile Node linkage;
2765     LinkedIntKeyStrongValueNode(int locator,
2766 jsr166 1.3 Object key, Object value,
2767 dl 1.1 Node linkage) {
2768     super(locator, key, value);
2769     this.linkage = linkage;
2770     }
2771     public final Node getLinkage() { return linkage; }
2772     public final void setLinkage(Node r) { linkage = r; }
2773     }
2774    
2775 jsr166 1.3 static final class IntKeyStrongValueNodeFactory
2776 dl 1.1 implements NodeFactory, Serializable {
2777     private static final long serialVersionUID = 7249069346764182397L;
2778     public final Node newNode(int locator,
2779 jsr166 1.3 Object key, Object value,
2780 dl 1.1 CustomConcurrentHashMap cchm,
2781     Node linkage) {
2782     if (linkage == null)
2783     return new TerminalIntKeyStrongValueNode
2784     (locator, key, value);
2785     else
2786     return new LinkedIntKeyStrongValueNode
2787     (locator, key, value, linkage);
2788     }
2789 jsr166 1.3 }
2790 dl 1.1
2791 jsr166 1.3 static abstract class IntKeyIntValueNode
2792 dl 1.1 extends IntKeyNode {
2793     volatile int value;
2794     IntKeyIntValueNode(int locator, Object key, Object value) {
2795     super(locator, key);
2796     this.value = ((Integer)value).intValue();
2797     }
2798     public final Object getValue() { return Integer.valueOf(value); }
2799 jsr166 1.3 public final void setValue(Object value) {
2800 dl 1.1 this.value = ((Integer)value).intValue();
2801     }
2802     public final void onReclamation() { }
2803     }
2804    
2805 jsr166 1.3 static final class TerminalIntKeyIntValueNode
2806 dl 1.1 extends IntKeyIntValueNode {
2807     TerminalIntKeyIntValueNode(int locator,
2808     Object key, Object value) {
2809     super(locator, key, value);
2810     }
2811     public final Node getLinkage() { return null; }
2812     public final void setLinkage(Node r) { }
2813     }
2814    
2815 jsr166 1.3 static final class LinkedIntKeyIntValueNode
2816 dl 1.1 extends IntKeyIntValueNode {
2817     volatile Node linkage;
2818     LinkedIntKeyIntValueNode(int locator,
2819 jsr166 1.3 Object key, Object value,
2820 dl 1.1 Node linkage) {
2821     super(locator, key, value);
2822     this.linkage = linkage;
2823     }
2824     public final Node getLinkage() { return linkage; }
2825     public final void setLinkage(Node r) { linkage = r; }
2826     }
2827    
2828 jsr166 1.3 static final class IntKeyIntValueNodeFactory
2829 dl 1.1 implements NodeFactory, Serializable {
2830     private static final long serialVersionUID = 7249069346764182397L;
2831     public final Node newNode(int locator,
2832 jsr166 1.3 Object key, Object value,
2833 dl 1.1 CustomConcurrentHashMap cchm,
2834     Node linkage) {
2835     if (linkage == null)
2836     return new TerminalIntKeyIntValueNode
2837     (locator, key, value);
2838     else
2839     return new LinkedIntKeyIntValueNode
2840     (locator, key, value, linkage);
2841     }
2842 jsr166 1.3 }
2843 dl 1.1
2844 jsr166 1.3 static abstract class IntKeyWeakValueNode
2845 dl 1.1 extends IntKeyNode {
2846     volatile EmbeddedWeakReference valueRef;
2847     final CustomConcurrentHashMap cchm;
2848 jsr166 1.3 IntKeyWeakValueNode(int locator, Object key, Object value,
2849 dl 1.1 CustomConcurrentHashMap cchm) {
2850     super(locator, key);
2851     this.cchm = cchm;
2852     if (value != null)
2853     this.valueRef = new EmbeddedWeakReference(value, this);
2854     }
2855     public final void onReclamation() {
2856     cchm.removeIfReclaimed(this);
2857     }
2858     public final Object getValue() {
2859     EmbeddedWeakReference vr = valueRef;
2860     return vr == null? null : vr.get();
2861     }
2862     public final void setValue(Object value) {
2863     if (value == null)
2864     valueRef = null;
2865     else
2866     valueRef = new EmbeddedWeakReference(value, this);
2867     }
2868     }
2869    
2870 jsr166 1.3 static final class TerminalIntKeyWeakValueNode
2871 dl 1.1 extends IntKeyWeakValueNode {
2872     TerminalIntKeyWeakValueNode(int locator,
2873 jsr166 1.3 Object key, Object value,
2874 dl 1.1 CustomConcurrentHashMap cchm) {
2875     super(locator, key, value, cchm);
2876     }
2877     public final Node getLinkage() { return null; }
2878     public final void setLinkage(Node r) { }
2879     }
2880    
2881 jsr166 1.3 static final class LinkedIntKeyWeakValueNode
2882 dl 1.1 extends IntKeyWeakValueNode {
2883     volatile Node linkage;
2884     LinkedIntKeyWeakValueNode(int locator,
2885 jsr166 1.3 Object key, Object value,
2886 dl 1.1 CustomConcurrentHashMap cchm,
2887     Node linkage) {
2888     super(locator, key, value, cchm);
2889     this.linkage = linkage;
2890     }
2891     public final Node getLinkage() { return linkage; }
2892     public final void setLinkage(Node r) { linkage = r; }
2893     }
2894    
2895 jsr166 1.3 static final class IntKeyWeakValueNodeFactory
2896 dl 1.1 implements NodeFactory, Serializable {
2897     private static final long serialVersionUID = 7249069346764182397L;
2898 jsr166 1.3 public final Node newNode(int locator,
2899     Object key, Object value,
2900 dl 1.1 CustomConcurrentHashMap cchm,
2901     Node linkage) {
2902     if (linkage == null)
2903     return new TerminalIntKeyWeakValueNode
2904     (locator, key, value, cchm);
2905     else
2906     return new LinkedIntKeyWeakValueNode
2907     (locator, key, value, cchm, linkage);
2908     }
2909 jsr166 1.3 }
2910 dl 1.1
2911    
2912 jsr166 1.3 static abstract class IntKeySoftValueNode
2913 dl 1.1 extends IntKeyNode {
2914     volatile EmbeddedSoftReference valueRef;
2915     final CustomConcurrentHashMap cchm;
2916 jsr166 1.3 IntKeySoftValueNode(int locator, Object key, Object value,
2917 dl 1.1 CustomConcurrentHashMap cchm) {
2918     super(locator, key);
2919     this.cchm = cchm;
2920     if (value != null)
2921     this.valueRef = new EmbeddedSoftReference(value, this);
2922     }
2923     public final void onReclamation() {
2924     cchm.removeIfReclaimed(this);
2925     }
2926     public final Object getValue() {
2927     EmbeddedSoftReference vr = valueRef;
2928     return vr == null? null : vr.get();
2929     }
2930     public final void setValue(Object value) {
2931     if (value == null)
2932     valueRef = null;
2933     else
2934     valueRef = new EmbeddedSoftReference(value, this);
2935     }
2936     }
2937    
2938 jsr166 1.3 static final class TerminalIntKeySoftValueNode
2939 dl 1.1 extends IntKeySoftValueNode {
2940     TerminalIntKeySoftValueNode(int locator,
2941 jsr166 1.3 Object key, Object value,
2942 dl 1.1 CustomConcurrentHashMap cchm) {
2943     super(locator, key, value, cchm);
2944     }
2945     public final Node getLinkage() { return null; }
2946     public final void setLinkage(Node r) { }
2947     }
2948    
2949 jsr166 1.3 static final class LinkedIntKeySoftValueNode
2950 dl 1.1 extends IntKeySoftValueNode {
2951     volatile Node linkage;
2952     LinkedIntKeySoftValueNode(int locator,
2953 jsr166 1.3 Object key, Object value,
2954 dl 1.1 CustomConcurrentHashMap cchm,
2955     Node linkage) {
2956     super(locator, key, value, cchm);
2957     this.linkage = linkage;
2958     }
2959     public final Node getLinkage() { return linkage; }
2960     public final void setLinkage(Node r) { linkage = r; }
2961     }
2962    
2963 jsr166 1.3 static final class IntKeySoftValueNodeFactory
2964 dl 1.1 implements NodeFactory, Serializable {
2965     private static final long serialVersionUID = 7249069346764182397L;
2966 jsr166 1.3 public final Node newNode(int locator,
2967     Object key, Object value,
2968 dl 1.1 CustomConcurrentHashMap cchm,
2969     Node linkage) {
2970     if (linkage == null)
2971     return new TerminalIntKeySoftValueNode
2972     (locator, key, value, cchm);
2973     else
2974     return new LinkedIntKeySoftValueNode
2975     (locator, key, value, cchm, linkage);
2976     }
2977 jsr166 1.3 }
2978 dl 1.1
2979    
2980    
2981     // Temporary Unsafe mechanics for preliminary release
2982    
2983     static final Unsafe _unsafe;
2984     static final long tableBase;
2985     static final int tableShift;
2986     static final long segmentsBase;
2987     static final int segmentsShift;
2988    
2989     private static Unsafe getUnsafe() throws Throwable {
2990     try {
2991     return Unsafe.getUnsafe();
2992     } catch (SecurityException se) {
2993     try {
2994     return java.security.AccessController.doPrivileged
2995     (new java.security.PrivilegedExceptionAction<Unsafe>() {
2996     public Unsafe run() throws Exception {
2997     return getUnsafePrivileged();
2998     }});
2999     } catch (java.security.PrivilegedActionException e) {
3000     throw e.getCause();
3001     }
3002     }
3003     }
3004    
3005     private static Unsafe getUnsafePrivileged()
3006     throws NoSuchFieldException, IllegalAccessException {
3007     Field f = Unsafe.class.getDeclaredField("theUnsafe");
3008     f.setAccessible(true);
3009     return (Unsafe) f.get(null);
3010     }
3011    
3012     static {
3013     try {
3014     _unsafe = getUnsafe();
3015     tableBase = _unsafe.arrayBaseOffset(Node[].class);
3016     int s = _unsafe.arrayIndexScale(Node[].class);
3017     if ((s & (s-1)) != 0)
3018     throw new Error("data type scale not a power of two");
3019     tableShift = 31 - Integer.numberOfLeadingZeros(s);
3020     segmentsBase = _unsafe.arrayBaseOffset(Segment[].class);
3021     s = _unsafe.arrayIndexScale(Segment[].class);
3022     if ((s & (s-1)) != 0)
3023     throw new Error("data type scale not a power of two");
3024     segmentsShift = 31 - Integer.numberOfLeadingZeros(s);
3025     } catch (Throwable e) {
3026     throw new RuntimeException("Could not initialize intrinsics", e);
3027     }
3028     }
3029    
3030     // Fenced store into segment table array. Unneeded when we have Fences
3031 jsr166 1.3 static final void storeNode(Node[] table,
3032 dl 1.1 int i, Node r) {
3033     _unsafe.putOrderedObject(table, (i << tableShift) + tableBase, r);
3034     }
3035    
3036 jsr166 1.3 static final void storeSegment(Segment[] segs,
3037 dl 1.1 int i, Segment s) {
3038     _unsafe.putOrderedObject(segs, (i << segmentsShift) + segmentsBase, s);
3039     }
3040    
3041    
3042     }