Home | History | Annotate | Download | only in util
      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}openjdk-redirect.html?v=8&path=/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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    286     public boolean isEmpty() {
    287         return size == 0;
    288     }
    289 
    290     /**
    291      * Returns index for Object x.
    292      */
    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      */
    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")
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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 
    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 
    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")
    824         public K next() {
    825             return (K) unmaskNull(traversalTable[nextIndex()]);
    826         }
    827     }
    828 
    829     private class ValueIterator extends IdentityHashMapIterator<V> {
    830         @SuppressWarnings("unchecked")
    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 
    841         public Map.Entry<K,V> next() {
    842             lastReturnedEntry = new Entry(nextIndex());
    843             return lastReturnedEntry;
    844         }
    845 
    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 
    857             private Entry(int index) {
    858                 this.index = index;
    859             }
    860 
    861             @SuppressWarnings("unchecked")
    862             public K getKey() {
    863                 checkIndexForEntryUse();
    864                 return (K) unmaskNull(traversalTable[index]);
    865             }
    866 
    867             @SuppressWarnings("unchecked")
    868             public V getValue() {
    869                 checkIndexForEntryUse();
    870                 return (V) traversalTable[index+1];
    871             }
    872 
    873             @SuppressWarnings("unchecked")
    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 
    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 
    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 
    903             public String toString() {
    904                 if (index < 0)
    905                     return super.toString();
    906 
    907                 return (unmaskNull(traversalTable[index]) + "="
    908                         + traversalTable[index+1]);
    909             }
    910 
    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      */
    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> {
    975         public Iterator<K> iterator() {
    976             return new KeyIterator();
    977         }
    978         public int size() {
    979             return size;
    980         }
    981         public boolean contains(Object o) {
    982             return containsKey(o);
    983         }
    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          */
    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         }
   1005         public void clear() {
   1006             IdentityHashMap.this.clear();
   1007         }
   1008         public int hashCode() {
   1009             int result = 0;
   1010             for (K key : this)
   1011                 result += System.identityHashCode(key);
   1012             return result;
   1013         }
   1014         public Object[] toArray() {
   1015             return toArray(new Object[0]);
   1016         }
   1017         @SuppressWarnings("unchecked")
   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 
   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      */
   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> {
   1081         public Iterator<V> iterator() {
   1082             return new ValueIterator();
   1083         }
   1084         public int size() {
   1085             return size;
   1086         }
   1087         public boolean contains(Object o) {
   1088             return containsValue(o);
   1089         }
   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         }
   1099         public void clear() {
   1100             IdentityHashMap.this.clear();
   1101         }
   1102         public Object[] toArray() {
   1103             return toArray(new Object[0]);
   1104         }
   1105         @SuppressWarnings("unchecked")
   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 
   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      */
   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>> {
   1185         public Iterator<Map.Entry<K,V>> iterator() {
   1186             return new EntryIterator();
   1187         }
   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         }
   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         }
   1200         public int size() {
   1201             return size;
   1202         }
   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          */
   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 
   1223         public Object[] toArray() {
   1224             return toArray(new Object[0]);
   1225         }
   1226 
   1227         @SuppressWarnings("unchecked")
   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 
   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      */
   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      */
   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      */
   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
   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
   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 
   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 
   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 
   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> {
   1418         KeySpliterator(IdentityHashMap<K,V> map, int origin, int fence, int est,
   1419                        int expectedModCount) {
   1420             super(map, origin, fence, est, expectedModCount);
   1421         }
   1422 
   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")
   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")
   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 
   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> {
   1475         ValueSpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est,
   1476                          int expectedModCount) {
   1477             super(m, origin, fence, est, expectedModCount);
   1478         }
   1479 
   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 
   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 
   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 
   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>> {
   1534         EntrySpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est,
   1535                          int expectedModCount) {
   1536             super(m, origin, fence, est, expectedModCount);
   1537         }
   1538 
   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 
   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 
   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 
   1592         public int characteristics() {
   1593             return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT;
   1594         }
   1595     }
   1596 
   1597 }
   1598