ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.4
Committed: Wed Aug 12 04:02:45 2009 UTC (14 years, 9 months ago) by jsr166
Branch: MAIN
Changes since 1.3: +13 -12 lines
Log Message:
typos

File Contents

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