History

My first initial commit with all of mine experimental changes.

Dmitry Kabak (userdima committed 13 years ago

Commit d37b88d1 parent 3f5b46618352 files · +2598093 −-8690Browse files

Showing the changes to java/pkg/java/util/IdentityHashMap.java (1 of 18352 files). Show all

Unified · Split

java/pkg/java/util/IdentityHashMap.java+1243−0
@@ -0,0 +1,1243 @@
1+/*
2+ * Copyright (c) 2000, 2011, 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+import java.io.*;
28+
29+/**
30+ * This class implements the <tt>Map</tt> interface with a hash table, using
31+ * reference-equality in place of object-equality when comparing keys (and
32+ * values). In other words, in an <tt>IdentityHashMap</tt>, two keys
33+ * <tt>k1</tt> and <tt>k2</tt> are considered equal if and only if
34+ * <tt>(k1==k2)</tt>. (In normal <tt>Map</tt> implementations (like
35+ * <tt>HashMap</tt>) two keys <tt>k1</tt> and <tt>k2</tt> are considered equal
36+ * if and only if <tt>(k1==null ? k2==null : k1.equals(k2))</tt>.)
37+ *
38+ * <p><b>This class is <i>not</i> a general-purpose <tt>Map</tt>
39+ * implementation! While this class implements the <tt>Map</tt> interface, it
40+ * intentionally violates <tt>Map's</tt> general contract, which mandates the
41+ * use of the <tt>equals</tt> method when comparing objects. This class is
42+ * designed for use only in the rare cases wherein reference-equality
43+ * semantics are required.</b>
44+ *
45+ * <p>A typical use of this class is <i>topology-preserving object graph
46+ * transformations</i>, such as serialization or deep-copying. To perform such
47+ * a transformation, a program must maintain a "node table" that keeps track
48+ * of all the object references that have already been processed. The node
49+ * table must not equate distinct objects even if they happen to be equal.
50+ * Another typical use of this class is to maintain <i>proxy objects</i>. For
51+ * example, a debugging facility might wish to maintain a proxy object for
52+ * each object in the program being debugged.
53+ *
54+ * <p>This class provides all of the optional map operations, and permits
55+ * <tt>null</tt> values and the <tt>null</tt> key. This class makes no
56+ * guarantees as to the order of the map; in particular, it does not guarantee
57+ * that the order will remain constant over time.
58+ *
59+ * <p>This class provides constant-time performance for the basic
60+ * operations (<tt>get</tt> and <tt>put</tt>), assuming the system
61+ * identity hash function ({@link System#identityHashCode(Object)})
62+ * disperses elements properly among the buckets.
63+ *
64+ * <p>This class has one tuning parameter (which affects performance but not
65+ * semantics): <i>expected maximum size</i>. This parameter is the maximum
66+ * number of key-value mappings that the map is expected to hold. Internally,
67+ * this parameter is used to determine the number of buckets initially
68+ * comprising the hash table. The precise relationship between the expected
69+ * maximum size and the number of buckets is unspecified.
70+ *
71+ * <p>If the size of the map (the number of key-value mappings) sufficiently
72+ * exceeds the expected maximum size, the number of buckets is increased
73+ * Increasing the number of buckets ("rehashing") may be fairly expensive, so
74+ * it pays to create identity hash maps with a sufficiently large expected
75+ * maximum size. On the other hand, iteration over collection views requires
76+ * time proportional to the number of buckets in the hash table, so it
77+ * pays not to set the expected maximum size too high if you are especially
78+ * concerned with iteration performance or memory usage.
79+ *
80+ * <p><strong>Note that this implementation is not synchronized.</strong>
81+ * If multiple threads access an identity hash map concurrently, and at
82+ * least one of the threads modifies the map structurally, it <i>must</i>
83+ * be synchronized externally. (A structural modification is any operation
84+ * that adds or deletes one or more mappings; merely changing the value
85+ * associated with a key that an instance already contains is not a
86+ * structural modification.) This is typically accomplished by
87+ * synchronizing on some object that naturally encapsulates the map.
88+ *
89+ * If no such object exists, the map should be "wrapped" using the
90+ * {@link Collections#synchronizedMap Collections.synchronizedMap}
91+ * method. This is best done at creation time, to prevent accidental
92+ * unsynchronized access to the map:<pre>
93+ * Map m = Collections.synchronizedMap(new IdentityHashMap(...));</pre>
94+ *
95+ * <p>The iterators returned by the <tt>iterator</tt> method of the
96+ * collections returned by all of this class's "collection view
97+ * methods" are <i>fail-fast</i>: if the map is structurally modified
98+ * at any time after the iterator is created, in any way except
99+ * through the iterator's own <tt>remove</tt> method, the iterator
100+ * will throw a {@link ConcurrentModificationException}. Thus, in the
101+ * face of concurrent modification, the iterator fails quickly and
102+ * cleanly, rather than risking arbitrary, non-deterministic behavior
103+ * at an undetermined time in the future.
104+ *
105+ * <p>Note that the fail-fast behavior of an iterator cannot be guaranteed
106+ * as it is, generally speaking, impossible to make any hard guarantees in the
107+ * presence of unsynchronized concurrent modification. Fail-fast iterators
108+ * throw <tt>ConcurrentModificationException</tt> on a best-effort basis.
109+ * Therefore, it would be wrong to write a program that depended on this
110+ * exception for its correctness: <i>fail-fast iterators should be used only
111+ * to detect bugs.</i>
112+ *
113+ * <p>Implementation note: This is a simple <i>linear-probe</i> hash table,
114+ * as described for example in texts by Sedgewick and Knuth. The array
115+ * alternates holding keys and values. (This has better locality for large
116+ * tables than does using separate arrays.) For many JRE implementations
117+ * and operation mixes, this class will yield better performance than
118+ * {@link HashMap} (which uses <i>chaining</i> rather than linear-probing).
119+ *
120+ * <p>This class is a member of the
121+ * <a href="{@docRoot}/../technotes/guides/collections/index.html">
122+ * Java Collections Framework</a>.
123+ *
124+ * @see System#identityHashCode(Object)
125+ * @see Object#hashCode()
126+ * @see Collection
127+ * @see Map
128+ * @see HashMap
129+ * @see TreeMap
130+ * @author Doug Lea and Josh Bloch
131+ * @since 1.4
132+ */
133+
134+public class IdentityHashMap<K,V>
135+ extends AbstractMap<K,V>
136+ implements Map<K,V>, java.io.Serializable, Cloneable
137+{
138+ /**
139+ * The initial capacity used by the no-args constructor.
140+ * MUST be a power of two. The value 32 corresponds to the
141+ * (specified) expected maximum size of 21, given a load factor
142+ * of 2/3.
143+ */
144+ private static final int DEFAULT_CAPACITY = 32;
145+
146+ /**
147+ * The minimum capacity, used if a lower value is implicitly specified
148+ * by either of the constructors with arguments. The value 4 corresponds
149+ * to an expected maximum size of 2, given a load factor of 2/3.
150+ * MUST be a power of two.
151+ */
152+ private static final int MINIMUM_CAPACITY = 4;
153+
154+ /**
155+ * The maximum capacity, used if a higher value is implicitly specified
156+ * by either of the constructors with arguments.
157+ * MUST be a power of two <= 1<<29.
158+ */
159+ private static final int MAXIMUM_CAPACITY = 1 << 29;
160+
161+ /**
162+ * The table, resized as necessary. Length MUST always be a power of two.
163+ */
164+ private transient Object[] table;
165+
166+ /**
167+ * The number of key-value mappings contained in this identity hash map.
168+ *
169+ * @serial
170+ */
171+ private int size;
172+
173+ /**
174+ * The number of modifications, to support fast-fail iterators
175+ */
176+ private transient int modCount;
177+
178+ /**
179+ * The next size value at which to resize (capacity * load factor).
180+ */
181+ private transient int threshold;
182+
183+ /**
184+ * Value representing null keys inside tables.
185+ */
186+ private static final Object NULL_KEY = new Object();
187+
188+ /**
189+ * Use NULL_KEY for key if it is null.
190+ */
191+ private static Object maskNull(Object key) {
192+ return (key == null ? NULL_KEY : key);
193+ }
194+
195+ /**
196+ * Returns internal representation of null key back to caller as null.
197+ */
198+ private static Object unmaskNull(Object key) {
199+ return (key == NULL_KEY ? null : key);
200+ }
201+
202+ /**
203+ * Constructs a new, empty identity hash map with a default expected
204+ * maximum size (21).
205+ */
206+ public IdentityHashMap() {
207+ init(DEFAULT_CAPACITY);
208+ }
209+
210+ /**
211+ * Constructs a new, empty map with the specified expected maximum size.
212+ * Putting more than the expected number of key-value mappings into
213+ * the map may cause the internal data structure to grow, which may be
214+ * somewhat time-consuming.
215+ *
216+ * @param expectedMaxSize the expected maximum size of the map
217+ * @throws IllegalArgumentException if <tt>expectedMaxSize</tt> is negative
218+ */
219+ public IdentityHashMap(int expectedMaxSize) {
220+ if (expectedMaxSize < 0)
221+ throw new IllegalArgumentException("expectedMaxSize is negative: "
222+ + expectedMaxSize);
223+ init(capacity(expectedMaxSize));
224+ }
225+
226+ /**
227+ * Returns the appropriate capacity for the specified expected maximum
228+ * size. Returns the smallest power of two between MINIMUM_CAPACITY
229+ * and MAXIMUM_CAPACITY, inclusive, that is greater than
230+ * (3 * expectedMaxSize)/2, if such a number exists. Otherwise
231+ * returns MAXIMUM_CAPACITY. If (3 * expectedMaxSize)/2 is negative, it
232+ * is assumed that overflow has occurred, and MAXIMUM_CAPACITY is returned.
233+ */
234+ private int capacity(int expectedMaxSize) {
235+ // Compute min capacity for expectedMaxSize given a load factor of 2/3
236+ int minCapacity = (3 * expectedMaxSize)/2;
237+
238+ // Compute the appropriate capacity
239+ int result;
240+ if (minCapacity > MAXIMUM_CAPACITY || minCapacity < 0) {
241+ result = MAXIMUM_CAPACITY;
242+ } else {
243+ result = MINIMUM_CAPACITY;
244+ while (result < minCapacity)
245+ result <<= 1;
246+ }
247+ return result;
248+ }
249+
250+ /**
251+ * Initializes object to be an empty map with the specified initial
252+ * capacity, which is assumed to be a power of two between
253+ * MINIMUM_CAPACITY and MAXIMUM_CAPACITY inclusive.
254+ */
255+ private void init(int initCapacity) {
256+ // assert (initCapacity & -initCapacity) == initCapacity; // power of 2
257+ // assert initCapacity >= MINIMUM_CAPACITY;
258+ // assert initCapacity <= MAXIMUM_CAPACITY;
259+
260+ threshold = (initCapacity * 2)/3;
261+ table = new Object[2 * initCapacity];
262+ }
263+
264+ /**
265+ * Constructs a new identity hash map containing the keys-value mappings
266+ * in the specified map.
267+ *
268+ * @param m the map whose mappings are to be placed into this map
269+ * @throws NullPointerException if the specified map is null
270+ */
271+ public IdentityHashMap(Map<? extends K, ? extends V> m) {
272+ // Allow for a bit of growth
273+ this((int) ((1 + m.size()) * 1.1));
274+ putAll(m);
275+ }
276+
277+ /**
278+ * Returns the number of key-value mappings in this identity hash map.
279+ *
280+ * @return the number of key-value mappings in this map
281+ */
282+ public int size() {
283+ return size;
284+ }
285+
286+ /**
287+ * Returns <tt>true</tt> if this identity hash map contains no key-value
288+ * mappings.
289+ *
290+ * @return <tt>true</tt> if this identity hash map contains no key-value
291+ * mappings
292+ */
293+ public boolean isEmpty() {
294+ return size == 0;
295+ }
296+
297+ /**
298+ * Returns index for Object x.
299+ */
300+ private static int hash(Object x, int length) {
301+ int h = System.identityHashCode(x);
302+ // Multiply by -127, and left-shift to use least bit as part of hash
303+ return ((h << 1) - (h << 8)) & (length - 1);
304+ }
305+
306+ /**
307+ * Circularly traverses table of size len.
308+ */
309+ private static int nextKeyIndex(int i, int len) {
310+ return (i + 2 < len ? i + 2 : 0);
311+ }
312+
313+ /**
314+ * Returns the value to which the specified key is mapped,
315+ * or {@code null} if this map contains no mapping for the key.
316+ *
317+ * <p>More formally, if this map contains a mapping from a key
318+ * {@code k} to a value {@code v} such that {@code (key == k)},
319+ * then this method returns {@code v}; otherwise it returns
320+ * {@code null}. (There can be at most one such mapping.)
321+ *
322+ * <p>A return value of {@code null} does not <i>necessarily</i>
323+ * indicate that the map contains no mapping for the key; it's also
324+ * possible that the map explicitly maps the key to {@code null}.
325+ * The {@link #containsKey containsKey} operation may be used to
326+ * distinguish these two cases.
327+ *
328+ * @see #put(Object, Object)
329+ */
330+ public V get(Object key) {
331+ Object k = maskNull(key);
332+ Object[] tab = table;
333+ int len = tab.length;
334+ int i = hash(k, len);
335+ while (true) {
336+ Object item = tab[i];
337+ if (item == k)
338+ return (V) tab[i + 1];
339+ if (item == null)
340+ return null;
341+ i = nextKeyIndex(i, len);
342+ }
343+ }
344+
345+ /**
346+ * Tests whether the specified object reference is a key in this identity
347+ * hash map.
348+ *
349+ * @param key possible key
350+ * @return <code>true</code> if the specified object reference is a key
351+ * in this map
352+ * @see #containsValue(Object)
353+ */
354+ public boolean containsKey(Object key) {
355+ Object k = maskNull(key);
356+ Object[] tab = table;
357+ int len = tab.length;
358+ int i = hash(k, len);
359+ while (true) {
360+ Object item = tab[i];
361+ if (item == k)
362+ return true;
363+ if (item == null)
364+ return false;
365+ i = nextKeyIndex(i, len);
366+ }
367+ }
368+
369+ /**
370+ * Tests whether the specified object reference is a value in this identity
371+ * hash map.
372+ *
373+ * @param value value whose presence in this map is to be tested
374+ * @return <tt>true</tt> if this map maps one or more keys to the
375+ * specified object reference
376+ * @see #containsKey(Object)
377+ */
378+ public boolean containsValue(Object value) {
379+ Object[] tab = table;
380+ for (int i = 1; i < tab.length; i += 2)
381+ if (tab[i] == value && tab[i - 1] != null)
382+ return true;
383+
384+ return false;
385+ }
386+
387+ /**
388+ * Tests if the specified key-value mapping is in the map.
389+ *
390+ * @param key possible key
391+ * @param value possible value
392+ * @return <code>true</code> if and only if the specified key-value
393+ * mapping is in the map
394+ */
395+ private boolean containsMapping(Object key, Object value) {
396+ Object k = maskNull(key);
397+ Object[] tab = table;
398+ int len = tab.length;
399+ int i = hash(k, len);
400+ while (true) {
401+ Object item = tab[i];
402+ if (item == k)
403+ return tab[i + 1] == value;
404+ if (item == null)
405+ return false;
406+ i = nextKeyIndex(i, len);
407+ }
408+ }
409+
410+ /**
411+ * Associates the specified value with the specified key in this identity
412+ * hash map. If the map previously contained a mapping for the key, the
413+ * old value is replaced.
414+ *
415+ * @param key the key with which the specified value is to be associated
416+ * @param value the value to be associated with the specified key
417+ * @return the previous value associated with <tt>key</tt>, or
418+ * <tt>null</tt> if there was no mapping for <tt>key</tt>.
419+ * (A <tt>null</tt> return can also indicate that the map
420+ * previously associated <tt>null</tt> with <tt>key</tt>.)
421+ * @see Object#equals(Object)
422+ * @see #get(Object)
423+ * @see #containsKey(Object)
424+ */
425+ public V put(K key, V value) {
426+ Object k = maskNull(key);
427+ Object[] tab = table;
428+ int len = tab.length;
429+ int i = hash(k, len);
430+
431+ Object item;
432+ while ( (item = tab[i]) != null) {
433+ if (item == k) {
434+ V oldValue = (V) tab[i + 1];
435+ tab[i + 1] = value;
436+ return oldValue;
437+ }
438+ i = nextKeyIndex(i, len);
439+ }
440+
441+ modCount++;
442+ tab[i] = k;
443+ tab[i + 1] = value;
444+ if (++size >= threshold)
445+ resize(len); // len == 2 * current capacity.
446+ return null;
447+ }
448+
449+ /**
450+ * Resize the table to hold given capacity.
451+ *
452+ * @param newCapacity the new capacity, must be a power of two.
453+ */
454+ private void resize(int newCapacity) {
455+ // assert (newCapacity & -newCapacity) == newCapacity; // power of 2
456+ int newLength = newCapacity * 2;
457+
458+ Object[] oldTable = table;
459+ int oldLength = oldTable.length;
460+ if (oldLength == 2*MAXIMUM_CAPACITY) { // can't expand any further
461+ if (threshold == MAXIMUM_CAPACITY-1)
462+ throw new IllegalStateException("Capacity exhausted.");
463+ threshold = MAXIMUM_CAPACITY-1; // Gigantic map!
464+ return;
465+ }
466+ if (oldLength >= newLength)
467+ return;
468+
469+ Object[] newTable = new Object[newLength];
470+ threshold = newLength / 3;
471+
472+ for (int j = 0; j < oldLength; j += 2) {
473+ Object key = oldTable[j];
474+ if (key != null) {
475+ Object value = oldTable[j+1];
476+ oldTable[j] = null;
477+ oldTable[j+1] = null;
478+ int i = hash(key, newLength);
479+ while (newTable[i] != null)
480+ i = nextKeyIndex(i, newLength);
481+ newTable[i] = key;
482+ newTable[i + 1] = value;
483+ }
484+ }
485+ table = newTable;
486+ }
487+
488+ /**
489+ * Copies all of the mappings from the specified map to this map.
490+ * These mappings will replace any mappings that this map had for
491+ * any of the keys currently in the specified map.
492+ *
493+ * @param m mappings to be stored in this map
494+ * @throws NullPointerException if the specified map is null
495+ */
496+ public void putAll(Map<? extends K, ? extends V> m) {
497+ int n = m.size();
498+ if (n == 0)
499+ return;
500+ if (n > threshold) // conservatively pre-expand
501+ resize(capacity(n));
502+
503+ for (Entry<? extends K, ? extends V> e : m.entrySet())
504+ put(e.getKey(), e.getValue());
505+ }
506+
507+ /**
508+ * Removes the mapping for this key from this map if present.
509+ *
510+ * @param key key whose mapping is to be removed from the map
511+ * @return the previous value associated with <tt>key</tt>, or
512+ * <tt>null</tt> if there was no mapping for <tt>key</tt>.
513+ * (A <tt>null</tt> return can also indicate that the map
514+ * previously associated <tt>null</tt> with <tt>key</tt>.)
515+ */
516+ public V remove(Object key) {
517+ Object k = maskNull(key);
518+ Object[] tab = table;
519+ int len = tab.length;
520+ int i = hash(k, len);
521+
522+ while (true) {
523+ Object item = tab[i];
524+ if (item == k) {
525+ modCount++;
526+ size--;
527+ V oldValue = (V) tab[i + 1];
528+ tab[i + 1] = null;
529+ tab[i] = null;
530+ closeDeletion(i);
531+ return oldValue;
532+ }
533+ if (item == null)
534+ return null;
535+ i = nextKeyIndex(i, len);
536+ }
537+
538+ }
539+
540+ /**
541+ * Removes the specified key-value mapping from the map if it is present.
542+ *
543+ * @param key possible key
544+ * @param value possible value
545+ * @return <code>true</code> if and only if the specified key-value
546+ * mapping was in the map
547+ */
548+ private boolean removeMapping(Object key, Object value) {
549+ Object k = maskNull(key);
550+ Object[] tab = table;
551+ int len = tab.length;
552+ int i = hash(k, len);
553+
554+ while (true) {
555+ Object item = tab[i];
556+ if (item == k) {
557+ if (tab[i + 1] != value)
558+ return false;
559+ modCount++;
560+ size--;
561+ tab[i] = null;
562+ tab[i + 1] = null;
563+ closeDeletion(i);
564+ return true;
565+ }
566+ if (item == null)
567+ return false;
568+ i = nextKeyIndex(i, len);
569+ }
570+ }
571+
572+ /**
573+ * Rehash all possibly-colliding entries following a
574+ * deletion. This preserves the linear-probe
575+ * collision properties required by get, put, etc.
576+ *
577+ * @param d the index of a newly empty deleted slot
578+ */
579+ private void closeDeletion(int d) {
580+ // Adapted from Knuth Section 6.4 Algorithm R
581+ Object[] tab = table;
582+ int len = tab.length;
583+
584+ // Look for items to swap into newly vacated slot
585+ // starting at index immediately following deletion,
586+ // and continuing until a null slot is seen, indicating
587+ // the end of a run of possibly-colliding keys.
588+ Object item;
589+ for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
590+ i = nextKeyIndex(i, len) ) {
591+ // The following test triggers if the item at slot i (which
592+ // hashes to be at slot r) should take the spot vacated by d.
593+ // If so, we swap it in, and then continue with d now at the
594+ // newly vacated i. This process will terminate when we hit
595+ // the null slot at the end of this run.
596+ // The test is messy because we are using a circular table.
597+ int r = hash(item, len);
598+ if ((i < r && (r <= d || d <= i)) || (r <= d && d <= i)) {
599+ tab[d] = item;
600+ tab[d + 1] = tab[i + 1];
601+ tab[i] = null;
602+ tab[i + 1] = null;
603+ d = i;
604+ }
605+ }
606+ }
607+
608+ /**
609+ * Removes all of the mappings from this map.
610+ * The map will be empty after this call returns.
611+ */
612+ public void clear() {
613+ modCount++;
614+ Object[] tab = table;
615+ for (int i = 0; i < tab.length; i++)
616+ tab[i] = null;
617+ size = 0;
618+ }
619+
620+ /**
621+ * Compares the specified object with this map for equality. Returns
622+ * <tt>true</tt> if the given object is also a map and the two maps
623+ * represent identical object-reference mappings. More formally, this
624+ * map is equal to another map <tt>m</tt> if and only if
625+ * <tt>this.entrySet().equals(m.entrySet())</tt>.
626+ *
627+ * <p><b>Owing to the reference-equality-based semantics of this map it is
628+ * possible that the symmetry and transitivity requirements of the
629+ * <tt>Object.equals</tt> contract may be violated if this map is compared
630+ * to a normal map. However, the <tt>Object.equals</tt> contract is
631+ * guaranteed to hold among <tt>IdentityHashMap</tt> instances.</b>
632+ *
633+ * @param o object to be compared for equality with this map
634+ * @return <tt>true</tt> if the specified object is equal to this map
635+ * @see Object#equals(Object)
636+ */
637+ public boolean equals(Object o) {
638+ if (o == this) {
639+ return true;
640+ } else if (o instanceof IdentityHashMap) {
641+ IdentityHashMap m = (IdentityHashMap) o;
642+ if (m.size() != size)
643+ return false;
644+
645+ Object[] tab = m.table;
646+ for (int i = 0; i < tab.length; i+=2) {
647+ Object k = tab[i];
648+ if (k != null && !containsMapping(k, tab[i + 1]))
649+ return false;
650+ }
651+ return true;
652+ } else if (o instanceof Map) {
653+ Map m = (Map)o;
654+ return entrySet().equals(m.entrySet());
655+ } else {
656+ return false; // o is not a Map
657+ }
658+ }
659+
660+ /**
661+ * Returns the hash code value for this map. The hash code of a map is
662+ * defined to be the sum of the hash codes of each entry in the map's
663+ * <tt>entrySet()</tt> view. This ensures that <tt>m1.equals(m2)</tt>
664+ * implies that <tt>m1.hashCode()==m2.hashCode()</tt> for any two
665+ * <tt>IdentityHashMap</tt> instances <tt>m1</tt> and <tt>m2</tt>, as
666+ * required by the general contract of {@link Object#hashCode}.
667+ *
668+ * <p><b>Owing to the reference-equality-based semantics of the
669+ * <tt>Map.Entry</tt> instances in the set returned by this map's
670+ * <tt>entrySet</tt> method, it is possible that the contractual
671+ * requirement of <tt>Object.hashCode</tt> mentioned in the previous
672+ * paragraph will be violated if one of the two objects being compared is
673+ * an <tt>IdentityHashMap</tt> instance and the other is a normal map.</b>
674+ *
675+ * @return the hash code value for this map
676+ * @see Object#equals(Object)
677+ * @see #equals(Object)
678+ */
679+ public int hashCode() {
680+ int result = 0;
681+ Object[] tab = table;
682+ for (int i = 0; i < tab.length; i +=2) {
683+ Object key = tab[i];
684+ if (key != null) {
685+ Object k = unmaskNull(key);
686+ result += System.identityHashCode(k) ^
687+ System.identityHashCode(tab[i + 1]);
688+ }
689+ }
690+ return result;
691+ }
692+
693+ /**
694+ * Returns a shallow copy of this identity hash map: the keys and values
695+ * themselves are not cloned.
696+ *
697+ * @return a shallow copy of this map
698+ */
699+ public Object clone() {
700+ try {
701+ IdentityHashMap<K,V> m = (IdentityHashMap<K,V>) super.clone();
702+ m.entrySet = null;
703+ m.table = table.clone();
704+ return m;
705+ } catch (CloneNotSupportedException e) {
706+ throw new InternalError();
707+ }
708+ }
709+
710+ private abstract class IdentityHashMapIterator<T> implements Iterator<T> {
711+ int index = (size != 0 ? 0 : table.length); // current slot.
712+ int expectedModCount = modCount; // to support fast-fail
713+ int lastReturnedIndex = -1; // to allow remove()
714+ boolean indexValid; // To avoid unnecessary next computation
715+ Object[] traversalTable = table; // reference to main table or copy
716+
717+ public boolean hasNext() {
718+ Object[] tab = traversalTable;
719+ for (int i = index; i < tab.length; i+=2) {
720+ Object key = tab[i];
721+ if (key != null) {
722+ index = i;
723+ return indexValid = true;
724+ }
725+ }
726+ index = tab.length;
727+ return false;
728+ }
729+
730+ protected int nextIndex() {
731+ if (modCount != expectedModCount)
732+ throw new ConcurrentModificationException();
733+ if (!indexValid && !hasNext())
734+ throw new NoSuchElementException();
735+
736+ indexValid = false;
737+ lastReturnedIndex = index;
738+ index += 2;
739+ return lastReturnedIndex;
740+ }
741+
742+ public void remove() {
743+ if (lastReturnedIndex == -1)
744+ throw new IllegalStateException();
745+ if (modCount != expectedModCount)
746+ throw new ConcurrentModificationException();
747+
748+ expectedModCount = ++modCount;
749+ int deletedSlot = lastReturnedIndex;
750+ lastReturnedIndex = -1;
751+ // back up index to revisit new contents after deletion
752+ index = deletedSlot;
753+ indexValid = false;
754+
755+ // Removal code proceeds as in closeDeletion except that
756+ // it must catch the rare case where an element already
757+ // seen is swapped into a vacant slot that will be later
758+ // traversed by this iterator. We cannot allow future
759+ // next() calls to return it again. The likelihood of
760+ // this occurring under 2/3 load factor is very slim, but
761+ // when it does happen, we must make a copy of the rest of
762+ // the table to use for the rest of the traversal. Since
763+ // this can only happen when we are near the end of the table,
764+ // even in these rare cases, this is not very expensive in
765+ // time or space.
766+
767+ Object[] tab = traversalTable;
768+ int len = tab.length;
769+
770+ int d = deletedSlot;
771+ K key = (K) tab[d];
772+ tab[d] = null; // vacate the slot
773+ tab[d + 1] = null;
774+
775+ // If traversing a copy, remove in real table.
776+ // We can skip gap-closure on copy.
777+ if (tab != IdentityHashMap.this.table) {
778+ IdentityHashMap.this.remove(key);
779+ expectedModCount = modCount;
780+ return;
781+ }
782+
783+ size--;
784+
785+ Object item;
786+ for (int i = nextKeyIndex(d, len); (item = tab[i]) != null;
787+ i = nextKeyIndex(i, len)) {
788+ int r = hash(item, len);
789+ // See closeDeletion for explanation of this conditional
790+ if ((i < r && (r <= d || d <= i)) ||
791+ (r <= d && d <= i)) {
792+
793+ // If we are about to swap an already-seen element
794+ // into a slot that may later be returned by next(),
795+ // then clone the rest of table for use in future
796+ // next() calls. It is OK that our copy will have
797+ // a gap in the "wrong" place, since it will never
798+ // be used for searching anyway.
799+
800+ if (i < deletedSlot && d >= deletedSlot &&
801+ traversalTable == IdentityHashMap.this.table) {
802+ int remaining = len - deletedSlot;
803+ Object[] newTable = new Object[remaining];
804+ System.arraycopy(tab, deletedSlot,
805+ newTable, 0, remaining);
806+ traversalTable = newTable;
807+ index = 0;
808+ }
809+
810+ tab[d] = item;
811+ tab[d + 1] = tab[i + 1];
812+ tab[i] = null;
813+ tab[i + 1] = null;
814+ d = i;
815+ }
816+ }
817+ }
818+ }
819+
820+ private class KeyIterator extends IdentityHashMapIterator<K> {
821+ public K next() {
822+ return (K) unmaskNull(traversalTable[nextIndex()]);
823+ }
824+ }
825+
826+ private class ValueIterator extends IdentityHashMapIterator<V> {
827+ public V next() {
828+ return (V) traversalTable[nextIndex() + 1];
829+ }
830+ }
831+
832+ private class EntryIterator
833+ extends IdentityHashMapIterator<Map.Entry<K,V>>
834+ {
835+ private Entry lastReturnedEntry = null;
836+
837+ public Map.Entry<K,V> next() {
838+ lastReturnedEntry = new Entry(nextIndex());
839+ return lastReturnedEntry;
840+ }
841+
842+ public void remove() {
843+ lastReturnedIndex =
844+ ((null == lastReturnedEntry) ? -1 : lastReturnedEntry.index);
845+ super.remove();
846+ lastReturnedEntry.index = lastReturnedIndex;
847+ lastReturnedEntry = null;
848+ }
849+
850+ private class Entry implements Map.Entry<K,V> {
851+ private int index;
852+
853+ private Entry(int index) {
854+ this.index = index;
855+ }
856+
857+ public K getKey() {
858+ checkIndexForEntryUse();
859+ return (K) unmaskNull(traversalTable[index]);
860+ }
861+
862+ public V getValue() {
863+ checkIndexForEntryUse();
864+ return (V) traversalTable[index+1];
865+ }
866+
867+ public V setValue(V value) {
868+ checkIndexForEntryUse();
869+ V oldValue = (V) traversalTable[index+1];
870+ traversalTable[index+1] = value;
871+ // if shadowing, force into main table
872+ if (traversalTable != IdentityHashMap.this.table)
873+ put((K) traversalTable[index], value);
874+ return oldValue;
875+ }
876+
877+ public boolean equals(Object o) {
878+ if (index < 0)
879+ return super.equals(o);
880+
881+ if (!(o instanceof Map.Entry))
882+ return false;
883+ Map.Entry e = (Map.Entry)o;
884+ return (e.getKey() == unmaskNull(traversalTable[index]) &&
885+ e.getValue() == traversalTable[index+1]);
886+ }
887+
888+ public int hashCode() {
889+ if (lastReturnedIndex < 0)
890+ return super.hashCode();
891+
892+ return (System.identityHashCode(unmaskNull(traversalTable[index])) ^
893+ System.identityHashCode(traversalTable[index+1]));
894+ }
895+
896+ public String toString() {
897+ if (index < 0)
898+ return super.toString();
899+
900+ return (unmaskNull(traversalTable[index]) + "="
901+ + traversalTable[index+1]);
902+ }
903+
904+ private void checkIndexForEntryUse() {
905+ if (index < 0)
906+ throw new IllegalStateException("Entry was removed");
907+ }
908+ }
909+ }
910+
911+ // Views
912+
913+ /**
914+ * This field is initialized to contain an instance of the entry set
915+ * view the first time this view is requested. The view is stateless,
916+ * so there's no reason to create more than one.
917+ */
918+ private transient Set<Map.Entry<K,V>> entrySet = null;
919+
920+ /**
921+ * Returns an identity-based set view of the keys contained in this map.
922+ * The set is backed by the map, so changes to the map are reflected in
923+ * the set, and vice-versa. If the map is modified while an iteration
924+ * over the set is in progress, the results of the iteration are
925+ * undefined. The set supports element removal, which removes the
926+ * corresponding mapping from the map, via the <tt>Iterator.remove</tt>,
927+ * <tt>Set.remove</tt>, <tt>removeAll</tt>, <tt>retainAll</tt>, and
928+ * <tt>clear</tt> methods. It does not support the <tt>add</tt> or
929+ * <tt>addAll</tt> methods.
930+ *
931+ * <p><b>While the object returned by this method implements the
932+ * <tt>Set</tt> interface, it does <i>not</i> obey <tt>Set's</tt> general
933+ * contract. Like its backing map, the set returned by this method
934+ * defines element equality as reference-equality rather than
935+ * object-equality. This affects the behavior of its <tt>contains</tt>,
936+ * <tt>remove</tt>, <tt>containsAll</tt>, <tt>equals</tt>, and
937+ * <tt>hashCode</tt> methods.</b>
938+ *
939+ * <p><b>The <tt>equals</tt> method of the returned set returns <tt>true</tt>
940+ * only if the specified object is a set containing exactly the same
941+ * object references as the returned set. The symmetry and transitivity
942+ * requirements of the <tt>Object.equals</tt> contract may be violated if
943+ * the set returned by this method is compared to a normal set. However,
944+ * the <tt>Object.equals</tt> contract is guaranteed to hold among sets
945+ * returned by this method.</b>
946+ *
947+ * <p>The <tt>hashCode</tt> method of the returned set returns the sum of
948+ * the <i>identity hashcodes</i> of the elements in the set, rather than
949+ * the sum of their hashcodes. This is mandated by the change in the
950+ * semantics of the <tt>equals</tt> method, in order to enforce the
951+ * general contract of the <tt>Object.hashCode</tt> method among sets
952+ * returned by this method.
953+ *
954+ * @return an identity-based set view of the keys contained in this map
955+ * @see Object#equals(Object)
956+ * @see System#identityHashCode(Object)
957+ */
958+ public Set<K> keySet() {
959+ Set<K> ks = keySet;
960+ if (ks != null)
961+ return ks;
962+ else
963+ return keySet = new KeySet();
964+ }
965+
966+ private class KeySet extends AbstractSet<K> {
967+ public Iterator<K> iterator() {
968+ return new KeyIterator();
969+ }
970+ public int size() {
971+ return size;
972+ }
973+ public boolean contains(Object o) {
974+ return containsKey(o);
975+ }
976+ public boolean remove(Object o) {
977+ int oldSize = size;
978+ IdentityHashMap.this.remove(o);
979+ return size != oldSize;
980+ }
981+ /*
982+ * Must revert from AbstractSet's impl to AbstractCollection's, as
983+ * the former contains an optimization that results in incorrect
984+ * behavior when c is a smaller "normal" (non-identity-based) Set.
985+ */
986+ public boolean removeAll(Collection<?> c) {
987+ boolean modified = false;
988+ for (Iterator<K> i = iterator(); i.hasNext(); ) {
989+ if (c.contains(i.next())) {
990+ i.remove();
991+ modified = true;
992+ }
993+ }
994+ return modified;
995+ }
996+ public void clear() {
997+ IdentityHashMap.this.clear();
998+ }
999+ public int hashCode() {
1000+ int result = 0;
1001+ for (K key : this)
1002+ result += System.identityHashCode(key);
1003+ return result;
1004+ }
1005+ }
1006+
1007+ /**
1008+ * Returns a {@link Collection} view of the values contained in this map.
1009+ * The collection is backed by the map, so changes to the map are
1010+ * reflected in the collection, and vice-versa. If the map is
1011+ * modified while an iteration over the collection is in progress,
1012+ * the results of the iteration are undefined. The collection
1013+ * supports element removal, which removes the corresponding
1014+ * mapping from the map, via the <tt>Iterator.remove</tt>,
1015+ * <tt>Collection.remove</tt>, <tt>removeAll</tt>,
1016+ * <tt>retainAll</tt> and <tt>clear</tt> methods. It does not
1017+ * support the <tt>add</tt> or <tt>addAll</tt> methods.
1018+ *
1019+ * <p><b>While the object returned by this method implements the
1020+ * <tt>Collection</tt> interface, it does <i>not</i> obey
1021+ * <tt>Collection's</tt> general contract. Like its backing map,
1022+ * the collection returned by this method defines element equality as
1023+ * reference-equality rather than object-equality. This affects the
1024+ * behavior of its <tt>contains</tt>, <tt>remove</tt> and
1025+ * <tt>containsAll</tt> methods.</b>
1026+ */
1027+ public Collection<V> values() {
1028+ Collection<V> vs = values;
1029+ if (vs != null)
1030+ return vs;
1031+ else
1032+ return values = new Values();
1033+ }
1034+
1035+ private class Values extends AbstractCollection<V> {
1036+ public Iterator<V> iterator() {
1037+ return new ValueIterator();
1038+ }
1039+ public int size() {
1040+ return size;
1041+ }
1042+ public boolean contains(Object o) {
1043+ return containsValue(o);
1044+ }
1045+ public boolean remove(Object o) {
1046+ for (Iterator<V> i = iterator(); i.hasNext(); ) {
1047+ if (i.next() == o) {
1048+ i.remove();
1049+ return true;
1050+ }
1051+ }
1052+ return false;
1053+ }
1054+ public void clear() {
1055+ IdentityHashMap.this.clear();
1056+ }
1057+ }
1058+
1059+ /**
1060+ * Returns a {@link Set} view of the mappings contained in this map.
1061+ * Each element in the returned set is a reference-equality-based
1062+ * <tt>Map.Entry</tt>. The set is backed by the map, so changes
1063+ * to the map are reflected in the set, and vice-versa. If the
1064+ * map is modified while an iteration over the set is in progress,
1065+ * the results of the iteration are undefined. The set supports
1066+ * element removal, which removes the corresponding mapping from
1067+ * the map, via the <tt>Iterator.remove</tt>, <tt>Set.remove</tt>,
1068+ * <tt>removeAll</tt>, <tt>retainAll</tt> and <tt>clear</tt>
1069+ * methods. It does not support the <tt>add</tt> or
1070+ * <tt>addAll</tt> methods.
1071+ *
1072+ * <p>Like the backing map, the <tt>Map.Entry</tt> objects in the set
1073+ * returned by this method define key and value equality as
1074+ * reference-equality rather than object-equality. This affects the
1075+ * behavior of the <tt>equals</tt> and <tt>hashCode</tt> methods of these
1076+ * <tt>Map.Entry</tt> objects. A reference-equality based <tt>Map.Entry
1077+ * e</tt> is equal to an object <tt>o</tt> if and only if <tt>o</tt> is a
1078+ * <tt>Map.Entry</tt> and <tt>e.getKey()==o.getKey() &amp;&amp;
1079+ * e.getValue()==o.getValue()</tt>. To accommodate these equals
1080+ * semantics, the <tt>hashCode</tt> method returns
1081+ * <tt>System.identityHashCode(e.getKey()) ^
1082+ * System.identityHashCode(e.getValue())</tt>.
1083+ *
1084+ * <p><b>Owing to the reference-equality-based semantics of the
1085+ * <tt>Map.Entry</tt> instances in the set returned by this method,
1086+ * it is possible that the symmetry and transitivity requirements of
1087+ * the {@link Object#equals(Object)} contract may be violated if any of
1088+ * the entries in the set is compared to a normal map entry, or if
1089+ * the set returned by this method is compared to a set of normal map
1090+ * entries (such as would be returned by a call to this method on a normal
1091+ * map). However, the <tt>Object.equals</tt> contract is guaranteed to
1092+ * hold among identity-based map entries, and among sets of such entries.
1093+ * </b>
1094+ *
1095+ * @return a set view of the identity-mappings contained in this map
1096+ */
1097+ public Set<Map.Entry<K,V>> entrySet() {
1098+ Set<Map.Entry<K,V>> es = entrySet;
1099+ if (es != null)
1100+ return es;
1101+ else
1102+ return entrySet = new EntrySet();
1103+ }
1104+
1105+ private class EntrySet extends AbstractSet<Map.Entry<K,V>> {
1106+ public Iterator<Map.Entry<K,V>> iterator() {
1107+ return new EntryIterator();
1108+ }
1109+ public boolean contains(Object o) {
1110+ if (!(o instanceof Map.Entry))
1111+ return false;
1112+ Map.Entry entry = (Map.Entry)o;
1113+ return containsMapping(entry.getKey(), entry.getValue());
1114+ }
1115+ public boolean remove(Object o) {
1116+ if (!(o instanceof Map.Entry))
1117+ return false;
1118+ Map.Entry entry = (Map.Entry)o;
1119+ return removeMapping(entry.getKey(), entry.getValue());
1120+ }
1121+ public int size() {
1122+ return size;
1123+ }
1124+ public void clear() {
1125+ IdentityHashMap.this.clear();
1126+ }
1127+ /*
1128+ * Must revert from AbstractSet's impl to AbstractCollection's, as
1129+ * the former contains an optimization that results in incorrect
1130+ * behavior when c is a smaller "normal" (non-identity-based) Set.
1131+ */
1132+ public boolean removeAll(Collection<?> c) {
1133+ boolean modified = false;
1134+ for (Iterator<Map.Entry<K,V>> i = iterator(); i.hasNext(); ) {
1135+ if (c.contains(i.next())) {
1136+ i.remove();
1137+ modified = true;
1138+ }
1139+ }
1140+ return modified;
1141+ }
1142+
1143+ public Object[] toArray() {
1144+ int size = size();
1145+ Object[] result = new Object[size];
1146+ Iterator<Map.Entry<K,V>> it = iterator();
1147+ for (int i = 0; i < size; i++)
1148+ result[i] = new AbstractMap.SimpleEntry<>(it.next());
1149+ return result;
1150+ }
1151+
1152+ @SuppressWarnings("unchecked")
1153+ public <T> T[] toArray(T[] a) {
1154+ int size = size();
1155+ if (a.length < size)
1156+ a = (T[])java.lang.reflect.Array
1157+ .newInstance(a.getClass().getComponentType(), size);
1158+ Iterator<Map.Entry<K,V>> it = iterator();
1159+ for (int i = 0; i < size; i++)
1160+ a[i] = (T) new AbstractMap.SimpleEntry<>(it.next());
1161+ if (a.length > size)
1162+ a[size] = null;
1163+ return a;
1164+ }
1165+ }
1166+
1167+
1168+ private static final long serialVersionUID = 8188218128353913216L;
1169+
1170+ /**
1171+ * Save the state of the <tt>IdentityHashMap</tt> instance to a stream
1172+ * (i.e., serialize it).
1173+ *
1174+ * @serialData The <i>size</i> of the HashMap (the number of key-value
1175+ * mappings) (<tt>int</tt>), followed by the key (Object) and
1176+ * value (Object) for each key-value mapping represented by the
1177+ * IdentityHashMap. The key-value mappings are emitted in no
1178+ * particular order.
1179+ */
1180+ private void writeObject(java.io.ObjectOutputStream s)
1181+ throws java.io.IOException {
1182+ // Write out and any hidden stuff
1183+ s.defaultWriteObject();
1184+
1185+ // Write out size (number of Mappings)
1186+ s.writeInt(size);
1187+
1188+ // Write out keys and values (alternating)
1189+ Object[] tab = table;
1190+ for (int i = 0; i < tab.length; i += 2) {
1191+ Object key = tab[i];
1192+ if (key != null) {
1193+ s.writeObject(unmaskNull(key));
1194+ s.writeObject(tab[i + 1]);
1195+ }
1196+ }
1197+ }
1198+
1199+ /**
1200+ * Reconstitute the <tt>IdentityHashMap</tt> instance from a stream (i.e.,
1201+ * deserialize it).
1202+ */
1203+ private void readObject(java.io.ObjectInputStream s)
1204+ throws java.io.IOException, ClassNotFoundException {
1205+ // Read in any hidden stuff
1206+ s.defaultReadObject();
1207+
1208+ // Read in size (number of Mappings)
1209+ int size = s.readInt();
1210+
1211+ // Allow for 33% growth (i.e., capacity is >= 2* size()).
1212+ init(capacity((size*4)/3));
1213+
1214+ // Read the keys and values, and put the mappings in the table
1215+ for (int i=0; i<size; i++) {
1216+ K key = (K) s.readObject();
1217+ V value = (V) s.readObject();
1218+ putForCreate(key, value);
1219+ }
1220+ }
1221+
1222+ /**
1223+ * The put method for readObject. It does not resize the table,
1224+ * update modCount, etc.
1225+ */
1226+ private void putForCreate(K key, V value)
1227+ throws IOException
1228+ {
1229+ K k = (K)maskNull(key);
1230+ Object[] tab = table;
1231+ int len = tab.length;
1232+ int i = hash(k, len);
1233+
1234+ Object item;
1235+ while ( (item = tab[i]) != null) {
1236+ if (item == k)
1237+ throw new java.io.StreamCorruptedException();
1238+ i = nextKeyIndex(i, len);
1239+ }
1240+ tab[i] = k;
1241+ tab[i + 1] = value;
1242+ }
1243+}