Path: blob/aarch64-shenandoah-jdk8u272-b10/jdk/src/share/classes/java/util/IdentityHashMap.java
38829 views
/*1* Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package java.util;2627import java.lang.reflect.Array;28import java.util.function.BiConsumer;29import java.util.function.BiFunction;30import java.util.function.Consumer;31import sun.misc.SharedSecrets;3233/**34* This class implements the <tt>Map</tt> interface with a hash table, using35* reference-equality in place of object-equality when comparing keys (and36* values). In other words, in an <tt>IdentityHashMap</tt>, two keys37* <tt>k1</tt> and <tt>k2</tt> are considered equal if and only if38* <tt>(k1==k2)</tt>. (In normal <tt>Map</tt> implementations (like39* <tt>HashMap</tt>) two keys <tt>k1</tt> and <tt>k2</tt> are considered equal40* 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, it44* intentionally violates <tt>Map's</tt> general contract, which mandates the45* use of the <tt>equals</tt> method when comparing objects. This class is46* designed for use only in the rare cases wherein reference-equality47* semantics are required.</b>48*49* <p>A typical use of this class is <i>topology-preserving object graph50* transformations</i>, such as serialization or deep-copying. To perform such51* a transformation, a program must maintain a "node table" that keeps track52* of all the object references that have already been processed. The node53* 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>. For55* example, a debugging facility might wish to maintain a proxy object for56* each object in the program being debugged.57*58* <p>This class provides all of the optional map operations, and permits59* <tt>null</tt> values and the <tt>null</tt> key. This class makes no60* guarantees as to the order of the map; in particular, it does not guarantee61* that the order will remain constant over time.62*63* <p>This class provides constant-time performance for the basic64* operations (<tt>get</tt> and <tt>put</tt>), assuming the system65* 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 not69* semantics): <i>expected maximum size</i>. This parameter is the maximum70* number of key-value mappings that the map is expected to hold. Internally,71* this parameter is used to determine the number of buckets initially72* comprising the hash table. The precise relationship between the expected73* maximum size and the number of buckets is unspecified.74*75* <p>If the size of the map (the number of key-value mappings) sufficiently76* exceeds the expected maximum size, the number of buckets is increased.77* Increasing the number of buckets ("rehashing") may be fairly expensive, so78* it pays to create identity hash maps with a sufficiently large expected79* maximum size. On the other hand, iteration over collection views requires80* time proportional to the number of buckets in the hash table, so it81* pays not to set the expected maximum size too high if you are especially82* 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 at86* least one of the threads modifies the map structurally, it <i>must</i>87* be synchronized externally. (A structural modification is any operation88* that adds or deletes one or more mappings; merely changing the value89* associated with a key that an instance already contains is not a90* structural modification.) This is typically accomplished by91* synchronizing on some object that naturally encapsulates the map.92*93* If no such object exists, the map should be "wrapped" using the94* {@link Collections#synchronizedMap Collections.synchronizedMap}95* method. This is best done at creation time, to prevent accidental96* 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 the100* collections returned by all of this class's "collection view101* methods" are <i>fail-fast</i>: if the map is structurally modified102* at any time after the iterator is created, in any way except103* through the iterator's own <tt>remove</tt> method, the iterator104* will throw a {@link ConcurrentModificationException}. Thus, in the105* face of concurrent modification, the iterator fails quickly and106* cleanly, rather than risking arbitrary, non-deterministic behavior107* at an undetermined time in the future.108*109* <p>Note that the fail-fast behavior of an iterator cannot be guaranteed110* as it is, generally speaking, impossible to make any hard guarantees in the111* presence of unsynchronized concurrent modification. Fail-fast iterators112* throw <tt>ConcurrentModificationException</tt> on a best-effort basis.113* Therefore, it would be wrong to write a program that depended on this114* exception for its correctness: <i>fail-fast iterators should be used only115* 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 array119* alternates holding keys and values. (This has better locality for large120* tables than does using separate arrays.) For many JRE implementations121* and operation mixes, this class will yield better performance than122* {@link HashMap} (which uses <i>chaining</i> rather than linear-probing).123*124* <p>This class is a member of the125* <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 Collection131* @see Map132* @see HashMap133* @see TreeMap134* @author Doug Lea and Josh Bloch135* @since 1.4136*/137138public class IdentityHashMap<K,V>139extends AbstractMap<K,V>140implements Map<K,V>, java.io.Serializable, Cloneable141{142/**143* The initial capacity used by the no-args constructor.144* MUST be a power of two. The value 32 corresponds to the145* (specified) expected maximum size of 21, given a load factor146* of 2/3.147*/148private static final int DEFAULT_CAPACITY = 32;149150/**151* The minimum capacity, used if a lower value is implicitly specified152* by either of the constructors with arguments. The value 4 corresponds153* to an expected maximum size of 2, given a load factor of 2/3.154* MUST be a power of two.155*/156private static final int MINIMUM_CAPACITY = 4;157158/**159* The maximum capacity, used if a higher value is implicitly specified160* 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 items164* because it has to have at least one slot with the key == null165* in order to avoid infinite loops in get(), put(), remove()166*/167private static final int MAXIMUM_CAPACITY = 1 << 29;168169/**170* The table, resized as necessary. Length MUST always be a power of two.171*/172transient Object[] table; // non-private to simplify nested class access173174/**175* The number of key-value mappings contained in this identity hash map.176*177* @serial178*/179int size;180181/**182* The number of modifications, to support fast-fail iterators183*/184transient int modCount;185186/**187* Value representing null keys inside tables.188*/189static final Object NULL_KEY = new Object();190191/**192* Use NULL_KEY for key if it is null.193*/194private static Object maskNull(Object key) {195return (key == null ? NULL_KEY : key);196}197198/**199* Returns internal representation of null key back to caller as null.200*/201static final Object unmaskNull(Object key) {202return (key == NULL_KEY ? null : key);203}204205/**206* Constructs a new, empty identity hash map with a default expected207* maximum size (21).208*/209public IdentityHashMap() {210init(DEFAULT_CAPACITY);211}212213/**214* Constructs a new, empty map with the specified expected maximum size.215* Putting more than the expected number of key-value mappings into216* the map may cause the internal data structure to grow, which may be217* somewhat time-consuming.218*219* @param expectedMaxSize the expected maximum size of the map220* @throws IllegalArgumentException if <tt>expectedMaxSize</tt> is negative221*/222public IdentityHashMap(int expectedMaxSize) {223if (expectedMaxSize < 0)224throw new IllegalArgumentException("expectedMaxSize is negative: "225+ expectedMaxSize);226init(capacity(expectedMaxSize));227}228229/**230* Returns the appropriate capacity for the given expected maximum size.231* Returns the smallest power of two between MINIMUM_CAPACITY and232* MAXIMUM_CAPACITY, inclusive, that is greater than (3 *233* expectedMaxSize)/2, if such a number exists. Otherwise returns234* MAXIMUM_CAPACITY.235*/236private static int capacity(int expectedMaxSize) {237// assert expectedMaxSize >= 0;238return239(expectedMaxSize > MAXIMUM_CAPACITY / 3) ? MAXIMUM_CAPACITY :240(expectedMaxSize <= 2 * MINIMUM_CAPACITY / 3) ? MINIMUM_CAPACITY :241Integer.highestOneBit(expectedMaxSize + (expectedMaxSize << 1));242}243244/**245* Initializes object to be an empty map with the specified initial246* capacity, which is assumed to be a power of two between247* MINIMUM_CAPACITY and MAXIMUM_CAPACITY inclusive.248*/249private void init(int initCapacity) {250// assert (initCapacity & -initCapacity) == initCapacity; // power of 2251// assert initCapacity >= MINIMUM_CAPACITY;252// assert initCapacity <= MAXIMUM_CAPACITY;253254table = new Object[2 * initCapacity];255}256257/**258* Constructs a new identity hash map containing the keys-value mappings259* in the specified map.260*261* @param m the map whose mappings are to be placed into this map262* @throws NullPointerException if the specified map is null263*/264public IdentityHashMap(Map<? extends K, ? extends V> m) {265// Allow for a bit of growth266this((int) ((1 + m.size()) * 1.1));267putAll(m);268}269270/**271* Returns the number of key-value mappings in this identity hash map.272*273* @return the number of key-value mappings in this map274*/275public int size() {276return size;277}278279/**280* Returns <tt>true</tt> if this identity hash map contains no key-value281* mappings.282*283* @return <tt>true</tt> if this identity hash map contains no key-value284* mappings285*/286public boolean isEmpty() {287return size == 0;288}289290/**291* Returns index for Object x.292*/293private static int hash(Object x, int length) {294int h = System.identityHashCode(x);295// Multiply by -127, and left-shift to use least bit as part of hash296return ((h << 1) - (h << 8)) & (length - 1);297}298299/**300* Circularly traverses table of size len.301*/302private static int nextKeyIndex(int i, int len) {303return (i + 2 < len ? i + 2 : 0);304}305306/**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 key311* {@code k} to a value {@code v} such that {@code (key == k)},312* then this method returns {@code v}; otherwise it returns313* {@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 also317* possible that the map explicitly maps the key to {@code null}.318* The {@link #containsKey containsKey} operation may be used to319* distinguish these two cases.320*321* @see #put(Object, Object)322*/323@SuppressWarnings("unchecked")324public V get(Object key) {325Object k = maskNull(key);326Object[] tab = table;327int len = tab.length;328int i = hash(k, len);329while (true) {330Object item = tab[i];331if (item == k)332return (V) tab[i + 1];333if (item == null)334return null;335i = nextKeyIndex(i, len);336}337}338339/**340* Tests whether the specified object reference is a key in this identity341* hash map.342*343* @param key possible key344* @return <code>true</code> if the specified object reference is a key345* in this map346* @see #containsValue(Object)347*/348public boolean containsKey(Object key) {349Object k = maskNull(key);350Object[] tab = table;351int len = tab.length;352int i = hash(k, len);353while (true) {354Object item = tab[i];355if (item == k)356return true;357if (item == null)358return false;359i = nextKeyIndex(i, len);360}361}362363/**364* Tests whether the specified object reference is a value in this identity365* hash map.366*367* @param value value whose presence in this map is to be tested368* @return <tt>true</tt> if this map maps one or more keys to the369* specified object reference370* @see #containsKey(Object)371*/372public boolean containsValue(Object value) {373Object[] tab = table;374for (int i = 1; i < tab.length; i += 2)375if (tab[i] == value && tab[i - 1] != null)376return true;377378return false;379}380381/**382* Tests if the specified key-value mapping is in the map.383*384* @param key possible key385* @param value possible value386* @return <code>true</code> if and only if the specified key-value387* mapping is in the map388*/389private boolean containsMapping(Object key, Object value) {390Object k = maskNull(key);391Object[] tab = table;392int len = tab.length;393int i = hash(k, len);394while (true) {395Object item = tab[i];396if (item == k)397return tab[i + 1] == value;398if (item == null)399return false;400i = nextKeyIndex(i, len);401}402}403404/**405* Associates the specified value with the specified key in this identity406* hash map. If the map previously contained a mapping for the key, the407* old value is replaced.408*409* @param key the key with which the specified value is to be associated410* @param value the value to be associated with the specified key411* @return the previous value associated with <tt>key</tt>, or412* <tt>null</tt> if there was no mapping for <tt>key</tt>.413* (A <tt>null</tt> return can also indicate that the map414* previously associated <tt>null</tt> with <tt>key</tt>.)415* @see Object#equals(Object)416* @see #get(Object)417* @see #containsKey(Object)418*/419public V put(K key, V value) {420final Object k = maskNull(key);421422retryAfterResize: for (;;) {423final Object[] tab = table;424final int len = tab.length;425int i = hash(k, len);426427for (Object item; (item = tab[i]) != null;428i = nextKeyIndex(i, len)) {429if (item == k) {430@SuppressWarnings("unchecked")431V oldValue = (V) tab[i + 1];432tab[i + 1] = value;433return oldValue;434}435}436437final int s = size + 1;438// Use optimized form of 3 * s.439// Next capacity is len, 2 * current capacity.440if (s + (s << 1) > len && resize(len))441continue retryAfterResize;442443modCount++;444tab[i] = k;445tab[i + 1] = value;446size = s;447return null;448}449}450451/**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 place456*/457private boolean resize(int newCapacity) {458// assert (newCapacity & -newCapacity) == newCapacity; // power of 2459int newLength = newCapacity * 2;460461Object[] oldTable = table;462int oldLength = oldTable.length;463if (oldLength == 2 * MAXIMUM_CAPACITY) { // can't expand any further464if (size == MAXIMUM_CAPACITY - 1)465throw new IllegalStateException("Capacity exhausted.");466return false;467}468if (oldLength >= newLength)469return false;470471Object[] newTable = new Object[newLength];472473for (int j = 0; j < oldLength; j += 2) {474Object key = oldTable[j];475if (key != null) {476Object value = oldTable[j+1];477oldTable[j] = null;478oldTable[j+1] = null;479int i = hash(key, newLength);480while (newTable[i] != null)481i = nextKeyIndex(i, newLength);482newTable[i] = key;483newTable[i + 1] = value;484}485}486table = newTable;487return true;488}489490/**491* Copies all of the mappings from the specified map to this map.492* These mappings will replace any mappings that this map had for493* any of the keys currently in the specified map.494*495* @param m mappings to be stored in this map496* @throws NullPointerException if the specified map is null497*/498public void putAll(Map<? extends K, ? extends V> m) {499int n = m.size();500if (n == 0)501return;502if (n > size)503resize(capacity(n)); // conservatively pre-expand504505for (Entry<? extends K, ? extends V> e : m.entrySet())506put(e.getKey(), e.getValue());507}508509/**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 map513* @return the previous value associated with <tt>key</tt>, or514* <tt>null</tt> if there was no mapping for <tt>key</tt>.515* (A <tt>null</tt> return can also indicate that the map516* previously associated <tt>null</tt> with <tt>key</tt>.)517*/518public V remove(Object key) {519Object k = maskNull(key);520Object[] tab = table;521int len = tab.length;522int i = hash(k, len);523524while (true) {525Object item = tab[i];526if (item == k) {527modCount++;528size--;529@SuppressWarnings("unchecked")530V oldValue = (V) tab[i + 1];531tab[i + 1] = null;532tab[i] = null;533closeDeletion(i);534return oldValue;535}536if (item == null)537return null;538i = nextKeyIndex(i, len);539}540}541542/**543* Removes the specified key-value mapping from the map if it is present.544*545* @param key possible key546* @param value possible value547* @return <code>true</code> if and only if the specified key-value548* mapping was in the map549*/550private boolean removeMapping(Object key, Object value) {551Object k = maskNull(key);552Object[] tab = table;553int len = tab.length;554int i = hash(k, len);555556while (true) {557Object item = tab[i];558if (item == k) {559if (tab[i + 1] != value)560return false;561modCount++;562size--;563tab[i] = null;564tab[i + 1] = null;565closeDeletion(i);566return true;567}568if (item == null)569return false;570i = nextKeyIndex(i, len);571}572}573574/**575* Rehash all possibly-colliding entries following a576* deletion. This preserves the linear-probe577* collision properties required by get, put, etc.578*579* @param d the index of a newly empty deleted slot580*/581private void closeDeletion(int d) {582// Adapted from Knuth Section 6.4 Algorithm R583Object[] tab = table;584int len = tab.length;585586// Look for items to swap into newly vacated slot587// starting at index immediately following deletion,588// and continuing until a null slot is seen, indicating589// the end of a run of possibly-colliding keys.590Object item;591for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;592i = nextKeyIndex(i, len) ) {593// The following test triggers if the item at slot i (which594// 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 the596// newly vacated i. This process will terminate when we hit597// the null slot at the end of this run.598// The test is messy because we are using a circular table.599int r = hash(item, len);600if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) {601tab[d] = item;602tab[d + 1] = tab[i + 1];603tab[i] = null;604tab[i + 1] = null;605d = i;606}607}608}609610/**611* Removes all of the mappings from this map.612* The map will be empty after this call returns.613*/614public void clear() {615modCount++;616Object[] tab = table;617for (int i = 0; i < tab.length; i++)618tab[i] = null;619size = 0;620}621622/**623* Compares the specified object with this map for equality. Returns624* <tt>true</tt> if the given object is also a map and the two maps625* represent identical object-reference mappings. More formally, this626* map is equal to another map <tt>m</tt> if and only if627* <tt>this.entrySet().equals(m.entrySet())</tt>.628*629* <p><b>Owing to the reference-equality-based semantics of this map it is630* possible that the symmetry and transitivity requirements of the631* <tt>Object.equals</tt> contract may be violated if this map is compared632* to a normal map. However, the <tt>Object.equals</tt> contract is633* guaranteed to hold among <tt>IdentityHashMap</tt> instances.</b>634*635* @param o object to be compared for equality with this map636* @return <tt>true</tt> if the specified object is equal to this map637* @see Object#equals(Object)638*/639public boolean equals(Object o) {640if (o == this) {641return true;642} else if (o instanceof IdentityHashMap) {643IdentityHashMap<?,?> m = (IdentityHashMap<?,?>) o;644if (m.size() != size)645return false;646647Object[] tab = m.table;648for (int i = 0; i < tab.length; i+=2) {649Object k = tab[i];650if (k != null && !containsMapping(k, tab[i + 1]))651return false;652}653return true;654} else if (o instanceof Map) {655Map<?,?> m = (Map<?,?>)o;656return entrySet().equals(m.entrySet());657} else {658return false; // o is not a Map659}660}661662/**663* Returns the hash code value for this map. The hash code of a map is664* defined to be the sum of the hash codes of each entry in the map's665* <tt>entrySet()</tt> view. This ensures that <tt>m1.equals(m2)</tt>666* implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two667* <tt>IdentityHashMap</tt> instances <tt>m1</tt> and <tt>m2</tt>, as668* required by the general contract of {@link Object#hashCode}.669*670* <p><b>Owing to the reference-equality-based semantics of the671* <tt>Map.Entry</tt> instances in the set returned by this map's672* <tt>entrySet</tt> method, it is possible that the contractual673* requirement of <tt>Object.hashCode</tt> mentioned in the previous674* paragraph will be violated if one of the two objects being compared is675* an <tt>IdentityHashMap</tt> instance and the other is a normal map.</b>676*677* @return the hash code value for this map678* @see Object#equals(Object)679* @see #equals(Object)680*/681public int hashCode() {682int result = 0;683Object[] tab = table;684for (int i = 0; i < tab.length; i +=2) {685Object key = tab[i];686if (key != null) {687Object k = unmaskNull(key);688result += System.identityHashCode(k) ^689System.identityHashCode(tab[i + 1]);690}691}692return result;693}694695/**696* Returns a shallow copy of this identity hash map: the keys and values697* themselves are not cloned.698*699* @return a shallow copy of this map700*/701public Object clone() {702try {703IdentityHashMap<?,?> m = (IdentityHashMap<?,?>) super.clone();704m.entrySet = null;705m.table = table.clone();706return m;707} catch (CloneNotSupportedException e) {708throw new InternalError(e);709}710}711712private abstract class IdentityHashMapIterator<T> implements Iterator<T> {713int index = (size != 0 ? 0 : table.length); // current slot.714int expectedModCount = modCount; // to support fast-fail715int lastReturnedIndex = -1; // to allow remove()716boolean indexValid; // To avoid unnecessary next computation717Object[] traversalTable = table; // reference to main table or copy718719public boolean hasNext() {720Object[] tab = traversalTable;721for (int i = index; i < tab.length; i+=2) {722Object key = tab[i];723if (key != null) {724index = i;725return indexValid = true;726}727}728index = tab.length;729return false;730}731732protected int nextIndex() {733if (modCount != expectedModCount)734throw new ConcurrentModificationException();735if (!indexValid && !hasNext())736throw new NoSuchElementException();737738indexValid = false;739lastReturnedIndex = index;740index += 2;741return lastReturnedIndex;742}743744public void remove() {745if (lastReturnedIndex == -1)746throw new IllegalStateException();747if (modCount != expectedModCount)748throw new ConcurrentModificationException();749750expectedModCount = ++modCount;751int deletedSlot = lastReturnedIndex;752lastReturnedIndex = -1;753// back up index to revisit new contents after deletion754index = deletedSlot;755indexValid = false;756757// Removal code proceeds as in closeDeletion except that758// it must catch the rare case where an element already759// seen is swapped into a vacant slot that will be later760// traversed by this iterator. We cannot allow future761// next() calls to return it again. The likelihood of762// this occurring under 2/3 load factor is very slim, but763// when it does happen, we must make a copy of the rest of764// the table to use for the rest of the traversal. Since765// this can only happen when we are near the end of the table,766// even in these rare cases, this is not very expensive in767// time or space.768769Object[] tab = traversalTable;770int len = tab.length;771772int d = deletedSlot;773Object key = tab[d];774tab[d] = null; // vacate the slot775tab[d + 1] = null;776777// If traversing a copy, remove in real table.778// We can skip gap-closure on copy.779if (tab != IdentityHashMap.this.table) {780IdentityHashMap.this.remove(key);781expectedModCount = modCount;782return;783}784785size--;786787Object item;788for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;789i = nextKeyIndex(i, len)) {790int r = hash(item, len);791// See closeDeletion for explanation of this conditional792if ((i < r && (r <= d || d <= i)) ||793(r <= d && d <= i)) {794795// If we are about to swap an already-seen element796// into a slot that may later be returned by next(),797// then clone the rest of table for use in future798// next() calls. It is OK that our copy will have799// a gap in the "wrong" place, since it will never800// be used for searching anyway.801802if (i < deletedSlot && d >= deletedSlot &&803traversalTable == IdentityHashMap.this.table) {804int remaining = len - deletedSlot;805Object[] newTable = new Object[remaining];806System.arraycopy(tab, deletedSlot,807newTable, 0, remaining);808traversalTable = newTable;809index = 0;810}811812tab[d] = item;813tab[d + 1] = tab[i + 1];814tab[i] = null;815tab[i + 1] = null;816d = i;817}818}819}820}821822private class KeyIterator extends IdentityHashMapIterator<K> {823@SuppressWarnings("unchecked")824public K next() {825return (K) unmaskNull(traversalTable[nextIndex()]);826}827}828829private class ValueIterator extends IdentityHashMapIterator<V> {830@SuppressWarnings("unchecked")831public V next() {832return (V) traversalTable[nextIndex() + 1];833}834}835836private class EntryIterator837extends IdentityHashMapIterator<Map.Entry<K,V>>838{839private Entry lastReturnedEntry;840841public Map.Entry<K,V> next() {842lastReturnedEntry = new Entry(nextIndex());843return lastReturnedEntry;844}845846public void remove() {847lastReturnedIndex =848((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);849super.remove();850lastReturnedEntry.index = lastReturnedIndex;851lastReturnedEntry = null;852}853854private class Entry implements Map.Entry<K,V> {855private int index;856857private Entry(int index) {858this.index = index;859}860861@SuppressWarnings("unchecked")862public K getKey() {863checkIndexForEntryUse();864return (K) unmaskNull(traversalTable[index]);865}866867@SuppressWarnings("unchecked")868public V getValue() {869checkIndexForEntryUse();870return (V) traversalTable[index+1];871}872873@SuppressWarnings("unchecked")874public V setValue(V value) {875checkIndexForEntryUse();876V oldValue = (V) traversalTable[index+1];877traversalTable[index+1] = value;878// if shadowing, force into main table879if (traversalTable != IdentityHashMap.this.table)880put((K) traversalTable[index], value);881return oldValue;882}883884public boolean equals(Object o) {885if (index < 0)886return super.equals(o);887888if (!(o instanceof Map.Entry))889return false;890Map.Entry<?,?> e = (Map.Entry<?,?>)o;891return (e.getKey() == unmaskNull(traversalTable[index]) &&892e.getValue() == traversalTable[index+1]);893}894895public int hashCode() {896if (lastReturnedIndex < 0)897return super.hashCode();898899return (System.identityHashCode(unmaskNull(traversalTable[index])) ^900System.identityHashCode(traversalTable[index+1]));901}902903public String toString() {904if (index < 0)905return super.toString();906907return (unmaskNull(traversalTable[index]) + "="908+ traversalTable[index+1]);909}910911private void checkIndexForEntryUse() {912if (index < 0)913throw new IllegalStateException("Entry was removed");914}915}916}917918// Views919920/**921* This field is initialized to contain an instance of the entry set922* view the first time this view is requested. The view is stateless,923* so there's no reason to create more than one.924*/925private transient Set<Map.Entry<K,V>> entrySet;926927/**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 in930* the set, and vice-versa. If the map is modified while an iteration931* over the set is in progress, the results of the iteration are932* undefined. The set supports element removal, which removes the933* corresponding mapping from the map, via the <tt>Iterator.remove</tt>,934* <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and935* <tt>clear</tt> methods. It does not support the <tt>add</tt> or936* <tt>addAll</tt> methods.937*938* <p><b>While the object returned by this method implements the939* <tt>Set</tt> interface, it does <i>not</i> obey <tt>Set's</tt> general940* contract. Like its backing map, the set returned by this method941* defines element equality as reference-equality rather than942* object-equality. This affects the behavior of its <tt>contains</tt>,943* <tt>remove</tt>, <tt>containsAll</tt>, <tt>equals</tt>, and944* <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 same948* object references as the returned set. The symmetry and transitivity949* requirements of the <tt>Object.equals</tt> contract may be violated if950* 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 sets952* returned by this method.</b>953*954* <p>The <tt>hashCode</tt> method of the returned set returns the sum of955* the <i>identity hashcodes</i> of the elements in the set, rather than956* the sum of their hashcodes. This is mandated by the change in the957* semantics of the <tt>equals</tt> method, in order to enforce the958* general contract of the <tt>Object.hashCode</tt> method among sets959* returned by this method.960*961* @return an identity-based set view of the keys contained in this map962* @see Object#equals(Object)963* @see System#identityHashCode(Object)964*/965public Set<K> keySet() {966Set<K> ks = keySet;967if (ks == null) {968ks = new KeySet();969keySet = ks;970}971return ks;972}973974private class KeySet extends AbstractSet<K> {975public Iterator<K> iterator() {976return new KeyIterator();977}978public int size() {979return size;980}981public boolean contains(Object o) {982return containsKey(o);983}984public boolean remove(Object o) {985int oldSize = size;986IdentityHashMap.this.remove(o);987return size != oldSize;988}989/*990* Must revert from AbstractSet's impl to AbstractCollection's, as991* the former contains an optimization that results in incorrect992* behavior when c is a smaller "normal" (non-identity-based) Set.993*/994public boolean removeAll(Collection<?> c) {995Objects.requireNonNull(c);996boolean modified = false;997for (Iterator<K> i = iterator(); i.hasNext(); ) {998if (c.contains(i.next())) {999i.remove();1000modified = true;1001}1002}1003return modified;1004}1005public void clear() {1006IdentityHashMap.this.clear();1007}1008public int hashCode() {1009int result = 0;1010for (K key : this)1011result += System.identityHashCode(key);1012return result;1013}1014public Object[] toArray() {1015return toArray(new Object[0]);1016}1017@SuppressWarnings("unchecked")1018public <T> T[] toArray(T[] a) {1019int expectedModCount = modCount;1020int size = size();1021if (a.length < size)1022a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);1023Object[] tab = table;1024int ti = 0;1025for (int si = 0; si < tab.length; si += 2) {1026Object key;1027if ((key = tab[si]) != null) { // key present ?1028// more elements than expected -> concurrent modification from other thread1029if (ti >= size) {1030throw new ConcurrentModificationException();1031}1032a[ti++] = (T) unmaskNull(key); // unmask key1033}1034}1035// fewer elements than expected or concurrent modification from other thread detected1036if (ti < size || expectedModCount != modCount) {1037throw new ConcurrentModificationException();1038}1039// final null marker as per spec1040if (ti < a.length) {1041a[ti] = null;1042}1043return a;1044}10451046public Spliterator<K> spliterator() {1047return new KeySpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);1048}1049}10501051/**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 are1054* reflected in the collection, and vice-versa. If the map is1055* modified while an iteration over the collection is in progress,1056* the results of the iteration are undefined. The collection1057* supports element removal, which removes the corresponding1058* 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 not1061* support the <tt>add</tt> or <tt>addAll</tt> methods.1062*1063* <p><b>While the object returned by this method implements the1064* <tt>Collection</tt> interface, it does <i>not</i> obey1065* <tt>Collection's</tt> general contract. Like its backing map,1066* the collection returned by this method defines element equality as1067* reference-equality rather than object-equality. This affects the1068* behavior of its <tt>contains</tt>, <tt>remove</tt> and1069* <tt>containsAll</tt> methods.</b>1070*/1071public Collection<V> values() {1072Collection<V> vs = values;1073if (vs == null) {1074vs = new Values();1075values = vs;1076}1077return vs;1078}10791080private class Values extends AbstractCollection<V> {1081public Iterator<V> iterator() {1082return new ValueIterator();1083}1084public int size() {1085return size;1086}1087public boolean contains(Object o) {1088return containsValue(o);1089}1090public boolean remove(Object o) {1091for (Iterator<V> i = iterator(); i.hasNext(); ) {1092if (i.next() == o) {1093i.remove();1094return true;1095}1096}1097return false;1098}1099public void clear() {1100IdentityHashMap.this.clear();1101}1102public Object[] toArray() {1103return toArray(new Object[0]);1104}1105@SuppressWarnings("unchecked")1106public <T> T[] toArray(T[] a) {1107int expectedModCount = modCount;1108int size = size();1109if (a.length < size)1110a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);1111Object[] tab = table;1112int ti = 0;1113for (int si = 0; si < tab.length; si += 2) {1114if (tab[si] != null) { // key present ?1115// more elements than expected -> concurrent modification from other thread1116if (ti >= size) {1117throw new ConcurrentModificationException();1118}1119a[ti++] = (T) tab[si+1]; // copy value1120}1121}1122// fewer elements than expected or concurrent modification from other thread detected1123if (ti < size || expectedModCount != modCount) {1124throw new ConcurrentModificationException();1125}1126// final null marker as per spec1127if (ti < a.length) {1128a[ti] = null;1129}1130return a;1131}11321133public Spliterator<V> spliterator() {1134return new ValueSpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);1135}1136}11371138/**1139* Returns a {@link Set} view of the mappings contained in this map.1140* Each element in the returned set is a reference-equality-based1141* <tt>Map.Entry</tt>. The set is backed by the map, so changes1142* to the map are reflected in the set, and vice-versa. If the1143* map is modified while an iteration over the set is in progress,1144* the results of the iteration are undefined. The set supports1145* element removal, which removes the corresponding mapping from1146* 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> or1149* <tt>addAll</tt> methods.1150*1151* <p>Like the backing map, the <tt>Map.Entry</tt> objects in the set1152* returned by this method define key and value equality as1153* reference-equality rather than object-equality. This affects the1154* behavior of the <tt>equals</tt> and <tt>hashCode</tt> methods of these1155* <tt>Map.Entry</tt> objects. A reference-equality based <tt>Map.Entry1156* e</tt> is equal to an object <tt>o</tt> if and only if <tt>o</tt> is a1157* <tt>Map.Entry</tt> and <tt>e.getKey()==o.getKey() &&1158* e.getValue()==o.getValue()</tt>. To accommodate these equals1159* semantics, the <tt>hashCode</tt> method returns1160* <tt>System.identityHashCode(e.getKey()) ^1161* System.identityHashCode(e.getValue())</tt>.1162*1163* <p><b>Owing to the reference-equality-based semantics of the1164* <tt>Map.Entry</tt> instances in the set returned by this method,1165* it is possible that the symmetry and transitivity requirements of1166* the {@link Object#equals(Object)} contract may be violated if any of1167* the entries in the set is compared to a normal map entry, or if1168* the set returned by this method is compared to a set of normal map1169* entries (such as would be returned by a call to this method on a normal1170* map). However, the <tt>Object.equals</tt> contract is guaranteed to1171* 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 map1175*/1176public Set<Map.Entry<K,V>> entrySet() {1177Set<Map.Entry<K,V>> es = entrySet;1178if (es != null)1179return es;1180else1181return entrySet = new EntrySet();1182}11831184private class EntrySet extends AbstractSet<Map.Entry<K,V>> {1185public Iterator<Map.Entry<K,V>> iterator() {1186return new EntryIterator();1187}1188public boolean contains(Object o) {1189if (!(o instanceof Map.Entry))1190return false;1191Map.Entry<?,?> entry = (Map.Entry<?,?>)o;1192return containsMapping(entry.getKey(), entry.getValue());1193}1194public boolean remove(Object o) {1195if (!(o instanceof Map.Entry))1196return false;1197Map.Entry<?,?> entry = (Map.Entry<?,?>)o;1198return removeMapping(entry.getKey(), entry.getValue());1199}1200public int size() {1201return size;1202}1203public void clear() {1204IdentityHashMap.this.clear();1205}1206/*1207* Must revert from AbstractSet's impl to AbstractCollection's, as1208* the former contains an optimization that results in incorrect1209* behavior when c is a smaller "normal" (non-identity-based) Set.1210*/1211public boolean removeAll(Collection<?> c) {1212Objects.requireNonNull(c);1213boolean modified = false;1214for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) {1215if (c.contains(i.next())) {1216i.remove();1217modified = true;1218}1219}1220return modified;1221}12221223public Object[] toArray() {1224return toArray(new Object[0]);1225}12261227@SuppressWarnings("unchecked")1228public <T> T[] toArray(T[] a) {1229int expectedModCount = modCount;1230int size = size();1231if (a.length < size)1232a = (T[]) Array.newInstance(a.getClass().getComponentType(), size);1233Object[] tab = table;1234int ti = 0;1235for (int si = 0; si < tab.length; si += 2) {1236Object key;1237if ((key = tab[si]) != null) { // key present ?1238// more elements than expected -> concurrent modification from other thread1239if (ti >= size) {1240throw new ConcurrentModificationException();1241}1242a[ti++] = (T) new AbstractMap.SimpleEntry<>(unmaskNull(key), tab[si + 1]);1243}1244}1245// fewer elements than expected or concurrent modification from other thread detected1246if (ti < size || expectedModCount != modCount) {1247throw new ConcurrentModificationException();1248}1249// final null marker as per spec1250if (ti < a.length) {1251a[ti] = null;1252}1253return a;1254}12551256public Spliterator<Map.Entry<K,V>> spliterator() {1257return new EntrySpliterator<>(IdentityHashMap.this, 0, -1, 0, 0);1258}1259}126012611262private static final long serialVersionUID = 8188218128353913216L;12631264/**1265* Saves the state of the <tt>IdentityHashMap</tt> instance to a stream1266* (i.e., serializes it).1267*1268* @serialData The <i>size</i> of the HashMap (the number of key-value1269* mappings) (<tt>int</tt>), followed by the key (Object) and1270* value (Object) for each key-value mapping represented by the1271* IdentityHashMap. The key-value mappings are emitted in no1272* particular order.1273*/1274private void writeObject(java.io.ObjectOutputStream s)1275throws java.io.IOException {1276// Write out and any hidden stuff1277s.defaultWriteObject();12781279// Write out size (number of Mappings)1280s.writeInt(size);12811282// Write out keys and values (alternating)1283Object[] tab = table;1284for (int i = 0; i < tab.length; i += 2) {1285Object key = tab[i];1286if (key != null) {1287s.writeObject(unmaskNull(key));1288s.writeObject(tab[i + 1]);1289}1290}1291}12921293/**1294* Reconstitutes the <tt>IdentityHashMap</tt> instance from a stream (i.e.,1295* deserializes it).1296*/1297private void readObject(java.io.ObjectInputStream s)1298throws java.io.IOException, ClassNotFoundException {1299// Read in any hidden stuff1300s.defaultReadObject();13011302// Read in size (number of Mappings)1303int size = s.readInt();1304if (size < 0)1305throw new java.io.StreamCorruptedException1306("Illegal mappings count: " + size);1307int cap = capacity(size);1308SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, cap);1309init(cap);13101311// Read the keys and values, and put the mappings in the table1312for (int i=0; i<size; i++) {1313@SuppressWarnings("unchecked")1314K key = (K) s.readObject();1315@SuppressWarnings("unchecked")1316V value = (V) s.readObject();1317putForCreate(key, value);1318}1319}13201321/**1322* The put method for readObject. It does not resize the table,1323* update modCount, etc.1324*/1325private void putForCreate(K key, V value)1326throws java.io.StreamCorruptedException1327{1328Object k = maskNull(key);1329Object[] tab = table;1330int len = tab.length;1331int i = hash(k, len);13321333Object item;1334while ( (item = tab[i]) != null) {1335if (item == k)1336throw new java.io.StreamCorruptedException();1337i = nextKeyIndex(i, len);1338}1339tab[i] = k;1340tab[i + 1] = value;1341}13421343@SuppressWarnings("unchecked")1344@Override1345public void forEach(BiConsumer<? super K, ? super V> action) {1346Objects.requireNonNull(action);1347int expectedModCount = modCount;13481349Object[] t = table;1350for (int index = 0; index < t.length; index += 2) {1351Object k = t[index];1352if (k != null) {1353action.accept((K) unmaskNull(k), (V) t[index + 1]);1354}13551356if (modCount != expectedModCount) {1357throw new ConcurrentModificationException();1358}1359}1360}13611362@SuppressWarnings("unchecked")1363@Override1364public void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {1365Objects.requireNonNull(function);1366int expectedModCount = modCount;13671368Object[] t = table;1369for (int index = 0; index < t.length; index += 2) {1370Object k = t[index];1371if (k != null) {1372t[index + 1] = function.apply((K) unmaskNull(k), (V) t[index + 1]);1373}13741375if (modCount != expectedModCount) {1376throw new ConcurrentModificationException();1377}1378}1379}13801381/**1382* Similar form as array-based Spliterators, but skips blank elements,1383* and guestimates size as decreasing by half per split.1384*/1385static class IdentityHashMapSpliterator<K,V> {1386final IdentityHashMap<K,V> map;1387int index; // current index, modified on advance/split1388int fence; // -1 until first use; then one past last index1389int est; // size estimate1390int expectedModCount; // initialized when fence set13911392IdentityHashMapSpliterator(IdentityHashMap<K,V> map, int origin,1393int fence, int est, int expectedModCount) {1394this.map = map;1395this.index = origin;1396this.fence = fence;1397this.est = est;1398this.expectedModCount = expectedModCount;1399}14001401final int getFence() { // initialize fence and size on first use1402int hi;1403if ((hi = fence) < 0) {1404est = map.size;1405expectedModCount = map.modCount;1406hi = fence = map.table.length;1407}1408return hi;1409}14101411public final long estimateSize() {1412getFence(); // force init1413return (long) est;1414}1415}14161417static final class KeySpliterator<K,V>1418extends IdentityHashMapSpliterator<K,V>1419implements Spliterator<K> {1420KeySpliterator(IdentityHashMap<K,V> map, int origin, int fence, int est,1421int expectedModCount) {1422super(map, origin, fence, est, expectedModCount);1423}14241425public KeySpliterator<K,V> trySplit() {1426int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;1427return (lo >= mid) ? null :1428new KeySpliterator<K,V>(map, lo, index = mid, est >>>= 1,1429expectedModCount);1430}14311432@SuppressWarnings("unchecked")1433public void forEachRemaining(Consumer<? super K> action) {1434if (action == null)1435throw new NullPointerException();1436int i, hi, mc; Object key;1437IdentityHashMap<K,V> m; Object[] a;1438if ((m = map) != null && (a = m.table) != null &&1439(i = index) >= 0 && (index = hi = getFence()) <= a.length) {1440for (; i < hi; i += 2) {1441if ((key = a[i]) != null)1442action.accept((K)unmaskNull(key));1443}1444if (m.modCount == expectedModCount)1445return;1446}1447throw new ConcurrentModificationException();1448}14491450@SuppressWarnings("unchecked")1451public boolean tryAdvance(Consumer<? super K> action) {1452if (action == null)1453throw new NullPointerException();1454Object[] a = map.table;1455int hi = getFence();1456while (index < hi) {1457Object key = a[index];1458index += 2;1459if (key != null) {1460action.accept((K)unmaskNull(key));1461if (map.modCount != expectedModCount)1462throw new ConcurrentModificationException();1463return true;1464}1465}1466return false;1467}14681469public int characteristics() {1470return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT;1471}1472}14731474static final class ValueSpliterator<K,V>1475extends IdentityHashMapSpliterator<K,V>1476implements Spliterator<V> {1477ValueSpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est,1478int expectedModCount) {1479super(m, origin, fence, est, expectedModCount);1480}14811482public ValueSpliterator<K,V> trySplit() {1483int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;1484return (lo >= mid) ? null :1485new ValueSpliterator<K,V>(map, lo, index = mid, est >>>= 1,1486expectedModCount);1487}14881489public void forEachRemaining(Consumer<? super V> action) {1490if (action == null)1491throw new NullPointerException();1492int i, hi, mc;1493IdentityHashMap<K,V> m; Object[] a;1494if ((m = map) != null && (a = m.table) != null &&1495(i = index) >= 0 && (index = hi = getFence()) <= a.length) {1496for (; i < hi; i += 2) {1497if (a[i] != null) {1498@SuppressWarnings("unchecked") V v = (V)a[i+1];1499action.accept(v);1500}1501}1502if (m.modCount == expectedModCount)1503return;1504}1505throw new ConcurrentModificationException();1506}15071508public boolean tryAdvance(Consumer<? super V> action) {1509if (action == null)1510throw new NullPointerException();1511Object[] a = map.table;1512int hi = getFence();1513while (index < hi) {1514Object key = a[index];1515@SuppressWarnings("unchecked") V v = (V)a[index+1];1516index += 2;1517if (key != null) {1518action.accept(v);1519if (map.modCount != expectedModCount)1520throw new ConcurrentModificationException();1521return true;1522}1523}1524return false;1525}15261527public int characteristics() {1528return (fence < 0 || est == map.size ? SIZED : 0);1529}15301531}15321533static final class EntrySpliterator<K,V>1534extends IdentityHashMapSpliterator<K,V>1535implements Spliterator<Map.Entry<K,V>> {1536EntrySpliterator(IdentityHashMap<K,V> m, int origin, int fence, int est,1537int expectedModCount) {1538super(m, origin, fence, est, expectedModCount);1539}15401541public EntrySpliterator<K,V> trySplit() {1542int hi = getFence(), lo = index, mid = ((lo + hi) >>> 1) & ~1;1543return (lo >= mid) ? null :1544new EntrySpliterator<K,V>(map, lo, index = mid, est >>>= 1,1545expectedModCount);1546}15471548public void forEachRemaining(Consumer<? super Map.Entry<K, V>> action) {1549if (action == null)1550throw new NullPointerException();1551int i, hi, mc;1552IdentityHashMap<K,V> m; Object[] a;1553if ((m = map) != null && (a = m.table) != null &&1554(i = index) >= 0 && (index = hi = getFence()) <= a.length) {1555for (; i < hi; i += 2) {1556Object key = a[i];1557if (key != null) {1558@SuppressWarnings("unchecked") K k =1559(K)unmaskNull(key);1560@SuppressWarnings("unchecked") V v = (V)a[i+1];1561action.accept1562(new AbstractMap.SimpleImmutableEntry<K,V>(k, v));15631564}1565}1566if (m.modCount == expectedModCount)1567return;1568}1569throw new ConcurrentModificationException();1570}15711572public boolean tryAdvance(Consumer<? super Map.Entry<K,V>> action) {1573if (action == null)1574throw new NullPointerException();1575Object[] a = map.table;1576int hi = getFence();1577while (index < hi) {1578Object key = a[index];1579@SuppressWarnings("unchecked") V v = (V)a[index+1];1580index += 2;1581if (key != null) {1582@SuppressWarnings("unchecked") K k =1583(K)unmaskNull(key);1584action.accept1585(new AbstractMap.SimpleImmutableEntry<K,V>(k, v));1586if (map.modCount != expectedModCount)1587throw new ConcurrentModificationException();1588return true;1589}1590}1591return false;1592}15931594public int characteristics() {1595return (fence < 0 || est == map.size ? SIZED : 0) | Spliterator.DISTINCT;1596}1597}15981599}160016011602