ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.37
Committed: Sun Sep 13 16:28:13 2015 UTC (8 years, 7 months ago) by jsr166
Branch: MAIN
CVS Tags: HEAD
Changes since 1.36: +13 -13 lines
Log Message:
consistent style for <li> tags, removing </li> end tags

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