ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.31
Committed: Tue Feb 5 17:39:56 2013 UTC (11 years, 3 months ago) by jsr166
Branch: MAIN
Changes since 1.30: +2 -2 lines
Log Message:
javadoc style

File Contents

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