1 /*
2  * Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package java.util;
27 
28 import java.lang.reflect.Array;
29 import java.util.function.BiConsumer;
30 import java.util.function.BiFunction;
31 import java.util.function.Consumer;
32 
33 /**
34  * This class implements the <tt>Map</tt> interface with a hash table, using
35  * reference-equality in place of object-equality when comparing keys (and
36  * values).  In other words, in an <tt>IdentityHashMap</tt>, two keys
37  * <tt>k1</tt> and <tt>k2</tt> are considered equal if and only if
38  * <tt>(k1==k2)</tt>.  (In normal <tt>Map</tt> implementations (like
39  * <tt>HashMap</tt>) two keys <tt>k1</tt> and <tt>k2</tt> are considered equal
40  * if and only if <tt>(k1==null ? k2==null : k1.equals(k2))</tt>.)
41  *
42  * <p><b>This class is <i>not</i> a general-purpose <tt>Map</tt>
43  * implementation!  While this class implements the <tt>Map</tt> interface, it
44  * intentionally violates <tt>Map's</tt> general contract, which mandates the
45  * use of the <tt>equals</tt> method when comparing objects.  This class is
46  * designed for use only in the rare cases wherein reference-equality
47  * semantics are required.</b>
48  *
49  * <p>A typical use of this class is <i>topology-preserving object graph
50  * transformations</i>, such as serialization or deep-copying.  To perform such
51  * a transformation, a program must maintain a "node table" that keeps track
52  * of all the object references that have already been processed.  The node
53  * table must not equate distinct objects even if they happen to be equal.
54  * Another typical use of this class is to maintain <i>proxy objects</i>.  For
55  * example, a debugging facility might wish to maintain a proxy object for
56  * each object in the program being debugged.
57  *
58  * <p>This class provides all of the optional map operations, and permits
59  * <tt>null</tt> values and the <tt>null</tt> key.  This class makes no
60  * guarantees as to the order of the map; in particular, it does not guarantee
61  * that the order will remain constant over time.
62  *
63  * <p>This class provides constant-time performance for the basic
64  * operations (<tt>get</tt> and <tt>put</tt>), assuming the system
65  * identity hash function ({@link System#identityHashCode(Object)})
66  * disperses elements properly among the buckets.
67  *
68  * <p>This class has one tuning parameter (which affects performance but not
69  * semantics): <i>expected maximum size</i>.  This parameter is the maximum
70  * number of key-value mappings that the map is expected to hold.  Internally,
71  * this parameter is used to determine the number of buckets initially
72  * comprising the hash table.  The precise relationship between the expected
73  * maximum size and the number of buckets is unspecified.
74  *
75  * <p>If the size of the map (the number of key-value mappings) sufficiently
76  * exceeds the expected maximum size, the number of buckets is increased.
77  * Increasing the number of buckets ("rehashing") may be fairly expensive, so
78  * it pays to create identity hash maps with a sufficiently large expected
79  * maximum size.  On the other hand, iteration over collection views requires
80  * time proportional to the number of buckets in the hash table, so it
81  * pays not to set the expected maximum size too high if you are especially
82  * concerned with iteration performance or memory usage.
83  *
84  * <p><strong>Note that this implementation is not synchronized.</strong>
85  * If multiple threads access an identity hash map concurrently, and at
86  * least one of the threads modifies the map structurally, it <i>must</i>
87  * be synchronized externally.  (A structural modification is any operation
88  * that adds or deletes one or more mappings; merely changing the value
89  * associated with a key that an instance already contains is not a
90  * structural modification.)  This is typically accomplished by
91  * synchronizing on some object that naturally encapsulates the map.
92  *
93  * If no such object exists, the map should be "wrapped" using the
94  * {@link Collections#synchronizedMap Collections.synchronizedMap}
95  * method.  This is best done at creation time, to prevent accidental
96  * unsynchronized access to the map:<pre>
97  *   Map m = Collections.synchronizedMap(new IdentityHashMap(...));</pre>
98  *
99  * <p>The iterators returned by the <tt>iterator</tt> method of the
100  * collections returned by all of this class's "collection view
101  * methods" are <i>fail-fast</i>: if the map is structurally modified
102  * at any time after the iterator is created, in any way except
103  * through the iterator's own <tt>remove</tt> method, the iterator
104  * will throw a {@link ConcurrentModificationException}.  Thus, in the
105  * face of concurrent modification, the iterator fails quickly and
106  * cleanly, rather than risking arbitrary, non-deterministic behavior
107  * at an undetermined time in the future.
108  *
109  * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
110  * as it is, generally speaking, impossible to make any hard guarantees in the
111  * presence of unsynchronized concurrent modification.  Fail-fast iterators
112  * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
113  * Therefore, it would be wrong to write a program that depended on this
114  * exception for its correctness: <i>fail-fast iterators should be used only
115  * to detect bugs.</i>
116  *
117  * <p>Implementation note: This is a simple <i>linear-probe</i> hash table,
118  * as described for example in texts by Sedgewick and Knuth.  The array
119  * alternates holding keys and values.  (This has better locality for large
120  * tables than does using separate arrays.)  For many JRE implementations
121  * and operation mixes, this class will yield better performance than
122  * {@link HashMap} (which uses <i>chaining</i> rather than linear-probing).
123  *
124  * <p>This class is a member of the
125  * <a href="{@docRoot}/../technotes/guides/collections/index.html">
126  * Java Collections Framework</a>.
127  *
128  * @see     System#identityHashCode(Object)
129  * @see     Object#hashCode()
130  * @see     Collection
131  * @see     Map
132  * @see     HashMap
133  * @see     TreeMap
134  * @author  Doug Lea and Josh Bloch
135  * @since   1.4
136  */
137 
138 public class IdentityHashMap<K,V>
139     extends AbstractMap<K,V>
140     implements Map<K,V>, java.io.Serializable, Cloneable
141 {
142     /**
143      * The initial capacity used by the no-args constructor.
144      * MUST be a power of two.  The value 32 corresponds to the
145      * (specified) expected maximum size of 21, given a load factor
146      * of 2/3.
147      */
148     private static final int DEFAULT_CAPACITY = 32;
149 
150     /**
151      * The minimum capacity, used if a lower value is implicitly specified
152      * by either of the constructors with arguments.  The value 4 corresponds
153      * to an expected maximum size of 2, given a load factor of 2/3.
154      * MUST be a power of two.
155      */
156     private static final int MINIMUM_CAPACITY = 4;
157 
158     /**
159      * The maximum capacity, used if a higher value is implicitly specified
160      * by either of the constructors with arguments.
161      * MUST be a power of two <= 1<<29.
162      *
163      * In fact, the map can hold no more than MAXIMUM_CAPACITY-1 items
164      * because it has to have at least one slot with the key == null
165      * in order to avoid infinite loops in get(), put(), remove()
166      */
167     private static final int MAXIMUM_CAPACITY = 1 << 29;
168 
169     /**
170      * The table, resized as necessary. Length MUST always be a power of two.
171      */
172     transient Object[] table; // non-private to simplify nested class access
173 
174     /**
175      * The number of key-value mappings contained in this identity hash map.
176      *
177      * @serial
178      */
179     int size;
180 
181     /**
182      * The number of modifications, to support fast-fail iterators
183      */
184     transient int modCount;
185 
186     /**
187      * Value representing null keys inside tables.
188      */
189     static final Object NULL_KEY = new Object();
190 
191     /**
192      * Use NULL_KEY for key if it is null.
193      */
maskNull(Object key)194     private static Object maskNull(Object key) {
195         return (key == null ? NULL_KEY : key);
196     }
197 
198     /**
199      * Returns internal representation of null key back to caller as null.
200      */
unmaskNull(Object key)201     static final Object unmaskNull(Object key) {
202         return (key == NULL_KEY ? null : key);
203     }
204 
205     /**
206      * Constructs a new, empty identity hash map with a default expected
207      * maximum size (21).
208      */
IdentityHashMap()209     public IdentityHashMap() {
210         init(DEFAULT_CAPACITY);
211     }
212 
213     /**
214      * Constructs a new, empty map with the specified expected maximum size.
215      * Putting more than the expected number of key-value mappings into
216      * the map may cause the internal data structure to grow, which may be
217      * somewhat time-consuming.
218      *
219      * @param expectedMaxSize the expected maximum size of the map
220      * @throws IllegalArgumentException if <tt>expectedMaxSize</tt> is negative
221      */
IdentityHashMap(int expectedMaxSize)222     public IdentityHashMap(int expectedMaxSize) {
223         if (expectedMaxSize < 0)
224             throw new IllegalArgumentException("expectedMaxSize is negative: "
225                                                + expectedMaxSize);
226         init(capacity(expectedMaxSize));
227     }
228 
229     /**
230      * Returns the appropriate capacity for the given expected maximum size.
231      * Returns the smallest power of two between MINIMUM_CAPACITY and
232      * MAXIMUM_CAPACITY, inclusive, that is greater than (3 *
233      * expectedMaxSize)/2, if such a number exists.  Otherwise returns
234      * MAXIMUM_CAPACITY.
235      */
capacity(int expectedMaxSize)236     private static int capacity(int expectedMaxSize) {
237         // assert expectedMaxSize >= 0;
238         return
239             (expectedMaxSize > MAXIMUM_CAPACITY / 3) ? MAXIMUM_CAPACITY :
240             (expectedMaxSize <= 2 * MINIMUM_CAPACITY / 3) ? MINIMUM_CAPACITY :
241             Integer.highestOneBit(expectedMaxSize + (expectedMaxSize << 1));
242     }
243 
244     /**
245      * Initializes object to be an empty map with the specified initial
246      * capacity, which is assumed to be a power of two between
247      * MINIMUM_CAPACITY and MAXIMUM_CAPACITY inclusive.
248      */
init(int initCapacity)249     private void init(int initCapacity) {
250         // assert (initCapacity & -initCapacity) == initCapacity; // power of 2
251         // assert initCapacity >= MINIMUM_CAPACITY;
252         // assert initCapacity <= MAXIMUM_CAPACITY;
253 
254         table = new Object[2 * initCapacity];
255     }
256 
257     /**
258      * Constructs a new identity hash map containing the keys-value mappings
259      * in the specified map.
260      *
261      * @param m the map whose mappings are to be placed into this map
262      * @throws NullPointerException if the specified map is null
263      */
IdentityHashMap(Map<? extends K, ? extends V> m)264     public IdentityHashMap(Map<? extends K, ? extends V> m) {
265         // Allow for a bit of growth
266         this((int) ((1 + m.size()) * 1.1));
267         putAll(m);
268     }
269 
270     /**
271      * Returns the number of key-value mappings in this identity hash map.
272      *
273      * @return the number of key-value mappings in this map
274      */
size()275     public int size() {
276         return size;
277     }
278 
279     /**
280      * Returns <tt>true</tt> if this identity hash map contains no key-value
281      * mappings.
282      *
283      * @return <tt>true</tt> if this identity hash map contains no key-value
284      *         mappings
285      */
isEmpty()286     public boolean isEmpty() {
287         return size == 0;
288     }
289 
290     /**
291      * Returns index for Object x.
292      */
hash(Object x, int length)293     private static int hash(Object x, int length) {
294         int h = System.identityHashCode(x);
295         // Multiply by -127, and left-shift to use least bit as part of hash
296         return ((h << 1) - (h << 8)) & (length - 1);
297     }
298 
299     /**
300      * Circularly traverses table of size len.
301      */
nextKeyIndex(int i, int len)302     private static int nextKeyIndex(int i, int len) {
303         return (i + 2 < len ? i + 2 : 0);
304     }
305 
306     /**
307      * Returns the value to which the specified key is mapped,
308      * or {@code null} if this map contains no mapping for the key.
309      *
310      * <p>More formally, if this map contains a mapping from a key
311      * {@code k} to a value {@code v} such that {@code (key == k)},
312      * then this method returns {@code v}; otherwise it returns
313      * {@code null}.  (There can be at most one such mapping.)
314      *
315      * <p>A return value of {@code null} does not <i>necessarily</i>
316      * indicate that the map contains no mapping for the key; it's also
317      * possible that the map explicitly maps the key to {@code null}.
318      * The {@link #containsKey containsKey} operation may be used to
319      * distinguish these two cases.
320      *
321      * @see #put(Object, Object)
322      */
323     @SuppressWarnings("unchecked")
get(Object key)324     public V get(Object key) {
325         Object k = maskNull(key);
326         Object[] tab = table;
327         int len = tab.length;
328         int i = hash(k, len);
329         while (true) {
330             Object item = tab[i];
331             if (item == k)
332                 return (V) tab[i + 1];
333             if (item == null)
334                 return null;
335             i = nextKeyIndex(i, len);
336         }
337     }
338 
339     /**
340      * Tests whether the specified object reference is a key in this identity
341      * hash map.
342      *
343      * @param   key   possible key
344      * @return  <code>true</code> if the specified object reference is a key
345      *          in this map
346      * @see     #containsValue(Object)
347      */
containsKey(Object key)348     public boolean containsKey(Object key) {
349         Object k = maskNull(key);
350         Object[] tab = table;
351         int len = tab.length;
352         int i = hash(k, len);
353         while (true) {
354             Object item = tab[i];
355             if (item == k)
356                 return true;
357             if (item == null)
358                 return false;
359             i = nextKeyIndex(i, len);
360         }
361     }
362 
363     /**
364      * Tests whether the specified object reference is a value in this identity
365      * hash map.
366      *
367      * @param value value whose presence in this map is to be tested
368      * @return <tt>true</tt> if this map maps one or more keys to the
369      *         specified object reference
370      * @see     #containsKey(Object)
371      */
containsValue(Object value)372     public boolean containsValue(Object value) {
373         Object[] tab = table;
374         for (int i = 1; i < tab.length; i += 2)
375             if (tab[i] == value && tab[i - 1] != null)
376                 return true;
377 
378         return false;
379     }
380 
381     /**
382      * Tests if the specified key-value mapping is in the map.
383      *
384      * @param   key   possible key
385      * @param   value possible value
386      * @return  <code>true</code> if and only if the specified key-value
387      *          mapping is in the map
388      */
containsMapping(Object key, Object value)389     private boolean containsMapping(Object key, Object value) {
390         Object k = maskNull(key);
391         Object[] tab = table;
392         int len = tab.length;
393         int i = hash(k, len);
394         while (true) {
395             Object item = tab[i];
396             if (item == k)
397                 return tab[i + 1] == value;
398             if (item == null)
399                 return false;
400             i = nextKeyIndex(i, len);
401         }
402     }
403 
404     /**
405      * Associates the specified value with the specified key in this identity
406      * hash map.  If the map previously contained a mapping for the key, the
407      * old value is replaced.
408      *
409      * @param key the key with which the specified value is to be associated
410      * @param value the value to be associated with the specified key
411      * @return the previous value associated with <tt>key</tt>, or
412      *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
413      *         (A <tt>null</tt> return can also indicate that the map
414      *         previously associated <tt>null</tt> with <tt>key</tt>.)
415      * @see     Object#equals(Object)
416      * @see     #get(Object)
417      * @see     #containsKey(Object)
418      */
put(K key, V value)419     public V put(K key, V value) {
420         final Object k = maskNull(key);
421 
422         retryAfterResize: for (;;) {
423             final Object[] tab = table;
424             final int len = tab.length;
425             int i = hash(k, len);
426 
427             for (Object item; (item = tab[i]) != null;
428                  i = nextKeyIndex(i, len)) {
429                 if (item == k) {
430                     @SuppressWarnings("unchecked")
431                         V oldValue = (V) tab[i + 1];
432                     tab[i + 1] = value;
433                     return oldValue;
434                 }
435             }
436 
437             final int s = size + 1;
438             // Use optimized form of 3 * s.
439             // Next capacity is len, 2 * current capacity.
440             if (s + (s << 1) > len && resize(len))
441                 continue retryAfterResize;
442 
443             modCount++;
444             tab[i] = k;
445             tab[i + 1] = value;
446             size = s;
447             return null;
448         }
449     }
450 
451     /**
452      * Resizes the table if necessary to hold given capacity.
453      *
454      * @param newCapacity the new capacity, must be a power of two.
455      * @return whether a resize did in fact take place
456      */
resize(int newCapacity)457     private boolean resize(int newCapacity) {
458         // assert (newCapacity & -newCapacity) == newCapacity; // power of 2
459         int newLength = newCapacity * 2;
460 
461         Object[] oldTable = table;
462         int oldLength = oldTable.length;
463         if (oldLength == 2 * MAXIMUM_CAPACITY) { // can't expand any further
464             if (size == MAXIMUM_CAPACITY - 1)
465                 throw new IllegalStateException("Capacity exhausted.");
466             return false;
467         }
468         if (oldLength >= newLength)
469             return false;
470 
471         Object[] newTable = new Object[newLength];
472 
473         for (int j = 0; j < oldLength; j += 2) {
474             Object key = oldTable[j];
475             if (key != null) {
476                 Object value = oldTable[j+1];
477                 oldTable[j] = null;
478                 oldTable[j+1] = null;
479                 int i = hash(key, newLength);
480                 while (newTable[i] != null)
481                     i = nextKeyIndex(i, newLength);
482                 newTable[i] = key;
483                 newTable[i + 1] = value;
484             }
485         }
486         table = newTable;
487         return true;
488     }
489 
490     /**
491      * Copies all of the mappings from the specified map to this map.
492      * These mappings will replace any mappings that this map had for
493      * any of the keys currently in the specified map.
494      *
495      * @param m mappings to be stored in this map
496      * @throws NullPointerException if the specified map is null
497      */
putAll(Map<? extends K, ? extends V> m)498     public void putAll(Map<? extends K, ? extends V> m) {
499         int n = m.size();
500         if (n == 0)
501             return;
502         if (n > size)
503             resize(capacity(n)); // conservatively pre-expand
504 
505         for (Entry<? extends K, ? extends V> e : m.entrySet())
506             put(e.getKey(), e.getValue());
507     }
508 
509     /**
510      * Removes the mapping for this key from this map if present.
511      *
512      * @param key key whose mapping is to be removed from the map
513      * @return the previous value associated with <tt>key</tt>, or
514      *         <tt>null</tt> if there was no mapping for <tt>key</tt>.
515      *         (A <tt>null</tt> return can also indicate that the map
516      *         previously associated <tt>null</tt> with <tt>key</tt>.)
517      */
remove(Object key)518     public V remove(Object key) {
519         Object k = maskNull(key);
520         Object[] tab = table;
521         int len = tab.length;
522         int i = hash(k, len);
523 
524         while (true) {
525             Object item = tab[i];
526             if (item == k) {
527                 modCount++;
528                 size--;
529                 @SuppressWarnings("unchecked")
530                     V oldValue = (V) tab[i + 1];
531                 tab[i + 1] = null;
532                 tab[i] = null;
533                 closeDeletion(i);
534                 return oldValue;
535             }
536             if (item == null)
537                 return null;
538             i = nextKeyIndex(i, len);
539         }
540     }
541 
542     /**
543      * Removes the specified key-value mapping from the map if it is present.
544      *
545      * @param   key   possible key
546      * @param   value possible value
547      * @return  <code>true</code> if and only if the specified key-value
548      *          mapping was in the map
549      */
removeMapping(Object key, Object value)550     private boolean removeMapping(Object key, Object value) {
551         Object k = maskNull(key);
552         Object[] tab = table;
553         int len = tab.length;
554         int i = hash(k, len);
555 
556         while (true) {
557             Object item = tab[i];
558             if (item == k) {
559                 if (tab[i + 1] != value)
560                     return false;
561                 modCount++;
562                 size--;
563                 tab[i] = null;
564                 tab[i + 1] = null;
565                 closeDeletion(i);
566                 return true;
567             }
568             if (item == null)
569                 return false;
570             i = nextKeyIndex(i, len);
571         }
572     }
573 
574     /**
575      * Rehash all possibly-colliding entries following a
576      * deletion. This preserves the linear-probe
577      * collision properties required by get, put, etc.
578      *
579      * @param d the index of a newly empty deleted slot
580      */
closeDeletion(int d)581     private void closeDeletion(int d) {
582         // Adapted from Knuth Section 6.4 Algorithm R
583         Object[] tab = table;
584         int len = tab.length;
585 
586         // Look for items to swap into newly vacated slot
587         // starting at index immediately following deletion,
588         // and continuing until a null slot is seen, indicating
589         // the end of a run of possibly-colliding keys.
590         Object item;
591         for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
592              i = nextKeyIndex(i, len) ) {
593             // The following test triggers if the item at slot i (which
594             // hashes to be at slot r) should take the spot vacated by d.
595             // If so, we swap it in, and then continue with d now at the
596             // newly vacated i.  This process will terminate when we hit
597             // the null slot at the end of this run.
598             // The test is messy because we are using a circular table.
599             int r = hash(item, len);
600             if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) {
601                 tab[d] = item;
602                 tab[d + 1] = tab[i + 1];
603                 tab[i] = null;
604                 tab[i + 1] = null;
605                 d = i;
606             }
607         }
608     }
609 
610     /**
611      * Removes all of the mappings from this map.
612      * The map will be empty after this call returns.
613      */
clear()614     public void clear() {
615         modCount++;
616         Object[] tab = table;
617         for (int i = 0; i < tab.length; i++)
618             tab[i] = null;
619         size = 0;
620     }
621 
622     /**
623      * Compares the specified object with this map for equality.  Returns
624      * <tt>true</tt> if the given object is also a map and the two maps
625      * represent identical object-reference mappings.  More formally, this
626      * map is equal to another map <tt>m</tt> if and only if
627      * <tt>this.entrySet().equals(m.entrySet())</tt>.
628      *
629      * <p><b>Owing to the reference-equality-based semantics of this map it is
630      * possible that the symmetry and transitivity requirements of the
631      * <tt>Object.equals</tt> contract may be violated if this map is compared
632      * to a normal map.  However, the <tt>Object.equals</tt> contract is
633      * guaranteed to hold among <tt>IdentityHashMap</tt> instances.</b>
634      *
635      * @param  o object to be compared for equality with this map
636      * @return <tt>true</tt> if the specified object is equal to this map
637      * @see Object#equals(Object)
638      */
equals(Object o)639     public boolean equals(Object o) {
640         if (o == this) {
641             return true;
642         } else if (o instanceof IdentityHashMap) {
643             IdentityHashMap<?,?> m = (IdentityHashMap<?,?>) o;
644             if (m.size() != size)
645                 return false;
646 
647             Object[] tab = m.table;
648             for (int i = 0; i < tab.length; i+=2) {
649                 Object k = tab[i];
650                 if (k != null && !containsMapping(k, tab[i + 1]))
651                     return false;
652             }
653             return true;
654         } else if (o instanceof Map) {
655             Map<?,?> m = (Map<?,?>)o;
656             return entrySet().equals(m.entrySet());
657         } else {
658             return false;  // o is not a Map
659         }
660     }
661 
662     /**
663      * Returns the hash code value for this map.  The hash code of a map is
664      * defined to be the sum of the hash codes of each entry in the map's
665      * <tt>entrySet()</tt> view.  This ensures that <tt>m1.equals(m2)</tt>
666      * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two
667      * <tt>IdentityHashMap</tt> instances <tt>m1</tt> and <tt>m2</tt>, as
668      * required by the general contract of {@link Object#hashCode}.
669      *
670      * <p><b>Owing to the reference-equality-based semantics of the
671      * <tt>Map.Entry</tt> instances in the set returned by this map's
672      * <tt>entrySet</tt> method, it is possible that the contractual
673      * requirement of <tt>Object.hashCode</tt> mentioned in the previous
674      * paragraph will be violated if one of the two objects being compared is
675      * an <tt>IdentityHashMap</tt> instance and the other is a normal map.</b>
676      *
677      * @return the hash code value for this map
678      * @see Object#equals(Object)
679      * @see #equals(Object)
680      */
hashCode()681     public int hashCode() {
682         int result = 0;
683         Object[] tab = table;
684         for (int i = 0; i < tab.length; i +=2) {
685             Object key = tab[i];
686             if (key != null) {
687                 Object k = unmaskNull(key);
688                 result += System.identityHashCode(k) ^
689                           System.identityHashCode(tab[i + 1]);
690             }
691         }
692         return result;
693     }
694 
695     /**
696      * Returns a shallow copy of this identity hash map: the keys and values
697      * themselves are not cloned.
698      *
699      * @return a shallow copy of this map
700      */
clone()701     public Object clone() {
702         try {
703             IdentityHashMap<?,?> m = (IdentityHashMap<?,?>) super.clone();
704             m.entrySet = null;
705             m.table = table.clone();
706             return m;
707         } catch (CloneNotSupportedException e) {
708             throw new InternalError(e);
709         }
710     }
711 
712     private abstract class IdentityHashMapIterator<T> implements Iterator<T> {
713         int index = (size != 0 ? 0 : table.length); // current slot.
714         int expectedModCount = modCount; // to support fast-fail
715         int lastReturnedIndex = -1;      // to allow remove()
716         boolean indexValid; // To avoid unnecessary next computation
717         Object[] traversalTable = table; // reference to main table or copy
718 
hasNext()719         public boolean hasNext() {
720             Object[] tab = traversalTable;
721             for (int i = index; i < tab.length; i+=2) {
722                 Object key = tab[i];
723                 if (key != null) {
724                     index = i;
725                     return indexValid = true;
726                 }
727             }
728             index = tab.length;
729             return false;
730         }
731 
nextIndex()732         protected int nextIndex() {
733             if (modCount != expectedModCount)
734                 throw new ConcurrentModificationException();
735             if (!indexValid && !hasNext())
736                 throw new NoSuchElementException();
737 
738             indexValid = false;
739             lastReturnedIndex = index;
740             index += 2;
741             return lastReturnedIndex;
742         }
743 
remove()744         public void remove() {
745             if (lastReturnedIndex == -1)
746                 throw new IllegalStateException();
747             if (modCount != expectedModCount)
748                 throw new ConcurrentModificationException();
749 
750             expectedModCount = ++modCount;
751             int deletedSlot = lastReturnedIndex;
752             lastReturnedIndex = -1;
753             // back up index to revisit new contents after deletion
754             index = deletedSlot;
755             indexValid = false;
756 
757             // Removal code proceeds as in closeDeletion except that
758             // it must catch the rare case where an element already
759             // seen is swapped into a vacant slot that will be later
760             // traversed by this iterator. We cannot allow future
761             // next() calls to return it again.  The likelihood of
762             // this occurring under 2/3 load factor is very slim, but
763             // when it does happen, we must make a copy of the rest of
764             // the table to use for the rest of the traversal. Since
765             // this can only happen when we are near the end of the table,
766             // even in these rare cases, this is not very expensive in
767             // time or space.
768 
769             Object[] tab = traversalTable;
770             int len = tab.length;
771 
772             int d = deletedSlot;
773             Object key = tab[d];
774             tab[d] = null;        // vacate the slot
775             tab[d + 1] = null;
776 
777             // If traversing a copy, remove in real table.
778             // We can skip gap-closure on copy.
779             if (tab != IdentityHashMap.this.table) {
780                 IdentityHashMap.this.remove(key);
781                 expectedModCount = modCount;
782                 return;
783             }
784 
785             size--;
786 
787             Object item;
788             for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
789                  i = nextKeyIndex(i, len)) {
790                 int r = hash(item, len);
791                 // See closeDeletion for explanation of this conditional
792                 if ((i < r && (r <= d || d <= i)) ||
793                     (r <= d && d <= i)) {
794 
795                     // If we are about to swap an already-seen element
796                     // into a slot that may later be returned by next(),
797                     // then clone the rest of table for use in future
798                     // next() calls. It is OK that our copy will have
799                     // a gap in the "wrong" place, since it will never
800                     // be used for searching anyway.
801 
802                     if (i < deletedSlot && d >= deletedSlot &&
803                         traversalTable == IdentityHashMap.this.table) {
804                         int remaining = len - deletedSlot;
805                         Object[] newTable = new Object[remaining];
806                         System.arraycopy(tab, deletedSlot,
807                                          newTable, 0, remaining);
808                         traversalTable = newTable;
809                         index = 0;
810                     }
811 
812                     tab[d] = item;
813                     tab[d + 1] = tab[i + 1];
814                     tab[i] = null;
815                     tab[i + 1] = null;
816                     d = i;
817                 }
818             }
819         }
820     }
821 
822     private class KeyIterator extends IdentityHashMapIterator<K> {
823         @SuppressWarnings("unchecked")
next()824         public K next() {
825             return (K) unmaskNull(traversalTable[nextIndex()]);
826         }
827     }
828 
829     private class ValueIterator extends IdentityHashMapIterator<V> {
830         @SuppressWarnings("unchecked")
next()831         public V next() {
832             return (V) traversalTable[nextIndex() + 1];
833         }
834     }
835 
836     private class EntryIterator
837         extends IdentityHashMapIterator<Map.Entry<K,V>>
838     {
839         private Entry lastReturnedEntry;
840 
next()841         public Map.Entry<K,V> next() {
842             lastReturnedEntry = new Entry(nextIndex());
843             return lastReturnedEntry;
844         }
845 
remove()846         public void remove() {
847             lastReturnedIndex =
848                 ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
849             super.remove();
850             lastReturnedEntry.index = lastReturnedIndex;
851             lastReturnedEntry = null;
852         }
853 
854         private class Entry implements Map.Entry<K,V> {
855             private int index;
856 
Entry(int index)857             private Entry(int index) {
858                 this.index = index;
859             }
860 
861             @SuppressWarnings("unchecked")
getKey()862             public K getKey() {
863                 checkIndexForEntryUse();
864                 return (K) unmaskNull(traversalTable[index]);
865             }
866 
867             @SuppressWarnings("unchecked")
getValue()868             public V getValue() {
869                 checkIndexForEntryUse();
870                 return (V) traversalTable[index+1];
871             }
872 
873             @SuppressWarnings("unchecked")
setValue(V value)874             public V setValue(V value) {
875                 checkIndexForEntryUse();
876                 V oldValue = (V) traversalTable[index+1];
877                 traversalTable[index+1] = value;
878                 // if shadowing, force into main table
879                 if (traversalTable != IdentityHashMap.this.table)
880                     put((K) traversalTable[index], value);
881                 return oldValue;
882             }
883 
equals(Object o)884             public boolean equals(Object o) {
885                 if (index < 0)
886                     return super.equals(o);
887 
888                 if (!(o instanceof Map.Entry))
889                     return false;
890                 Map.Entry<?,?> e = (Map.Entry<?,?>)o;
891                 return (e.getKey() == unmaskNull(traversalTable[index]) &&
892                        e.getValue() == traversalTable[index+1]);
893             }
894 
hashCode()895             public int hashCode() {
896                 if (lastReturnedIndex < 0)
897                     return super.hashCode();
898 
899                 return (System.identityHashCode(unmaskNull(traversalTable[index])) ^
900                        System.identityHashCode(traversalTable[index+1]));
901             }
902 
toString()903             public String toString() {
904                 if (index < 0)
905                     return super.toString();
906 
907                 return (unmaskNull(traversalTable[index]) + "="
908                         + traversalTable[index+1]);
909             }
910 
checkIndexForEntryUse()911             private void checkIndexForEntryUse() {
912                 if (index < 0)
913                     throw new IllegalStateException("Entry was removed");
914             }
915         }
916     }
917 
918     // Views
919 
920     /**
921      * This field is initialized to contain an instance of the entry set
922      * view the first time this view is requested.  The view is stateless,
923      * so there's no reason to create more than one.
924      */
925     private transient Set<Map.Entry<K,V>> entrySet;
926 
927     /**
928      * Returns an identity-based set view of the keys contained in this map.
929      * The set is backed by the map, so changes to the map are reflected in
930      * the set, and vice-versa.  If the map is modified while an iteration
931      * over the set is in progress, the results of the iteration are
932      * undefined.  The set supports element removal, which removes the
933      * corresponding mapping from the map, via the <tt>Iterator.remove</tt>,
934      * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
935      * <tt>clear</tt> methods.  It does not support the <tt>add</tt> or
936      * <tt>addAll</tt> methods.
937      *
938      * <p><b>While the object returned by this method implements the
939      * <tt>Set</tt> interface, it does <i>not</i> obey <tt>Set's</tt> general
940      * contract.  Like its backing map, the set returned by this method
941      * defines element equality as reference-equality rather than
942      * object-equality.  This affects the behavior of its <tt>contains</tt>,
943      * <tt>remove</tt>, <tt>containsAll</tt>, <tt>equals</tt>, and
944      * <tt>hashCode</tt> methods.</b>
945      *
946      * <p><b>The <tt>equals</tt> method of the returned set returns <tt>true</tt>
947      * only if the specified object is a set containing exactly the same
948      * object references as the returned set.  The symmetry and transitivity
949      * requirements of the <tt>Object.equals</tt> contract may be violated if
950      * the set returned by this method is compared to a normal set.  However,
951      * the <tt>Object.equals</tt> contract is guaranteed to hold among sets
952      * returned by this method.</b>
953      *
954      * <p>The <tt>hashCode</tt> method of the returned set returns the sum of
955      * the <i>identity hashcodes</i> of the elements in the set, rather than
956      * the sum of their hashcodes.  This is mandated by the change in the
957      * semantics of the <tt>equals</tt> method, in order to enforce the
958      * general contract of the <tt>Object.hashCode</tt> method among sets
959      * returned by this method.
960      *
961      * @return an identity-based set view of the keys contained in this map
962      * @see Object#equals(Object)
963      * @see System#identityHashCode(Object)
964      */
keySet()965     public Set<K> keySet() {
966         Set<K> ks = keySet;
967         if (ks == null) {
968             ks = new KeySet();
969             keySet = ks;
970         }
971         return ks;
972     }
973 
974     private class KeySet extends AbstractSet<K> {
iterator()975         public Iterator<K> iterator() {
976             return new KeyIterator();
977         }
size()978         public int size() {
979             return size;
980         }
contains(Object o)981         public boolean contains(Object o) {
982             return containsKey(o);
983         }
remove(Object o)984         public boolean remove(Object o) {
985             int oldSize = size;
986             IdentityHashMap.this.remove(o);
987             return size != oldSize;
988         }
989         /*
990          * Must revert from AbstractSet's impl to AbstractCollection's, as
991          * the former contains an optimization that results in incorrect
992          * behavior when c is a smaller "normal" (non-identity-based) Set.
993          */
removeAll(Collection<?> c)994         public boolean removeAll(Collection<?> c) {
995             Objects.requireNonNull(c);
996             boolean modified = false;
997             for (Iterator<K> i = iterator(); i.hasNext(); ) {
998                 if (c.contains(i.next())) {
999                     i.remove();
1000                     modified = true;
1001                 }
1002             }
1003             return modified;
1004         }
clear()1005         public void clear() {
1006             IdentityHashMap.this.clear();
1007         }
hashCode()1008         public int hashCode() {
1009             int result = 0;
1010             for (K key : this)
1011                 result += System.identityHashCode(key);
1012             return result;
1013         }
toArray()1014         public Object[] toArray() {
1015             return toArray(new Object[0]);
1016         }
1017         @SuppressWarnings("unchecked")
toArray(T[] a)1018         public <T> T[] toArray(T[] a) {
1019             int expectedModCount = modCount;
1020             int size = size();
1021             if (a.length < size)
1022                 a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
1023             Object[] tab = table;
1024             int ti = 0;
1025             for (int si = 0; si < tab.length; si += 2) {
1026                 Object key;
1027                 if ((key = tab[si]) != null) { // key present ?
1028                     // more elements than expected -> concurrent modification from other thread
1029                     if (ti >= size) {
1030                         throw new ConcurrentModificationException();
1031                     }
1032                     a[ti++] = (T) unmaskNull(key); // unmask key
1033                 }
1034             }
1035             // fewer elements than expected or concurrent modification from other thread detected
1036             if (ti < size || expectedModCount != modCount) {
1037                 throw new ConcurrentModificationException();
1038             }
1039             // final null marker as per spec
1040             if (ti < a.length) {
1041                 a[ti] = null;
1042             }
1043             return a;
1044         }
1045 
spliterator()1046         public Spliterator<K> spliterator() {
1047             return new KeySpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
1048         }
1049     }
1050 
1051     /**
1052      * Returns a {@link Collection} view of the values contained in this map.
1053      * The collection is backed by the map, so changes to the map are
1054      * reflected in the collection, and vice-versa.  If the map is
1055      * modified while an iteration over the collection is in progress,
1056      * the results of the iteration are undefined.  The collection
1057      * supports element removal, which removes the corresponding
1058      * mapping from the map, via the <tt>Iterator.remove</tt>,
1059      * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
1060      * <tt>retainAll</tt> and <tt>clear</tt> methods.  It does not
1061      * support the <tt>add</tt> or <tt>addAll</tt> methods.
1062      *
1063      * <p><b>While the object returned by this method implements the
1064      * <tt>Collection</tt> interface, it does <i>not</i> obey
1065      * <tt>Collection's</tt> general contract.  Like its backing map,
1066      * the collection returned by this method defines element equality as
1067      * reference-equality rather than object-equality.  This affects the
1068      * behavior of its <tt>contains</tt>, <tt>remove</tt> and
1069      * <tt>containsAll</tt> methods.</b>
1070      */
values()1071     public Collection<V> values() {
1072         Collection<V> vs = values;
1073         if (vs == null) {
1074             vs = new Values();
1075             values = vs;
1076         }
1077         return vs;
1078     }
1079 
1080     private class Values extends AbstractCollection<V> {
iterator()1081         public Iterator<V> iterator() {
1082             return new ValueIterator();
1083         }
size()1084         public int size() {
1085             return size;
1086         }
contains(Object o)1087         public boolean contains(Object o) {
1088             return containsValue(o);
1089         }
remove(Object o)1090         public boolean remove(Object o) {
1091             for (Iterator<V> i = iterator(); i.hasNext(); ) {
1092                 if (i.next() == o) {
1093                     i.remove();
1094                     return true;
1095                 }
1096             }
1097             return false;
1098         }
clear()1099         public void clear() {
1100             IdentityHashMap.this.clear();
1101         }
toArray()1102         public Object[] toArray() {
1103             return toArray(new Object[0]);
1104         }
1105         @SuppressWarnings("unchecked")
toArray(T[] a)1106         public <T> T[] toArray(T[] a) {
1107             int expectedModCount = modCount;
1108             int size = size();
1109             if (a.length < size)
1110                 a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
1111             Object[] tab = table;
1112             int ti = 0;
1113             for (int si = 0; si < tab.length; si += 2) {
1114                 if (tab[si] != null) { // key present ?
1115                     // more elements than expected -> concurrent modification from other thread
1116                     if (ti >= size) {
1117                         throw new ConcurrentModificationException();
1118                     }
1119                     a[ti++] = (T) tab[si+1]; // copy value
1120                 }
1121             }
1122             // fewer elements than expected or concurrent modification from other thread detected
1123             if (ti < size || expectedModCount != modCount) {
1124                 throw new ConcurrentModificationException();
1125             }
1126             // final null marker as per spec
1127             if (ti < a.length) {
1128                 a[ti] = null;
1129             }
1130             return a;
1131         }
1132 
spliterator()1133         public Spliterator<V> spliterator() {
1134             return new ValueSpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
1135         }
1136     }
1137 
1138     /**
1139      * Returns a {@link Set} view of the mappings contained in this map.
1140      * Each element in the returned set is a reference-equality-based
1141      * <tt>Map.Entry</tt>.  The set is backed by the map, so changes
1142      * to the map are reflected in the set, and vice-versa.  If the
1143      * map is modified while an iteration over the set is in progress,
1144      * the results of the iteration are undefined.  The set supports
1145      * element removal, which removes the corresponding mapping from
1146      * the map, via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
1147      * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt>
1148      * methods.  It does not support the <tt>add</tt> or
1149      * <tt>addAll</tt> methods.
1150      *
1151      * <p>Like the backing map, the <tt>Map.Entry</tt> objects in the set
1152      * returned by this method define key and value equality as
1153      * reference-equality rather than object-equality.  This affects the
1154      * behavior of the <tt>equals</tt> and <tt>hashCode</tt> methods of these
1155      * <tt>Map.Entry</tt> objects.  A reference-equality based <tt>Map.Entry
1156      * e</tt> is equal to an object <tt>o</tt> if and only if <tt>o</tt> is a
1157      * <tt>Map.Entry</tt> and <tt>e.getKey()==o.getKey() &amp;&amp;
1158      * e.getValue()==o.getValue()</tt>.  To accommodate these equals
1159      * semantics, the <tt>hashCode</tt> method returns
1160      * <tt>System.identityHashCode(e.getKey()) ^
1161      * System.identityHashCode(e.getValue())</tt>.
1162      *
1163      * <p><b>Owing to the reference-equality-based semantics of the
1164      * <tt>Map.Entry</tt> instances in the set returned by this method,
1165      * it is possible that the symmetry and transitivity requirements of
1166      * the {@link Object#equals(Object)} contract may be violated if any of
1167      * the entries in the set is compared to a normal map entry, or if
1168      * the set returned by this method is compared to a set of normal map
1169      * entries (such as would be returned by a call to this method on a normal
1170      * map).  However, the <tt>Object.equals</tt> contract is guaranteed to
1171      * hold among identity-based map entries, and among sets of such entries.
1172      * </b>
1173      *
1174      * @return a set view of the identity-mappings contained in this map
1175      */
entrySet()1176     public Set<Map.Entry<K,V>> entrySet() {
1177         Set<Map.Entry<K,V>> es = entrySet;
1178         if (es != null)
1179             return es;
1180         else
1181             return entrySet = new EntrySet();
1182     }
1183 
1184     private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
iterator()1185         public Iterator<Map.Entry<K,V>> iterator() {
1186             return new EntryIterator();
1187         }
contains(Object o)1188         public boolean contains(Object o) {
1189             if (!(o instanceof Map.Entry))
1190                 return false;
1191             Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
1192             return containsMapping(entry.getKey(), entry.getValue());
1193         }
remove(Object o)1194         public boolean remove(Object o) {
1195             if (!(o instanceof Map.Entry))
1196                 return false;
1197             Map.Entry<?,?> entry = (Map.Entry<?,?>)o;
1198             return removeMapping(entry.getKey(), entry.getValue());
1199         }
size()1200         public int size() {
1201             return size;
1202         }
clear()1203         public void clear() {
1204             IdentityHashMap.this.clear();
1205         }
1206         /*
1207          * Must revert from AbstractSet's impl to AbstractCollection's, as
1208          * the former contains an optimization that results in incorrect
1209          * behavior when c is a smaller "normal" (non-identity-based) Set.
1210          */
removeAll(Collection<?> c)1211         public boolean removeAll(Collection<?> c) {
1212             Objects.requireNonNull(c);
1213             boolean modified = false;
1214             for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) {
1215                 if (c.contains(i.next())) {
1216                     i.remove();
1217                     modified = true;
1218                 }
1219             }
1220             return modified;
1221         }
1222 
toArray()1223         public Object[] toArray() {
1224             return toArray(new Object[0]);
1225         }
1226 
1227         @SuppressWarnings("unchecked")
toArray(T[] a)1228         public <T> T[] toArray(T[] a) {
1229             int expectedModCount = modCount;
1230             int size = size();
1231             if (a.length < size)
1232                 a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);
1233             Object[] tab = table;
1234             int ti = 0;
1235             for (int si = 0; si < tab.length; si += 2) {
1236                 Object key;
1237                 if ((key = tab[si]) != null) { // key present ?
1238                     // more elements than expected -> concurrent modification from other thread
1239                     if (ti >= size) {
1240                         throw new ConcurrentModificationException();
1241                     }
1242                     a[ti++] = (T) new AbstractMap.SimpleEntry<>(unmaskNull(key), tab[si + 1]);
1243                 }
1244             }
1245             // fewer elements than expected or concurrent modification from other thread detected
1246             if (ti < size || expectedModCount != modCount) {
1247                 throw new ConcurrentModificationException();
1248             }
1249             // final null marker as per spec
1250             if (ti < a.length) {
1251                 a[ti] = null;
1252             }
1253             return a;
1254         }
1255 
spliterator()1256         public Spliterator<Map.Entry<K,V>> spliterator() {
1257             return new EntrySpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);
1258         }
1259     }
1260 
1261 
1262     private static final long serialVersionUID = 8188218128353913216L;
1263 
1264     /**
1265      * Saves the state of the <tt>IdentityHashMap</tt> instance to a stream
1266      * (i.e., serializes it).
1267      *
1268      * @serialData The <i>size</i> of the HashMap (the number of key-value
1269      *          mappings) (<tt>int</tt>), followed by the key (Object) and
1270      *          value (Object) for each key-value mapping represented by the
1271      *          IdentityHashMap.  The key-value mappings are emitted in no
1272      *          particular order.
1273      */
writeObject(java.io.ObjectOutputStream s)1274     private void writeObject(java.io.ObjectOutputStream s)
1275         throws java.io.IOException  {
1276         // Write out and any hidden stuff
1277         s.defaultWriteObject();
1278 
1279         // Write out size (number of Mappings)
1280         s.writeInt(size);
1281 
1282         // Write out keys and values (alternating)
1283         Object[] tab = table;
1284         for (int i = 0; i < tab.length; i += 2) {
1285             Object key = tab[i];
1286             if (key != null) {
1287                 s.writeObject(unmaskNull(key));
1288                 s.writeObject(tab[i + 1]);
1289             }
1290         }
1291     }
1292 
1293     /**
1294      * Reconstitutes the <tt>IdentityHashMap</tt> instance from a stream (i.e.,
1295      * deserializes it).
1296      */
readObject(java.io.ObjectInputStream s)1297     private void readObject(java.io.ObjectInputStream s)
1298         throws java.io.IOException, ClassNotFoundException  {
1299         // Read in any hidden stuff
1300         s.defaultReadObject();
1301 
1302         // Read in size (number of Mappings)
1303         int size = s.readInt();
1304         if (size < 0)
1305             throw new java.io.StreamCorruptedException
1306                 ("Illegal mappings count: " + size);
1307         init(capacity(size));
1308 
1309         // Read the keys and values, and put the mappings in the table
1310         for (int i=0; i<size; i++) {
1311             @SuppressWarnings("unchecked")
1312                 K key = (K) s.readObject();
1313             @SuppressWarnings("unchecked")
1314                 V value = (V) s.readObject();
1315             putForCreate(key, value);
1316         }
1317     }
1318 
1319     /**
1320      * The put method for readObject.  It does not resize the table,
1321      * update modCount, etc.
1322      */
putForCreate(K key, V value)1323     private void putForCreate(K key, V value)
1324         throws java.io.StreamCorruptedException
1325     {
1326         Object k = maskNull(key);
1327         Object[] tab = table;
1328         int len = tab.length;
1329         int i = hash(k, len);
1330 
1331         Object item;
1332         while ( (item = tab[i]) != null) {
1333             if (item == k)
1334                 throw new java.io.StreamCorruptedException();
1335             i = nextKeyIndex(i, len);
1336         }
1337         tab[i] = k;
1338         tab[i + 1] = value;
1339     }
1340 
1341     @SuppressWarnings("unchecked")
1342     @Override
forEach(BiConsumer<? super K, ? super V> action)1343     public void forEach(BiConsumer<? super K, ? super V> action) {
1344         Objects.requireNonNull(action);
1345         int expectedModCount = modCount;
1346 
1347         Object[] t = table;
1348         for (int index = 0; index < t.length; index += 2) {
1349             Object k = t[index];
1350             if (k != null) {
1351                 action.accept((K) unmaskNull(k), (V) t[index + 1]);
1352             }
1353 
1354             if (modCount != expectedModCount) {
1355                 throw new ConcurrentModificationException();
1356             }
1357         }
1358     }
1359 
1360     @SuppressWarnings("unchecked")
1361     @Override
replaceAll(BiFunction<? super K, ? super V, ? extends V> function)1362     public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
1363         Objects.requireNonNull(function);
1364         int expectedModCount = modCount;
1365 
1366         Object[] t = table;
1367         for (int index = 0; index < t.length; index += 2) {
1368             Object k = t[index];
1369             if (k != null) {
1370                 t[index + 1] = function.apply((K) unmaskNull(k), (V) t[index + 1]);
1371             }
1372 
1373             if (modCount != expectedModCount) {
1374                 throw new ConcurrentModificationException();
1375             }
1376         }
1377     }
1378 
1379     /**
1380      * Similar form as array-based Spliterators, but skips blank elements,
1381      * and guestimates size as decreasing by half per split.
1382      */
1383     static class IdentityHashMapSpliterator<K,V> {
1384         final IdentityHashMap<K,V> map;
1385         int index;             // current index, modified on advance/split
1386         int fence;             // -1 until first use; then one past last index
1387         int est;               // size estimate
1388         int expectedModCount;  // initialized when fence set
1389 
IdentityHashMapSpliterator(IdentityHashMap<K,V> map, int origin, int fence, int est, int expectedModCount)1390         IdentityHashMapSpliterator(IdentityHashMap<K,V> map, int origin,
1391                                    int fence, int est, int expectedModCount) {
1392             this.map = map;
1393             this.index = origin;
1394             this.fence = fence;
1395             this.est = est;
1396             this.expectedModCount = expectedModCount;
1397         }
1398 
getFence()1399         final int getFence() { // initialize fence and size on first use
1400             int hi;
1401             if ((hi = fence) < 0) {
1402                 est = map.size;
1403                 expectedModCount = map.modCount;
1404                 hi = fence = map.table.length;
1405             }
1406             return hi;
1407         }
1408 
estimateSize()1409         public final long estimateSize() {
1410             getFence(); // force init
1411             return (long) est;
1412         }
1413     }
1414 
1415     static final class KeySpliterator<K,V>
1416         extends IdentityHashMapSpliterator<K,V>
1417         implements Spliterator<K> {
KeySpliterator(IdentityHashMap<K,V> map, int origin, int fence, int est, int expectedModCount)1418         KeySpliterator(IdentityHashMap<K,V> map, int origin, int fence, int est,
1419                        int expectedModCount) {
1420             super(map, origin, fence, est, expectedModCount);
1421         }
1422 
trySplit()1423         public KeySpliterator<K,V> trySplit() {
1424             int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
1425             return (lo >= mid) ? null :
1426                 new KeySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
1427                                         expectedModCount);
1428         }
1429 
1430         @SuppressWarnings("unchecked")
forEachRemaining(Consumer<? super K> action)1431         public void forEachRemaining(Consumer<? super K> action) {
1432             if (action == null)
1433                 throw new NullPointerException();
1434             int i, hi, mc; Object key;
1435             IdentityHashMap<K,V> m; Object[] a;
1436             if ((m = map) != null && (a = m.table) != null &&
1437                 (i = index) >= 0 && (index = hi = getFence()) <= a.length) {
1438                 for (; i < hi; i += 2) {
1439                     if ((key = a[i]) != null)
1440                         action.accept((K)unmaskNull(key));
1441                 }
1442                 if (m.modCount == expectedModCount)
1443                     return;
1444             }
1445             throw new ConcurrentModificationException();
1446         }
1447 
1448         @SuppressWarnings("unchecked")
tryAdvance(Consumer<? super K> action)1449         public boolean tryAdvance(Consumer<? super K> action) {
1450             if (action == null)
1451                 throw new NullPointerException();
1452             Object[] a = map.table;
1453             int hi = getFence();
1454             while (index < hi) {
1455                 Object key = a[index];
1456                 index += 2;
1457                 if (key != null) {
1458                     action.accept((K)unmaskNull(key));
1459                     if (map.modCount != expectedModCount)
1460                         throw new ConcurrentModificationException();
1461                     return true;
1462                 }
1463             }
1464             return false;
1465         }
1466 
characteristics()1467         public int characteristics() {
1468             return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT;
1469         }
1470     }
1471 
1472     static final class ValueSpliterator<K,V>
1473         extends IdentityHashMapSpliterator<K,V>
1474         implements Spliterator<V> {
ValueSpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est, int expectedModCount)1475         ValueSpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est,
1476                          int expectedModCount) {
1477             super(m, origin, fence, est, expectedModCount);
1478         }
1479 
trySplit()1480         public ValueSpliterator<K,V> trySplit() {
1481             int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
1482             return (lo >= mid) ? null :
1483                 new ValueSpliterator<K,V>(map, lo, index = mid, est >>>= 1,
1484                                           expectedModCount);
1485         }
1486 
forEachRemaining(Consumer<? super V> action)1487         public void forEachRemaining(Consumer<? super V> action) {
1488             if (action == null)
1489                 throw new NullPointerException();
1490             int i, hi, mc;
1491             IdentityHashMap<K,V> m; Object[] a;
1492             if ((m = map) != null && (a = m.table) != null &&
1493                 (i = index) >= 0 && (index = hi = getFence()) <= a.length) {
1494                 for (; i < hi; i += 2) {
1495                     if (a[i] != null) {
1496                         @SuppressWarnings("unchecked") V v = (V)a[i+1];
1497                         action.accept(v);
1498                     }
1499                 }
1500                 if (m.modCount == expectedModCount)
1501                     return;
1502             }
1503             throw new ConcurrentModificationException();
1504         }
1505 
tryAdvance(Consumer<? super V> action)1506         public boolean tryAdvance(Consumer<? super V> action) {
1507             if (action == null)
1508                 throw new NullPointerException();
1509             Object[] a = map.table;
1510             int hi = getFence();
1511             while (index < hi) {
1512                 Object key = a[index];
1513                 @SuppressWarnings("unchecked") V v = (V)a[index+1];
1514                 index += 2;
1515                 if (key != null) {
1516                     action.accept(v);
1517                     if (map.modCount != expectedModCount)
1518                         throw new ConcurrentModificationException();
1519                     return true;
1520                 }
1521             }
1522             return false;
1523         }
1524 
characteristics()1525         public int characteristics() {
1526             return (fence < 0 || est == map.size ? SIZED : 0);
1527         }
1528 
1529     }
1530 
1531     static final class EntrySpliterator<K,V>
1532         extends IdentityHashMapSpliterator<K,V>
1533         implements Spliterator<Map.Entry<K,V>> {
EntrySpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est, int expectedModCount)1534         EntrySpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est,
1535                          int expectedModCount) {
1536             super(m, origin, fence, est, expectedModCount);
1537         }
1538 
trySplit()1539         public EntrySpliterator<K,V> trySplit() {
1540             int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;
1541             return (lo >= mid) ? null :
1542                 new EntrySpliterator<K,V>(map, lo, index = mid, est >>>= 1,
1543                                           expectedModCount);
1544         }
1545 
forEachRemaining(Consumer<? super Map.Entry<K, V>> action)1546         public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {
1547             if (action == null)
1548                 throw new NullPointerException();
1549             int i, hi, mc;
1550             IdentityHashMap<K,V> m; Object[] a;
1551             if ((m = map) != null && (a = m.table) != null &&
1552                 (i = index) >= 0 && (index = hi = getFence()) <= a.length) {
1553                 for (; i < hi; i += 2) {
1554                     Object key = a[i];
1555                     if (key != null) {
1556                         @SuppressWarnings("unchecked") K k =
1557                             (K)unmaskNull(key);
1558                         @SuppressWarnings("unchecked") V v = (V)a[i+1];
1559                         action.accept
1560                             (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
1561 
1562                     }
1563                 }
1564                 if (m.modCount == expectedModCount)
1565                     return;
1566             }
1567             throw new ConcurrentModificationException();
1568         }
1569 
tryAdvance(Consumer<? super Map.Entry<K,V>> action)1570         public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {
1571             if (action == null)
1572                 throw new NullPointerException();
1573             Object[] a = map.table;
1574             int hi = getFence();
1575             while (index < hi) {
1576                 Object key = a[index];
1577                 @SuppressWarnings("unchecked") V v = (V)a[index+1];
1578                 index += 2;
1579                 if (key != null) {
1580                     @SuppressWarnings("unchecked") K k =
1581                         (K)unmaskNull(key);
1582                     action.accept
1583                         (new AbstractMap.SimpleImmutableEntry<K,V>(k, v));
1584                     if (map.modCount != expectedModCount)
1585                         throw new ConcurrentModificationException();
1586                     return true;
1587                 }
1588             }
1589             return false;
1590         }
1591 
characteristics()1592         public int characteristics() {
1593             return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT;
1594         }
1595     }
1596 
1597 }
1598