Showing the changes to java/pkg/java/util/IdentityHashMap.java (1 of 18352 files). Show all
Unified · Split
| @@ -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() && | ||
| 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 | } | ||