ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/jsr166/jsr166/src/extra166y/CustomConcurrentHashMap.java
Revision: 1.24
Committed: Sun Dec 30 02:05:53 2012 UTC (11 years, 4 months ago) by jsr166
Branch: MAIN
Changes since 1.23: +8 -8 lines
Log Message:
punctuation

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