001/*
002 *   Copyright (C) Christian Schulte, 2005-206
003 *   All rights reserved.
004 *
005 *   Redistribution and use in source and binary forms, with or without
006 *   modification, are permitted provided that the following conditions
007 *   are met:
008 *
009 *     o Redistributions of source code must retain the above copyright
010 *       notice, this list of conditions and the following disclaimer.
011 *
012 *     o Redistributions in binary form must reproduce the above copyright
013 *       notice, this list of conditions and the following disclaimer in
014 *       the documentation and/or other materials provided with the
015 *       distribution.
016 *
017 *   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
018 *   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
019 *   AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
020 *   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY DIRECT, INDIRECT,
021 *   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
022 *   NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
023 *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
024 *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
025 *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
026 *   THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
027 *
028 *   $JOMC: WeakIdentityHashMap.java 4173 2012-01-15 07:50:51Z schulte2005 $
029 *
030 */
031package org.jomc.util;
032
033import java.lang.ref.ReferenceQueue;
034import java.lang.ref.WeakReference;
035import java.util.AbstractCollection;
036import java.util.AbstractSet;
037import java.util.Collection;
038import java.util.ConcurrentModificationException;
039import java.util.Iterator;
040import java.util.Map;
041import java.util.NoSuchElementException;
042import java.util.Set;
043
044/**
045 * Hash-table based {@code Map} implementation with weak keys, using object-identity in place of object-equality when
046 * comparing keys.
047 *
048 * <p>In a {@code WeakIdentityHashMap} two keys {@code k1} and {@code k2} are considered equal if and only if
049 * {@code k1==k2} evaluates to {@code true}. An entry will automatically be removed when its key is no longer in
050 * ordinary use. More precisely, the presence of a mapping for a given key will not prevent the key from being discarded
051 * by the garbage collector, that is, made finalizable, finalised, and then reclaimed. When a key has been discarded its
052 * entry is effectively removed from the map, so this class behaves somewhat differently from other {@code Map}
053 * implementations and is not a general-purpose {@code Map} implementation! Although it implements the {@code Map}
054 * interface, it intentionally violates {@code Map}'s general contract, which mandates the use of the {@code equals}
055 * method when comparing objects.</p>
056 *
057 * <p>This class has performance characteristics similar to those of the {@code HashMap} class, and has the same
058 * efficiency parameters of {@code initialCapacity} and {@code loadFactor}. All of the optional map operations are
059 * provided. It does not support {@code null} values and the {@code null} key. All methods taking a key or value will
060 * throw a {@code NullPointerException} when given a {@code null} reference. No guarantees are made as to the order of
061 * the map; in particular, there is no guarantee that the order will remain constant over time. Like most collection
062 * classes, this class is not synchronised. A synchronised {@code WeakIdentityHashMap} may be constructed using the
063 * {@code Collections.synchronizedMap} method.</p>
064 *
065 * <p>The behaviour of the {@code WeakIdentityHashMap} class depends in part upon the actions of the garbage collector,
066 * so several {@code Map} invariants do not hold for this class. Because the garbage collector may discard keys at
067 * any time, a {@code WeakIdentityHashMap} may behave as though an unknown thread is silently removing entries. In
068 * particular, even if synchronising on a {@code WeakIdentityHashMap} instance and invoking none of its mutator
069 * methods, it is possible for the {@code size} method to return smaller values over time, for the {@code isEmpty}
070 * method to return {@code false} and then {@code true}, for the {@code containsKey} method to return {@code true} and
071 * later {@code false} for a given key, for the {@code get} method to return a value for a given key but later return
072 * {@code null}, for the {@code put} method to return {@code null} and the {@code remove} method to return {@code false}
073 * for a key that previously appeared to be in the map, and for successive examinations of the key set, the value
074 * collection, and the entry set to yield successively smaller numbers of elements. To protect against such situations
075 * all {@code Iterator}s and {@code Entry}s created by this class throw an {@code IllegalStateException} when a key
076 * becomes {@code null} or a mapping got removed.</p>
077 *
078 * <p>The iterators returned by the {@code iterator} method of the collections returned by all of this classes
079 * "collection view methods" are fail-fast: if the map is structurally modified at any time after the iterator is
080 * created, in any way except through the iterator's own {@code remove} method, the iterator will throw a
081 * {@code ConcurrentModificationException}. Note that the fail-fast behaviour of an iterator cannot be guaranteed as it
082 * is, generally speaking, impossible to make any hard guarantees in the presence of unsynchronised concurrent
083 * modification. Fail-fast iterators throw {@code ConcurrentModificationException}s on a best-effort basis. Therefore,
084 * it would be wrong to write a program that depends on this exception for its correctness: <i>the fail-fast behaviour
085 * of iterators should be used only to detect bugs.</i></p>
086 *
087 * @param <K> The type of keys maintained by this map.
088 * @param <V> The type of mapped values.
089 *
090 * @author <a href="mailto:schulte2005@users.sourceforge.net">Christian Schulte</a>
091 * @version $JOMC: WeakIdentityHashMap.java 4173 2012-01-15 07:50:51Z schulte2005 $
092 *
093 * @see java.util.HashMap
094 * @see java.util.WeakHashMap
095 * @see java.util.IdentityHashMap
096 * @see java.util.Collections#synchronizedMap
097 */
098public final class WeakIdentityHashMap<K, V> implements Map<K, V>
099{
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() )  &amp;&amp;
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}