| 1 | /* | 
| 2 |  *   Copyright (C) Christian Schulte, 2005-206 | 
| 3 |  *   All rights reserved. | 
| 4 |  * | 
| 5 |  *   Redistribution and use in source and binary forms, with or without | 
| 6 |  *   modification, are permitted provided that the following conditions | 
| 7 |  *   are met: | 
| 8 |  * | 
| 9 |  *     o Redistributions of source code must retain the above copyright | 
| 10 |  *       notice, this list of conditions and the following disclaimer. | 
| 11 |  * | 
| 12 |  *     o Redistributions in binary form must reproduce the above copyright | 
| 13 |  *       notice, this list of conditions and the following disclaimer in | 
| 14 |  *       the documentation and/or other materials provided with the | 
| 15 |  *       distribution. | 
| 16 |  * | 
| 17 |  *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, | 
| 18 |  *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY | 
| 19 |  *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL | 
| 20 |  *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT, | 
| 21 |  *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | 
| 22 |  *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | 
| 23 |  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | 
| 24 |  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | 
| 25 |  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | 
| 26 |  *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 
| 27 |  * | 
| 28 |  *   $JOMC: WeakIdentityHashMap.java 4613 2012-09-22 10:07:08Z schulte $ | 
| 29 |  * | 
| 30 |  */ | 
| 31 | package org.jomc.util; | 
| 32 |   | 
| 33 | import java.lang.ref.ReferenceQueue; | 
| 34 | import java.lang.ref.WeakReference; | 
| 35 | import java.util.AbstractCollection; | 
| 36 | import java.util.AbstractSet; | 
| 37 | import java.util.Collection; | 
| 38 | import java.util.ConcurrentModificationException; | 
| 39 | import java.util.Iterator; | 
| 40 | import java.util.Map; | 
| 41 | import java.util.NoSuchElementException; | 
| 42 | import java.util.Set; | 
| 43 |   | 
| 44 | /** | 
| 45 |  * Hash-table based {@code Map} implementation with weak keys, using object-identity in place of object-equality when | 
| 46 |  * comparing keys. | 
| 47 |  * | 
| 48 |  * <p>In a {@code WeakIdentityHashMap} two keys {@code k1} and {@code k2} are considered equal if and only if | 
| 49 |  * {@code k1==k2} evaluates to {@code true}. An entry will automatically be removed when its key is no longer in | 
| 50 |  * ordinary use. More precisely, the presence of a mapping for a given key will not prevent the key from being discarded | 
| 51 |  * by the garbage collector, that is, made finalizable, finalised, and then reclaimed. When a key has been discarded its | 
| 52 |  * entry is effectively removed from the map, so this class behaves somewhat differently from other {@code Map} | 
| 53 |  * implementations and is not a general-purpose {@code Map} implementation! Although it implements the {@code Map} | 
| 54 |  * interface, it intentionally violates {@code Map}'s general contract, which mandates the use of the {@code equals} | 
| 55 |  * method when comparing objects.</p> | 
| 56 |  * | 
| 57 |  * <p>This class has performance characteristics similar to those of the {@code HashMap} class, and has the same | 
| 58 |  * efficiency parameters of {@code initialCapacity} and {@code loadFactor}. All of the optional map operations are | 
| 59 |  * provided. It does not support {@code null} values and the {@code null} key. All methods taking a key or value will | 
| 60 |  * throw a {@code NullPointerException} when given a {@code null} reference. No guarantees are made as to the order of | 
| 61 |  * the map; in particular, there is no guarantee that the order will remain constant over time. Like most collection | 
| 62 |  * classes, this class is not synchronised. A synchronised {@code WeakIdentityHashMap} may be constructed using the | 
| 63 |  * {@code Collections.synchronizedMap} method.</p> | 
| 64 |  * | 
| 65 |  * <p>The behaviour of the {@code WeakIdentityHashMap} class depends in part upon the actions of the garbage collector, | 
| 66 |  * so several {@code Map} invariants do not hold for this class. Because the garbage collector may discard keys at | 
| 67 |  * any time, a {@code WeakIdentityHashMap} may behave as though an unknown thread is silently removing entries. In | 
| 68 |  * particular, even if synchronising on a {@code WeakIdentityHashMap} instance and invoking none of its mutator | 
| 69 |  * methods, it is possible for the {@code size} method to return smaller values over time, for the {@code isEmpty} | 
| 70 |  * method to return {@code false} and then {@code true}, for the {@code containsKey} method to return {@code true} and | 
| 71 |  * later {@code false} for a given key, for the {@code get} method to return a value for a given key but later return | 
| 72 |  * {@code null}, for the {@code put} method to return {@code null} and the {@code remove} method to return {@code false} | 
| 73 |  * for a key that previously appeared to be in the map, and for successive examinations of the key set, the value | 
| 74 |  * collection, and the entry set to yield successively smaller numbers of elements. To protect against such situations | 
| 75 |  * all {@code Iterator}s and {@code Entry}s created by this class throw an {@code IllegalStateException} when a key | 
| 76 |  * becomes {@code null} or a mapping got removed.</p> | 
| 77 |  * | 
| 78 |  * <p>The iterators returned by the {@code iterator} method of the collections returned by all of this classes | 
| 79 |  * "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is | 
| 80 |  * created, in any way except through the iterator's own {@code remove} method, the iterator will throw a | 
| 81 |  * {@code ConcurrentModificationException}. Note that the fail-fast behaviour of an iterator cannot be guaranteed as it | 
| 82 |  * is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronised concurrent | 
| 83 |  * modification. Fail-fast iterators throw {@code ConcurrentModificationException}s on a best-effort basis. Therefore, | 
| 84 |  * it would be wrong to write a program that depends on this exception for its correctness: <i>the fail-fast behaviour | 
| 85 |  * of iterators should be used only to detect bugs.</i></p> | 
| 86 |  * | 
| 87 |  * @param <K> The type of keys maintained by this map. | 
| 88 |  * @param <V> The type of mapped values. | 
| 89 |  * | 
| 90 |  * @author <a href="mailto:cs@schulte.it">Christian Schulte</a> | 
| 91 |  * @version $JOMC: WeakIdentityHashMap.java 4613 2012-09-22 10:07:08Z schulte $ | 
| 92 |  * | 
| 93 |  * @see java.util.HashMap | 
| 94 |  * @see java.util.WeakHashMap | 
| 95 |  * @see java.util.IdentityHashMap | 
| 96 |  * @see java.util.Collections#synchronizedMap | 
| 97 |  */ | 
| 98 | public final class WeakIdentityHashMap<K, V> implements Map<K, V> | 
| 99 | { | 
| 100 |   | 
| 101 |     /** Maximum capacity of the hash-table backing the implementation ({@code 2^30}). */ | 
| 102 |     private static final int MAXIMUM_CAPACITY = 0x40000000; | 
| 103 |   | 
| 104 |     /** Default initial capacity ({@code 2^4}). */ | 
| 105 |     private static final int DEFAULT_INITIAL_CAPACITY = 16; | 
| 106 |   | 
| 107 |     /** Default load factor ({@code 0.75}). */ | 
| 108 |     private static final float DEFAULT_LOAD_FACTOR = 0.75F; | 
| 109 |   | 
| 110 |     /** The number of times the map got structurally modified. */ | 
| 111 |     private int modifications; | 
| 112 |   | 
| 113 |     /** The number of mappings held by the map. */ | 
| 114 |     private int size; | 
| 115 |   | 
| 116 |     /** The size value at which the hash table needs resizing. */ | 
| 117 |     private int resizeThreshold; | 
| 118 |   | 
| 119 |     /** The hash-table backing the map. */ | 
| 120 |     private WeakEntry<K, V>[] hashTable; | 
| 121 |   | 
| 122 |     /** Queue, to which weak keys are appended to. */ | 
| 123 |     private final ReferenceQueue<K> referenceQueue = new ReferenceQueue<K>(); | 
| 124 |   | 
| 125 |     /** The key set view of the map. */ | 
| 126 |     private transient Set<K> keySet; | 
| 127 |   | 
| 128 |     /** The entry set view of the map. */ | 
| 129 |     private transient Set<Map.Entry<K, V>> entrySet; | 
| 130 |   | 
| 131 |     /** The value collection view of the map. */ | 
| 132 |     private transient Collection<V> valueCollection; | 
| 133 |   | 
| 134 |     /** The initial capacity of the hash table. */ | 
| 135 |     private final int initialCapacity; | 
| 136 |   | 
| 137 |     /** The load factor for the hash table. */ | 
| 138 |     private final float loadFactor; | 
| 139 |   | 
| 140 |     /** Null value returned by method {@link #getEntry(Object)}. */ | 
| 141 |     private final WeakEntry<K, V> NULL_ENTRY = new WeakEntry<K, V>( null, null, 0, this.referenceQueue ); | 
| 142 |   | 
| 143 |     /** | 
| 144 |      * Constructs a new, empty {@code WeakIdentityHashMap} with the default initial capacity ({@code 16}) and load | 
| 145 |      * factor ({@code 0.75}). | 
| 146 |      */ | 
| 147 |     public WeakIdentityHashMap() | 
| 148 |     { | 
| 149 |         this( DEFAULT_INITIAL_CAPACITY, DEFAULT_LOAD_FACTOR ); | 
| 150 |     } | 
| 151 |   | 
| 152 |     /** | 
| 153 |      * Constructs a new, empty {@code WeakIdentityHashMap} with the given initial capacity and the default load factor | 
| 154 |      * ({@code 0.75}). | 
| 155 |      * | 
| 156 |      * @param  initialCapacity The initial capacity of the {@code WeakIdentityHashMap}. | 
| 157 |      * | 
| 158 |      * @throws IllegalArgumentException if {@code initialCapacity} is negative or greater than the maximum supported | 
| 159 |      * capacity ({@code 2^30}). | 
| 160 |      */ | 
| 161 |     public WeakIdentityHashMap( final int initialCapacity ) | 
| 162 |     { | 
| 163 |         this( initialCapacity, DEFAULT_LOAD_FACTOR ); | 
| 164 |     } | 
| 165 |   | 
| 166 |     /** | 
| 167 |      * Constructs a new, empty {@code WeakIdentityHashMap} with the default initial capacity ({@code 16}) and the given | 
| 168 |      * load factor. | 
| 169 |      * | 
| 170 |      * @param loadFactor The load factor of the {@code WeakIdentityHashMap}. | 
| 171 |      * | 
| 172 |      * @throws IllegalArgumentException if {@code loadFactor} is nonpositive. | 
| 173 |      */ | 
| 174 |     public WeakIdentityHashMap( final float loadFactor ) | 
| 175 |     { | 
| 176 |         this( DEFAULT_INITIAL_CAPACITY, loadFactor ); | 
| 177 |     } | 
| 178 |   | 
| 179 |     /** | 
| 180 |      * Constructs a new, empty {@code WeakIdentityHashMap} with the given initial capacity and the given load factor. | 
| 181 |      * | 
| 182 |      * @param initialCapacity The initial capacity of the {@code WeakIdentityHashMap}. | 
| 183 |      * @param loadFactor The load factor of the {@code WeakIdentityHashMap}. | 
| 184 |      * | 
| 185 |      * @throws IllegalArgumentException if {@code initialCapacity} is negative or greater than the maximum supported | 
| 186 |      * capacity ({@code 2^30}), or if {@code loadFactor} is nonpositive. | 
| 187 |      */ | 
| 188 |     public WeakIdentityHashMap( final int initialCapacity, final float loadFactor ) | 
| 189 |     { | 
| 190 |         if ( initialCapacity < 0 || initialCapacity > MAXIMUM_CAPACITY ) | 
| 191 |         { | 
| 192 |             throw new IllegalArgumentException( Integer.toString( initialCapacity ) ); | 
| 193 |         } | 
| 194 |         if ( loadFactor <= 0 || Float.isNaN( loadFactor ) ) | 
| 195 |         { | 
| 196 |             throw new IllegalArgumentException( Float.toString( loadFactor ) ); | 
| 197 |         } | 
| 198 |   | 
| 199 |         this.initialCapacity = initialCapacity; | 
| 200 |         this.loadFactor = loadFactor; | 
| 201 |         this.resizeThreshold = initialCapacity; | 
| 202 |         this.size = 0; | 
| 203 |         this.hashTable = new WeakEntry[ initialCapacity ]; | 
| 204 |     } | 
| 205 |   | 
| 206 |     /** | 
| 207 |      * Gets the number of key-value mappings in this map. | 
| 208 |      * <p>If the map contains more than {@code Integer.MAX_VALUE} elements, returns {@code Integer.MAX_VALUE}.</p> | 
| 209 |      * | 
| 210 |      * @return The number of key-value mappings in this map. | 
| 211 |      */ | 
| 212 |     public int size() | 
| 213 |     { | 
| 214 |         if ( this.size > 0 ) | 
| 215 |         { | 
| 216 |             this.purge(); | 
| 217 |         } | 
| 218 |   | 
| 219 |         return this.size; | 
| 220 |     } | 
| 221 |   | 
| 222 |     /** | 
| 223 |      * Gets a flag indicating if this map is empty. | 
| 224 |      * | 
| 225 |      * @return {@code true}, if this map contains no key-value mappings; {@code false}, if this map contains at least | 
| 226 |      * one mapping. | 
| 227 |      */ | 
| 228 |     public boolean isEmpty() | 
| 229 |     { | 
| 230 |         return this.size() == 0; | 
| 231 |     } | 
| 232 |   | 
| 233 |     /** | 
| 234 |      * Gets a flag indicating if this map contains a mapping for a given key. | 
| 235 |      * <p>More formally, returns {@code true}, if and only if this map contains a mapping for a key {@code k} such that | 
| 236 |      * {@code key==k}. There can be at most one such mapping.</p> | 
| 237 |      * | 
| 238 |      * @param key The key whose presence in this map is to be tested. | 
| 239 |      * | 
| 240 |      * @return {@code true}, if this map contains a mapping for {@code key}; {@code false}, if this map does not contain | 
| 241 |      * a mapping for {@code key}. | 
| 242 |      * | 
| 243 |      * @throws NullPointerException if {@code key} is {@code null}. | 
| 244 |      */ | 
| 245 |     public boolean containsKey( final Object key ) | 
| 246 |     { | 
| 247 |         if ( key == null ) | 
| 248 |         { | 
| 249 |             throw new NullPointerException( "key" ); | 
| 250 |         } | 
| 251 |   | 
| 252 |         return this.getEntry( key ).value != null; | 
| 253 |     } | 
| 254 |   | 
| 255 |     /** | 
| 256 |      * Gets a flag indicating if this map maps one or more keys to the specified value. | 
| 257 |      * <p>More formally, this method returns {@code true}, if and only if this map contains at least one mapping to a | 
| 258 |      * value {@code v} such that {@code value.equals(v)}. This operation requires time linear in the map size.</p> | 
| 259 |      * | 
| 260 |      * @param value The value whose presence in this map is to be tested. | 
| 261 |      * | 
| 262 |      * @return {@code true}, if this map maps one or more keys to {@code value}; {@code false}, if this map does not map | 
| 263 |      * any key to {@code value}. | 
| 264 |      * | 
| 265 |      * @throws NullPointerException if {@code value} is {@code null}. | 
| 266 |      */ | 
| 267 |     public boolean containsValue( final Object value ) | 
| 268 |     { | 
| 269 |         if ( value == null ) | 
| 270 |         { | 
| 271 |             throw new NullPointerException( "value" ); | 
| 272 |         } | 
| 273 |   | 
| 274 |         final WeakEntry<K, V>[] table = this.getHashTable(); | 
| 275 |   | 
| 276 |         for ( int i = table.length - 1; i >= 0; i-- ) | 
| 277 |         { | 
| 278 |             for ( WeakEntry<K, V> e = table[i]; e != null; e = e.next ) | 
| 279 |             { | 
| 280 |                 if ( value.equals( e.value ) ) | 
| 281 |                 { | 
| 282 |                     return true; | 
| 283 |                 } | 
| 284 |             } | 
| 285 |         } | 
| 286 |   | 
| 287 |         return false; | 
| 288 |     } | 
| 289 |   | 
| 290 |     /** | 
| 291 |      * Gets the value to which a given key is mapped or {@code null}, if this map contains no mapping for that key. | 
| 292 |      * <p>More formally, if this map contains a mapping from a key {@code k} to a value {@code v} such that | 
| 293 |      * {@code key==k}, then this method returns {@code v}; otherwise it returns {@code null}. There can be at most one | 
| 294 |      * such mapping.</p> | 
| 295 |      * | 
| 296 |      * @param key The key whose associated value is to be returned. | 
| 297 |      * | 
| 298 |      * @return The value to which {@code key} is mapped or {@code null}, if this map contains no mapping for | 
| 299 |      * {@code key}. | 
| 300 |      * | 
| 301 |      * @throws NullPointerException if {@code key} is {@code null}. | 
| 302 |      */ | 
| 303 |     public V get( final Object key ) | 
| 304 |     { | 
| 305 |         if ( key == null ) | 
| 306 |         { | 
| 307 |             throw new NullPointerException( "key" ); | 
| 308 |         } | 
| 309 |   | 
| 310 |         return this.getEntry( key ).value; | 
| 311 |     } | 
| 312 |   | 
| 313 |     /** | 
| 314 |      * Associates a given value with a given key in this map. | 
| 315 |      * <p>If the map previously contained a mapping for that key, the old value is replaced by the given value.</p> | 
| 316 |      * | 
| 317 |      * @param key The key with which {@code value} is to be associated. | 
| 318 |      * @param value The value to be associated with {@code key}. | 
| 319 |      * | 
| 320 |      * @return The value previously associated with {@code key} or {@code null}, if there was no mapping for | 
| 321 |      * {@code key}. | 
| 322 |      * | 
| 323 |      * @throws NullPointerException if {@code key} or {@code value} is {@code null}. | 
| 324 |      */ | 
| 325 |     public V put( final K key, final V value ) | 
| 326 |     { | 
| 327 |         if ( key == null ) | 
| 328 |         { | 
| 329 |             throw new NullPointerException( "key" ); | 
| 330 |         } | 
| 331 |         if ( value == null ) | 
| 332 |         { | 
| 333 |             throw new NullPointerException( "value" ); | 
| 334 |         } | 
| 335 |   | 
| 336 |         final int hashCode = System.identityHashCode( key ); | 
| 337 |         final WeakEntry<K, V>[] table = this.getHashTable(); | 
| 338 |         final int index = getHashTableIndex( hashCode, table.length ); | 
| 339 |   | 
| 340 |         for ( WeakEntry<K, V> e = table[index]; e != null; e = e.next ) | 
| 341 |         { | 
| 342 |             if ( e.hashCode == hashCode && e.get() == key ) | 
| 343 |             { | 
| 344 |                 final V oldValue = e.value; | 
| 345 |                 e.value = value; | 
| 346 |                 return oldValue; | 
| 347 |             } | 
| 348 |         } | 
| 349 |   | 
| 350 |         final WeakEntry<K, V> entry = new WeakEntry<K, V>( key, value, hashCode, this.referenceQueue ); | 
| 351 |         entry.next = table[index]; | 
| 352 |         table[index] = entry; | 
| 353 |   | 
| 354 |         this.increaseSize(); | 
| 355 |   | 
| 356 |         return null; | 
| 357 |     } | 
| 358 |   | 
| 359 |     /** | 
| 360 |      * Removes the mapping for a given key from this map if it is present. | 
| 361 |      * <p>More formally, if this map contains a mapping from key {@code k} to value {@code v} such that {@code key==k}, | 
| 362 |      * that mapping is removed. The map can contain at most one such mapping. The map will not contain a mapping for the | 
| 363 |      * given key once the call returns.</p> | 
| 364 |      * | 
| 365 |      * @param key The key whose mapping is to be removed from the map. | 
| 366 |      * | 
| 367 |      * @return The value previously associated with {@code key} or {@code null}, if there was no mapping for | 
| 368 |      * {@code key}. | 
| 369 |      * | 
| 370 |      * @throws NullPointerException if {@code key} is {@code null}. | 
| 371 |      */ | 
| 372 |     public V remove( final Object key ) | 
| 373 |     { | 
| 374 |         if ( key == null ) | 
| 375 |         { | 
| 376 |             throw new NullPointerException( "key" ); | 
| 377 |         } | 
| 378 |   | 
| 379 |         final WeakEntry<K, V>[] table = this.getHashTable(); | 
| 380 |         final int hashCode = System.identityHashCode( key ); | 
| 381 |         final int index = getHashTableIndex( hashCode, table.length ); | 
| 382 |   | 
| 383 |         for ( WeakEntry<K, V> e = table[index], pre = null; e != null; pre = e, e = e.next ) | 
| 384 |         { | 
| 385 |             if ( e.hashCode == hashCode && e.get() == key ) | 
| 386 |             { | 
| 387 |                 if ( pre != null ) | 
| 388 |                 { | 
| 389 |                     pre.next = e.next; | 
| 390 |                 } | 
| 391 |                 else | 
| 392 |                 { | 
| 393 |                     table[index] = e.next; | 
| 394 |                 } | 
| 395 |   | 
| 396 |                 this.decreaseSize(); | 
| 397 |   | 
| 398 |                 final V removed = e.value; | 
| 399 |                 e.removed = true; | 
| 400 |                 e.value = null; | 
| 401 |                 e.next = null; | 
| 402 |                 return removed; | 
| 403 |             } | 
| 404 |         } | 
| 405 |   | 
| 406 |         return null; | 
| 407 |     } | 
| 408 |   | 
| 409 |     /** | 
| 410 |      * Copies all of the mappings from a given map to this map. | 
| 411 |      * <p>The effect of this call is equivalent to that of calling {@link #put(Object,Object) put(k, v)} on this map | 
| 412 |      * once for each mapping from key {@code k} to value {@code v} in the given map. The behavior of this operation is | 
| 413 |      * undefined if the given map is modified while the operation is in progress.</p> | 
| 414 |      * | 
| 415 |      * @param m The mappings to be stored in this map. | 
| 416 |      * | 
| 417 |      * @throws NullPointerException if {@code map} is {@code null}, or if {@code map} contains {@code null} keys or | 
| 418 |      * values. | 
| 419 |      */ | 
| 420 |     public void putAll( final Map<? extends K, ? extends V> m ) | 
| 421 |     { | 
| 422 |         if ( m == null ) | 
| 423 |         { | 
| 424 |             throw new NullPointerException( "m" ); | 
| 425 |         } | 
| 426 |   | 
| 427 |         for ( final Iterator<? extends Map.Entry<? extends K, ? extends V>> it = m.entrySet().iterator(); | 
| 428 |               it.hasNext(); ) | 
| 429 |         { | 
| 430 |             final Map.Entry<? extends K, ? extends V> entry = it.next(); | 
| 431 |             this.put( entry.getKey(), entry.getValue() ); | 
| 432 |         } | 
| 433 |     } | 
| 434 |   | 
| 435 |     /** Removes all of the mappings from this map so that the map will be empty after this call returns. */ | 
| 436 |     @SuppressWarnings( "empty-statement" ) | 
| 437 |     public void clear() | 
| 438 |     { | 
| 439 |         this.purge(); | 
| 440 |         this.hashTable = new WeakEntry[ this.initialCapacity ]; | 
| 441 |         this.size = 0; | 
| 442 |         this.resizeThreshold = this.initialCapacity; | 
| 443 |         this.modifications++; | 
| 444 |         while ( this.referenceQueue.poll() != null ); | 
| 445 |     } | 
| 446 |   | 
| 447 |     /** | 
| 448 |      * Gets a {@code Set} view of the keys contained in this map. | 
| 449 |      * <p>The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is | 
| 450 |      * modified while an iteration over the set is in progress (except through the iterator's own {@code remove} | 
| 451 |      * operation), the results of the iteration are undefined, that is, the iterator may throw an | 
| 452 |      * {@code IllegalStateException}. The set supports element removal, which removes the corresponding mapping from the | 
| 453 |      * map, via the {@code Iterator.remove}, {@code Set.remove}, {@code removeAll}, {@code retainAll}, and {@code clear} | 
| 454 |      * operations. It does not support the {@code add} or {@code addAll} operations.</p> | 
| 455 |      * | 
| 456 |      * @return A set view of the keys contained in this map. | 
| 457 |      */ | 
| 458 |     public Set<K> keySet() | 
| 459 |     { | 
| 460 |         if ( this.keySet == null ) | 
| 461 |         { | 
| 462 |             this.keySet = new AbstractSet<K>() | 
| 463 |             { | 
| 464 |   | 
| 465 |                 public Iterator<K> iterator() | 
| 466 |                 { | 
| 467 |                     return new KeyIterator(); | 
| 468 |                 } | 
| 469 |   | 
| 470 |                 public int size() | 
| 471 |                 { | 
| 472 |                     return WeakIdentityHashMap.this.size(); | 
| 473 |                 } | 
| 474 |   | 
| 475 |             }; | 
| 476 |   | 
| 477 |         } | 
| 478 |   | 
| 479 |         return this.keySet; | 
| 480 |     } | 
| 481 |   | 
| 482 |     /** | 
| 483 |      * Gets a {@code Collection} view of the values contained in this map. | 
| 484 |      * <p>The collection is backed by the map, so changes to the map are reflected in the collection, and vice-versa. | 
| 485 |      * If the map is modified while an iteration over the collection is in progress (except through the iterator's own | 
| 486 |      * {@code remove} operation), the results of the iteration are undefined, that is, the iterator may throw an | 
| 487 |      * {@code IllegalStateException}. The collection supports element removal, which removes the corresponding mapping | 
| 488 |      * from the map, via the {@code Iterator.remove}, {@code Collection.remove}, {@code removeAll}, {@code retainAll} | 
| 489 |      * and {@code clear} operations. It does not support the {@code add} or {@code addAll} operations.</p> | 
| 490 |      * | 
| 491 |      * @return A collection view of the values contained in this map. | 
| 492 |      */ | 
| 493 |     public Collection<V> values() | 
| 494 |     { | 
| 495 |         if ( this.valueCollection == null ) | 
| 496 |         { | 
| 497 |             this.valueCollection = new AbstractCollection<V>() | 
| 498 |             { | 
| 499 |   | 
| 500 |                 public Iterator<V> iterator() | 
| 501 |                 { | 
| 502 |                     return new ValueIterator(); | 
| 503 |                 } | 
| 504 |   | 
| 505 |                 public int size() | 
| 506 |                 { | 
| 507 |                     return WeakIdentityHashMap.this.size(); | 
| 508 |                 } | 
| 509 |   | 
| 510 |             }; | 
| 511 |         } | 
| 512 |   | 
| 513 |         return this.valueCollection; | 
| 514 |     } | 
| 515 |   | 
| 516 |     /** | 
| 517 |      * Gets a {@code Set} view of the mappings contained in this map. | 
| 518 |      * <p>The set is backed by the map, so changes to the map are reflected in the set, and vice-versa. If the map is | 
| 519 |      * modified while an iteration over the set is in progress (except through the iterator's own {@code remove} | 
| 520 |      * operation, or through the {@code setValue} operation on a map entry returned by the iterator) the results of the | 
| 521 |      * iteration are undefined, that is, the iterator may throw an {@code IllegalStateException}. The set supports | 
| 522 |      * element removal, which removes the corresponding mapping from the map, via the {@code Iterator.remove}, | 
| 523 |      * {@code Set.remove}, {@code removeAll}, {@code retainAll} and {@code clear} operations. It does not support the | 
| 524 |      * {@code add} or {@code addAll} operations.</p> | 
| 525 |      * | 
| 526 |      * @return A set view of the mappings contained in this map. | 
| 527 |      */ | 
| 528 |     public Set<Map.Entry<K, V>> entrySet() | 
| 529 |     { | 
| 530 |         if ( this.entrySet == null ) | 
| 531 |         { | 
| 532 |             this.entrySet = new AbstractSet<Map.Entry<K, V>>() | 
| 533 |             { | 
| 534 |   | 
| 535 |                 public Iterator<Map.Entry<K, V>> iterator() | 
| 536 |                 { | 
| 537 |                     return new EntryIterator(); | 
| 538 |                 } | 
| 539 |   | 
| 540 |                 public int size() | 
| 541 |                 { | 
| 542 |                     return WeakIdentityHashMap.this.size(); | 
| 543 |                 } | 
| 544 |   | 
| 545 |             }; | 
| 546 |         } | 
| 547 |   | 
| 548 |         return this.entrySet; | 
| 549 |     } | 
| 550 |   | 
| 551 |     /** | 
| 552 |      * Returns a string representation of the object. | 
| 553 |      * | 
| 554 |      * @return A string representation of the object. | 
| 555 |      */ | 
| 556 |     @Override | 
| 557 |     public String toString() | 
| 558 |     { | 
| 559 |         return super.toString() + this.internalString(); | 
| 560 |     } | 
| 561 |   | 
| 562 |     /** | 
| 563 |      * Compares the specified object with this map for equality. | 
| 564 |      * <p>Returns {@code true}, if the given object is also a map and the two maps represent the same mappings. More | 
| 565 |      * formally, two maps {@code m1} and {@code m2} represent the same mappings if | 
| 566 |      * {@code m1.entrySet().equals(m2.entrySet())}.</p> | 
| 567 |      * | 
| 568 |      * @param o The object to be compared for equality with this map. | 
| 569 |      * | 
| 570 |      * @return {@code true}, if {@code o} is equal to this map; {@code false}, if {@code o} is not equal to this map. | 
| 571 |      */ | 
| 572 |     @Override | 
| 573 |     public boolean equals( final Object o ) | 
| 574 |     { | 
| 575 |         boolean equal = this == o; | 
| 576 |   | 
| 577 |         if ( !equal && o instanceof Map<?, ?> ) | 
| 578 |         { | 
| 579 |             final Map<?, ?> that = (Map<?, ?>) o; | 
| 580 |             equal = this.entrySet().equals( that.entrySet() ); | 
| 581 |         } | 
| 582 |   | 
| 583 |         return equal; | 
| 584 |     } | 
| 585 |   | 
| 586 |     /** | 
| 587 |      * Gets the hash code value for this map. | 
| 588 |      * <p>The hash code of a map is defined to be the sum of the hash codes of each entry in the map's | 
| 589 |      * {@code entrySet()} view.</p> | 
| 590 |      * | 
| 591 |      * @return The hash code value for this map. | 
| 592 |      */ | 
| 593 |     @Override | 
| 594 |     public int hashCode() | 
| 595 |     { | 
| 596 |         return this.entrySet().hashCode(); | 
| 597 |     } | 
| 598 |   | 
| 599 |     /** | 
| 600 |      * Finalizes the object by polling the internal reference queue for any pending references. | 
| 601 |      * | 
| 602 |      * @since 1.2 | 
| 603 |      */ | 
| 604 |     @Override | 
| 605 |     protected void finalize() throws Throwable | 
| 606 |     { | 
| 607 |         this.modifications++; | 
| 608 |         while ( this.referenceQueue.poll() != null ); | 
| 609 |         super.finalize(); | 
| 610 |     } | 
| 611 |   | 
| 612 |     /** | 
| 613 |      * Creates a string representing the mappings of the instance. | 
| 614 |      * | 
| 615 |      * @return A string representing the mappings of the instance. | 
| 616 |      */ | 
| 617 |     private String internalString() | 
| 618 |     { | 
| 619 |         final StringBuilder buf = new StringBuilder( 12 * this.size() ).append( '{' ); | 
| 620 |         final WeakEntry<K, V>[] table = this.getHashTable(); | 
| 621 |         for ( int i = table.length - 1, index = 0; i >= 0; i-- ) | 
| 622 |         { | 
| 623 |             for ( WeakEntry<K, V> e = table[i]; e != null; e = e.next ) | 
| 624 |             { | 
| 625 |                 if ( buf.length() > 1 ) | 
| 626 |                 { | 
| 627 |                     buf.append( ", " ); | 
| 628 |                 } | 
| 629 |   | 
| 630 |                 buf.append( '[' ).append( index++ ).append( "]=" ).append( e ); | 
| 631 |             } | 
| 632 |         } | 
| 633 |   | 
| 634 |         return buf.append( '}' ).toString(); | 
| 635 |     } | 
| 636 |   | 
| 637 |     /** | 
| 638 |      * Gets the index of a hash code value. | 
| 639 |      * | 
| 640 |      * @param hashCode The hash code value to return the index of. | 
| 641 |      * @param capacity The capacity to return an index for. | 
| 642 |      * | 
| 643 |      * @return The index of {@code hashCode} for {@code capacity}. | 
| 644 |      */ | 
| 645 |     private static int getHashTableIndex( final int hashCode, final int capacity ) | 
| 646 |     { | 
| 647 |         return hashCode & ( capacity - 1 ); | 
| 648 |     } | 
| 649 |   | 
| 650 |     /** | 
| 651 |      * Gets the hash-table backing the instance. | 
| 652 |      * <p>This method creates a new hash-table and re-hashes any mappings whenever the size of the map gets greater than | 
| 653 |      * the capacity of the internal hash-table times the load factor value.</p> | 
| 654 |      * | 
| 655 |      * @return The hash-table backing the instance. | 
| 656 |      */ | 
| 657 |     private WeakEntry<K, V>[] getHashTable() | 
| 658 |     { | 
| 659 |         if ( this.hashTable.length < this.resizeThreshold ) | 
| 660 |         { | 
| 661 |             @SuppressWarnings( "unchecked" ) | 
| 662 |             final WeakEntry<K, V>[] table = new WeakEntry[ this.calculateCapacity() ]; | 
| 663 |   | 
| 664 |             for ( int i = this.hashTable.length - 1; i >= 0; i-- ) | 
| 665 |             { | 
| 666 |                 WeakEntry<K, V> entry = this.hashTable[i]; | 
| 667 |   | 
| 668 |                 while ( entry != null ) | 
| 669 |                 { | 
| 670 |                     final WeakEntry<K, V> next = entry.next; | 
| 671 |                     final int index = getHashTableIndex( entry.hashCode, table.length ); | 
| 672 |   | 
| 673 |                     entry.next = table[index]; | 
| 674 |                     table[index] = entry; | 
| 675 |                     entry = next; | 
| 676 |                 } | 
| 677 |             } | 
| 678 |   | 
| 679 |             this.hashTable = table; | 
| 680 |             this.modifications++; | 
| 681 |         } | 
| 682 |   | 
| 683 |         this.purge(); | 
| 684 |         return this.hashTable; | 
| 685 |     } | 
| 686 |   | 
| 687 |     /** Removes any garbage collected entries. */ | 
| 688 |     private void purge() | 
| 689 |     { | 
| 690 |         WeakEntry<K, V> purge; | 
| 691 |   | 
| 692 |         while ( ( purge = (WeakEntry<K, V>) this.referenceQueue.poll() ) != null ) | 
| 693 |         { | 
| 694 |             final int index = getHashTableIndex( purge.hashCode, this.hashTable.length ); | 
| 695 |   | 
| 696 |             for ( WeakEntry<K, V> e = this.hashTable[index], pre = null; e != null; pre = e, e = e.next ) | 
| 697 |             { | 
| 698 |                 if ( e == purge ) | 
| 699 |                 { | 
| 700 |                     if ( pre != null ) | 
| 701 |                     { | 
| 702 |                         pre.next = purge.next; | 
| 703 |                     } | 
| 704 |                     else | 
| 705 |                     { | 
| 706 |                         this.hashTable[index] = purge.next; | 
| 707 |                     } | 
| 708 |   | 
| 709 |                     purge.removed = true; | 
| 710 |                     purge.next = null; | 
| 711 |                     purge.value = null; | 
| 712 |   | 
| 713 |                     this.decreaseSize(); | 
| 714 |   | 
| 715 |                     break; | 
| 716 |                 } | 
| 717 |             } | 
| 718 |         } | 
| 719 |     } | 
| 720 |   | 
| 721 |     private void increaseSize() | 
| 722 |     { | 
| 723 |         if ( this.size < Integer.MAX_VALUE ) | 
| 724 |         { | 
| 725 |             this.size++; | 
| 726 |             this.resizeThreshold = (int) ( this.size * this.loadFactor ); | 
| 727 |         } | 
| 728 |   | 
| 729 |         this.modifications++; | 
| 730 |     } | 
| 731 |   | 
| 732 |     private void decreaseSize() | 
| 733 |     { | 
| 734 |         if ( this.size > 0 ) | 
| 735 |         { | 
| 736 |             this.size--; | 
| 737 |         } | 
| 738 |   | 
| 739 |         this.modifications++; | 
| 740 |     } | 
| 741 |   | 
| 742 |     private int calculateCapacity() | 
| 743 |     { | 
| 744 |         int maxCapacity = this.initialCapacity; | 
| 745 |         if ( maxCapacity < this.resizeThreshold ) | 
| 746 |         { | 
| 747 |             maxCapacity = this.resizeThreshold > MAXIMUM_CAPACITY ? MAXIMUM_CAPACITY : this.resizeThreshold; | 
| 748 |         } | 
| 749 |   | 
| 750 |         int capacity = 1; | 
| 751 |         while ( capacity < maxCapacity ) | 
| 752 |         { | 
| 753 |             capacity <<= 1; | 
| 754 |         } | 
| 755 |   | 
| 756 |         return capacity; | 
| 757 |     } | 
| 758 |   | 
| 759 |     private WeakEntry<K, V> getEntry( final Object key ) | 
| 760 |     { | 
| 761 |         final int hashCode = System.identityHashCode( key ); | 
| 762 |         final WeakEntry<K, V>[] table = getHashTable(); | 
| 763 |   | 
| 764 |         for ( WeakEntry<K, V> e = table[getHashTableIndex( hashCode, table.length )]; e != null; e = e.next ) | 
| 765 |         { | 
| 766 |             if ( e.hashCode == hashCode && e.get() == key ) | 
| 767 |             { | 
| 768 |                 return e; | 
| 769 |             } | 
| 770 |         } | 
| 771 |   | 
| 772 |         return NULL_ENTRY; | 
| 773 |     } | 
| 774 |   | 
| 775 |     /** | 
| 776 |      * A map entry (key-value pair) with weakly referenced key. | 
| 777 |      * <p>The {@code WeakIdentityHashMap.entrySet} method returns a collection-view of the map, whose elements are of | 
| 778 |      * this class. The only way to obtain a reference to a map entry is from the iterator of this collection-view. These | 
| 779 |      * {@code Map.Entry} objects are valid only for the duration of the iteration; more formally, the behavior of a map | 
| 780 |      * entry is undefined if the backing map has been modified after the entry was returned by the iterator, except | 
| 781 |      * through the {@code setValue} operation on the map entry.</p> | 
| 782 |      * | 
| 783 |      * @param <K> The type of the key. | 
| 784 |      * @param <V> The type of the value. | 
| 785 |      * | 
| 786 |      * @see WeakIdentityHashMap#entrySet() | 
| 787 |      */ | 
| 788 |     private static class WeakEntry<K, V> extends WeakReference<K> implements Map.Entry<K, V> | 
| 789 |     { | 
| 790 |   | 
| 791 |         /** The value of the entry. */ | 
| 792 |         private V value; | 
| 793 |   | 
| 794 |         /** The next entry in the bucket. */ | 
| 795 |         private WeakEntry<K, V> next; | 
| 796 |   | 
| 797 |         /** Flag indicating that this entry got removed from the map. */ | 
| 798 |         private boolean removed; | 
| 799 |   | 
| 800 |         /** The hash code value of the key. */ | 
| 801 |         private final int hashCode; | 
| 802 |   | 
| 803 |         WeakEntry( final K key, final V value, final int hashCode, final ReferenceQueue<K> queue ) | 
| 804 |         { | 
| 805 |             super( key, queue ); | 
| 806 |             this.hashCode = hashCode; | 
| 807 |             this.value = value; | 
| 808 |         } | 
| 809 |   | 
| 810 |         /** | 
| 811 |          * Gets the key corresponding to this entry. | 
| 812 |          * | 
| 813 |          * @return The key corresponding to this entry. | 
| 814 |          * | 
| 815 |          * @throws IllegalStateException if the entry got removed from the backing map (either due to an iterator's | 
| 816 |          * {@code remove} operation or due to the key having been garbage collected). | 
| 817 |          */ | 
| 818 |         public K getKey() | 
| 819 |         { | 
| 820 |             final K key = this.get(); | 
| 821 |   | 
| 822 |             if ( key == null || this.removed ) | 
| 823 |             { | 
| 824 |                 throw new IllegalStateException(); | 
| 825 |             } | 
| 826 |   | 
| 827 |             return key; | 
| 828 |         } | 
| 829 |   | 
| 830 |         /** | 
| 831 |          * Gets the value corresponding to this entry. | 
| 832 |          * | 
| 833 |          * @return The value corresponding to this entry. | 
| 834 |          * | 
| 835 |          * @throws IllegalStateException if the entry got removed from the backing map (either due to an iterator's | 
| 836 |          * {@code remove} operation or due to the key having been garbage collected). | 
| 837 |          */ | 
| 838 |         public V getValue() | 
| 839 |         { | 
| 840 |             if ( this.get() == null || this.removed ) | 
| 841 |             { | 
| 842 |                 throw new IllegalStateException(); | 
| 843 |             } | 
| 844 |   | 
| 845 |             return this.value; | 
| 846 |         } | 
| 847 |   | 
| 848 |         /** | 
| 849 |          * Replaces the value corresponding to this entry with the specified value. | 
| 850 |          * | 
| 851 |          * @param value The new value to be stored in this entry. | 
| 852 |          * | 
| 853 |          * @return The old value corresponding to the entry. | 
| 854 |          * | 
| 855 |          * @throws NullPointerException if {@code value} is {@code null}. | 
| 856 |          * @throws IllegalStateException if the entry got removed from the backing map (either due to an iterator's | 
| 857 |          * {@code remove} operation or due to the key having been garbage collected). | 
| 858 |          */ | 
| 859 |         public V setValue( final V value ) | 
| 860 |         { | 
| 861 |             if ( value == null ) | 
| 862 |             { | 
| 863 |                 throw new NullPointerException( "value" ); | 
| 864 |             } | 
| 865 |             if ( this.get() == null || this.removed ) | 
| 866 |             { | 
| 867 |                 throw new IllegalStateException(); | 
| 868 |             } | 
| 869 |   | 
| 870 |             final V oldValue = this.getValue(); | 
| 871 |   | 
| 872 |             if ( value != oldValue && !value.equals( oldValue ) ) | 
| 873 |             { | 
| 874 |                 this.value = value; | 
| 875 |             } | 
| 876 |   | 
| 877 |             return oldValue; | 
| 878 |         } | 
| 879 |   | 
| 880 |         /** | 
| 881 |          * Returns a string representation of the object. | 
| 882 |          * | 
| 883 |          * @return A string representation of the object. | 
| 884 |          */ | 
| 885 |         @Override | 
| 886 |         public String toString() | 
| 887 |         { | 
| 888 |             return super.toString() + this.internalString(); | 
| 889 |         } | 
| 890 |   | 
| 891 |         /** | 
| 892 |          * Compares a given object with this entry for equality. | 
| 893 |          * <p>Returns {@code true}, if the given object is also a map entry and the two entries represent the same | 
| 894 |          * mapping. More formally, two entries {@code e1} and {@code e2} represent the same mapping if | 
| 895 |          * <pre><blockquote> | 
| 896 |          * ( e1.getKey() == e2.getKey() )  && | 
| 897 |          * ( e1.getValue().equals( e2.getValue() ) ) | 
| 898 |          * </blockquote></pre></p> | 
| 899 |          * | 
| 900 |          * @param o The object to be compared for equality with this map entry. | 
| 901 |          * | 
| 902 |          * @return {@code true}, if {@code o} is equal to this map entry; {@code false}, if {@code o} is not equal to | 
| 903 |          * this map entry. | 
| 904 |          */ | 
| 905 |         @Override | 
| 906 |         public boolean equals( final Object o ) | 
| 907 |         { | 
| 908 |             boolean equal = this == o; | 
| 909 |   | 
| 910 |             if ( !equal && o instanceof Map.Entry<?, ?> ) | 
| 911 |             { | 
| 912 |                 final Map.Entry<?, ?> that = (Map.Entry<?, ?>) o; | 
| 913 |                 equal = this.getKey() == that.getKey() && this.getValue().equals( that.getValue() ); | 
| 914 |             } | 
| 915 |   | 
| 916 |             return equal; | 
| 917 |         } | 
| 918 |   | 
| 919 |         /** | 
| 920 |          * Gets the hash code value for this map entry. | 
| 921 |          * <p>The hash code of a map entry {@code e} is defined to be: | 
| 922 |          * <pre><blockquote> | 
| 923 |          * ( e.getKey() == null ? 0 : e.getKey().hashCode() ) ^ | 
| 924 |          * ( e.getValue() == null ? 0 : e.getValue().hashCode() ) | 
| 925 |          * </blockquote></pre></p> | 
| 926 |          * | 
| 927 |          * @return The hash code value for this map entry. | 
| 928 |          */ | 
| 929 |         @Override | 
| 930 |         public int hashCode() | 
| 931 |         { | 
| 932 |             return ( this.hashCode ) ^ ( this.getValue().hashCode() ); | 
| 933 |         } | 
| 934 |   | 
| 935 |         /** | 
| 936 |          * Creates a string representing the properties of the instance. | 
| 937 |          * | 
| 938 |          * @return A string representing the properties of the instance. | 
| 939 |          */ | 
| 940 |         private String internalString() | 
| 941 |         { | 
| 942 |             final StringBuilder buf = new StringBuilder( 50 ).append( '{' ); | 
| 943 |             buf.append( "key=" ).append( this.getKey() ).append( ", value=" ).append( this.getValue() ); | 
| 944 |             return buf.append( '}' ).toString(); | 
| 945 |         } | 
| 946 |   | 
| 947 |     } | 
| 948 |   | 
| 949 |     /** Base iterator implementation over the hash-table backing the implementation. */ | 
| 950 |     private class WeakEntryIterator | 
| 951 |     { | 
| 952 |   | 
| 953 |         /** The next element in the iteration. */ | 
| 954 |         private WeakEntry<K, V> next; | 
| 955 |   | 
| 956 |         /** The current element in the iteration. */ | 
| 957 |         private WeakEntry<K, V> current; | 
| 958 |   | 
| 959 |         /** The current index into the hash-table. */ | 
| 960 |         private int index; | 
| 961 |   | 
| 962 |         /** The number of modifications when this iterator got created. */ | 
| 963 |         private int modifications; | 
| 964 |   | 
| 965 |         /** Creates a new {@code WeakEntryIterator} instance. */ | 
| 966 |         WeakEntryIterator() | 
| 967 |         { | 
| 968 |             final WeakEntry<K, V>[] table = getHashTable(); | 
| 969 |             for ( this.index = table.length - 1; this.index >= 0; this.index-- ) | 
| 970 |             { | 
| 971 |                 if ( table[this.index] != null ) | 
| 972 |                 { | 
| 973 |                     this.next = table[this.index--]; | 
| 974 |                     break; | 
| 975 |                 } | 
| 976 |             } | 
| 977 |   | 
| 978 |             this.modifications = WeakIdentityHashMap.this.modifications; | 
| 979 |         } | 
| 980 |   | 
| 981 |         /** | 
| 982 |          * Gets a flag indicating that the iteration has more elements. | 
| 983 |          * | 
| 984 |          * @return {@code true}, if the iterator has more elements; {@code false}, if the iterator does not have more | 
| 985 |          * elements. | 
| 986 |          */ | 
| 987 |         public boolean hasNext() | 
| 988 |         { | 
| 989 |             if ( this.modifications != WeakIdentityHashMap.this.modifications ) | 
| 990 |             { | 
| 991 |                 throw new ConcurrentModificationException(); | 
| 992 |             } | 
| 993 |   | 
| 994 |             return this.next != null; | 
| 995 |         } | 
| 996 |   | 
| 997 |         /** | 
| 998 |          * Gets the next element in the iteration. | 
| 999 |          * | 
| 1000 |          * @return The next element in the iteration. | 
| 1001 |          * | 
| 1002 |          * @throws NoSuchElementException if the iterator does not have more elements. | 
| 1003 |          */ | 
| 1004 |         public Map.Entry<K, V> nextElement() | 
| 1005 |         { | 
| 1006 |             if ( this.modifications != WeakIdentityHashMap.this.modifications ) | 
| 1007 |             { | 
| 1008 |                 throw new ConcurrentModificationException(); | 
| 1009 |             } | 
| 1010 |             if ( this.next == null ) | 
| 1011 |             { | 
| 1012 |                 throw new NoSuchElementException(); | 
| 1013 |             } | 
| 1014 |   | 
| 1015 |             this.current = this.next; | 
| 1016 |   | 
| 1017 |             if ( this.next.next != null ) | 
| 1018 |             { | 
| 1019 |                 this.next = this.next.next; | 
| 1020 |             } | 
| 1021 |             else | 
| 1022 |             { | 
| 1023 |                 this.next = null; | 
| 1024 |                 final WeakEntry<K, V>[] table = getHashTable(); | 
| 1025 |                 for ( ; this.index >= 0; this.index-- ) | 
| 1026 |                 { | 
| 1027 |                     if ( table[this.index] != null ) | 
| 1028 |                     { | 
| 1029 |                         this.next = table[this.index--]; | 
| 1030 |                         break; | 
| 1031 |                     } | 
| 1032 |                 } | 
| 1033 |             } | 
| 1034 |   | 
| 1035 |             return this.current; | 
| 1036 |         } | 
| 1037 |   | 
| 1038 |         /** | 
| 1039 |          * Removes from the underlying hash-table the last element returned by the iterator. | 
| 1040 |          * | 
| 1041 |          * @throws IllegalStateException if the {@code next} method has not yet been called, or the {@code remove} | 
| 1042 |          * method has already been called after the last call to the {@code next} method. | 
| 1043 |          */ | 
| 1044 |         public void remove() | 
| 1045 |         { | 
| 1046 |             if ( this.modifications != WeakIdentityHashMap.this.modifications ) | 
| 1047 |             { | 
| 1048 |                 throw new ConcurrentModificationException(); | 
| 1049 |             } | 
| 1050 |             if ( this.current == null ) | 
| 1051 |             { | 
| 1052 |                 throw new IllegalStateException(); | 
| 1053 |             } | 
| 1054 |   | 
| 1055 |             final K key = this.current.getKey(); | 
| 1056 |   | 
| 1057 |             if ( key == null ) | 
| 1058 |             { | 
| 1059 |                 throw new IllegalStateException(); | 
| 1060 |             } | 
| 1061 |   | 
| 1062 |             WeakIdentityHashMap.this.remove( key ); | 
| 1063 |             this.modifications = WeakIdentityHashMap.this.modifications; | 
| 1064 |             this.current = null; | 
| 1065 |         } | 
| 1066 |   | 
| 1067 |     } | 
| 1068 |   | 
| 1069 |     /** Iterator over the hash-table backing the implementation. */ | 
| 1070 |     private class EntryIterator extends WeakEntryIterator implements Iterator<Map.Entry<K, V>> | 
| 1071 |     { | 
| 1072 |   | 
| 1073 |         /** Creates a new {@code EntryIterator} instance. */ | 
| 1074 |         EntryIterator() | 
| 1075 |         { | 
| 1076 |             super(); | 
| 1077 |         } | 
| 1078 |   | 
| 1079 |         /** | 
| 1080 |          * Gets the next element in the iteration. | 
| 1081 |          * | 
| 1082 |          * @return The next element in the iteration. | 
| 1083 |          * | 
| 1084 |          * @throws NoSuchElementException if the iterator does not have more elements. | 
| 1085 |          */ | 
| 1086 |         public Map.Entry<K, V> next() | 
| 1087 |         { | 
| 1088 |             return super.nextElement(); | 
| 1089 |         } | 
| 1090 |   | 
| 1091 |     } | 
| 1092 |   | 
| 1093 |     /** Iterator over the hash-table backing the implementation. */ | 
| 1094 |     private class KeyIterator extends WeakEntryIterator implements Iterator<K> | 
| 1095 |     { | 
| 1096 |   | 
| 1097 |         /** Creates a new {@code KeyIterator} instance. */ | 
| 1098 |         KeyIterator() | 
| 1099 |         { | 
| 1100 |             super(); | 
| 1101 |         } | 
| 1102 |   | 
| 1103 |         /** | 
| 1104 |          * Gets the next element in the iteration. | 
| 1105 |          * | 
| 1106 |          * @return The next element in the iteration. | 
| 1107 |          * | 
| 1108 |          * @throws NoSuchElementException if the iterator does not have more elements. | 
| 1109 |          */ | 
| 1110 |         public K next() | 
| 1111 |         { | 
| 1112 |             return super.nextElement().getKey(); | 
| 1113 |         } | 
| 1114 |   | 
| 1115 |     } | 
| 1116 |   | 
| 1117 |     /** Iterator over the hash-table backing the implementation. */ | 
| 1118 |     private class ValueIterator extends WeakEntryIterator implements Iterator<V> | 
| 1119 |     { | 
| 1120 |   | 
| 1121 |         /** Creates a new {@code ValueIterator} instance. */ | 
| 1122 |         ValueIterator() | 
| 1123 |         { | 
| 1124 |             super(); | 
| 1125 |         } | 
| 1126 |   | 
| 1127 |         /** | 
| 1128 |          * Gets the next element in the iteration. | 
| 1129 |          * | 
| 1130 |          * @return The next element in the iteration. | 
| 1131 |          * | 
| 1132 |          * @throws NoSuchElementException if the iterator does not have more elements. | 
| 1133 |          */ | 
| 1134 |         public V next() | 
| 1135 |         { | 
| 1136 |             return super.nextElement().getValue(); | 
| 1137 |         } | 
| 1138 |   | 
| 1139 |     } | 
| 1140 |   | 
| 1141 | } |