ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.11
Committed: Wed Sep 1 23:26:57 2010 UTC (13 years, 8 months ago) by jsr166
Branch: MAIN
Changes since 1.10: +8 -8 lines
Log Message:
coding style

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