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