EMMA Coverage Report (generated Fri Feb 21 04:03:47 CET 2014)
[all classes][org.jomc.util]

COVERAGE SUMMARY FOR SOURCE FILE [WeakIdentityHashMap.java]

nameclass, %method, %block, %line, %
WeakIdentityHashMap.java0%   (0/9)0%   (0/63)0%   (0/1162)0%   (0/254)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class WeakIdentityHashMap0%   (0/1)0%   (0/30)0%   (0/742)0%   (0/167)
WeakIdentityHashMap (): void 0%   (0/1)0%   (0/5)0%   (0/2)
WeakIdentityHashMap (float): void 0%   (0/1)0%   (0/5)0%   (0/2)
WeakIdentityHashMap (int): void 0%   (0/1)0%   (0/5)0%   (0/2)
WeakIdentityHashMap (int, float): void 0%   (0/1)0%   (0/58)0%   (0/13)
access$400 (WeakIdentityHashMap): WeakIdentityHashMap$WeakEntry [] 0%   (0/1)0%   (0/3)0%   (0/1)
access$500 (WeakIdentityHashMap): int 0%   (0/1)0%   (0/3)0%   (0/1)
calculateCapacity (): int 0%   (0/1)0%   (0/28)0%   (0/7)
clear (): void 0%   (0/1)0%   (0/26)0%   (0/7)
containsKey (Object): boolean 0%   (0/1)0%   (0/16)0%   (0/3)
containsValue (Object): boolean 0%   (0/1)0%   (0/38)0%   (0/8)
decreaseSize (): void 0%   (0/1)0%   (0/16)0%   (0/4)
entrySet (): Set 0%   (0/1)0%   (0/12)0%   (0/3)
equals (Object): boolean 0%   (0/1)0%   (0/23)0%   (0/5)
finalize (): void 0%   (0/1)0%   (0/14)0%   (0/4)
get (Object): Object 0%   (0/1)0%   (0/12)0%   (0/3)
getEntry (Object): WeakIdentityHashMap$WeakEntry 0%   (0/1)0%   (0/32)0%   (0/6)
getHashTable (): WeakIdentityHashMap$WeakEntry [] 0%   (0/1)0%   (0/63)0%   (0/15)
getHashTableIndex (int, int): int 0%   (0/1)0%   (0/6)0%   (0/1)
hashCode (): int 0%   (0/1)0%   (0/4)0%   (0/1)
increaseSize (): void 0%   (0/1)0%   (0/26)0%   (0/5)
internalString (): String 0%   (0/1)0%   (0/58)0%   (0/8)
isEmpty (): boolean 0%   (0/1)0%   (0/7)0%   (0/1)
keySet (): Set 0%   (0/1)0%   (0/12)0%   (0/3)
purge (): void 0%   (0/1)0%   (0/63)0%   (0/14)
put (Object, Object): Object 0%   (0/1)0%   (0/75)0%   (0/17)
putAll (Map): void 0%   (0/1)0%   (0/27)0%   (0/8)
remove (Object): Object 0%   (0/1)0%   (0/74)0%   (0/17)
size (): int 0%   (0/1)0%   (0/8)0%   (0/3)
toString (): String 0%   (0/1)0%   (0/11)0%   (0/1)
values (): Collection 0%   (0/1)0%   (0/12)0%   (0/3)
     
class WeakIdentityHashMap$10%   (0/1)0%   (0/3)0%   (0/16)0%   (0/3)
WeakIdentityHashMap$1 (WeakIdentityHashMap): void 0%   (0/1)0%   (0/6)0%   (0/1)
iterator (): Iterator 0%   (0/1)0%   (0/6)0%   (0/1)
size (): int 0%   (0/1)0%   (0/4)0%   (0/1)
     
class WeakIdentityHashMap$20%   (0/1)0%   (0/3)0%   (0/16)0%   (0/3)
WeakIdentityHashMap$2 (WeakIdentityHashMap): void 0%   (0/1)0%   (0/6)0%   (0/1)
iterator (): Iterator 0%   (0/1)0%   (0/6)0%   (0/1)
size (): int 0%   (0/1)0%   (0/4)0%   (0/1)
     
class WeakIdentityHashMap$30%   (0/1)0%   (0/3)0%   (0/16)0%   (0/3)
WeakIdentityHashMap$3 (WeakIdentityHashMap): void 0%   (0/1)0%   (0/6)0%   (0/1)
iterator (): Iterator 0%   (0/1)0%   (0/6)0%   (0/1)
size (): int 0%   (0/1)0%   (0/4)0%   (0/1)
     
class WeakIdentityHashMap$EntryIterator0%   (0/1)0%   (0/2)0%   (0/10)0%   (0/4)
WeakIdentityHashMap$EntryIterator (WeakIdentityHashMap): void 0%   (0/1)0%   (0/7)0%   (0/3)
next (): Map$Entry 0%   (0/1)0%   (0/3)0%   (0/1)
     
class WeakIdentityHashMap$KeyIterator0%   (0/1)0%   (0/2)0%   (0/11)0%   (0/4)
WeakIdentityHashMap$KeyIterator (WeakIdentityHashMap): void 0%   (0/1)0%   (0/7)0%   (0/3)
next (): Object 0%   (0/1)0%   (0/4)0%   (0/1)
     
class WeakIdentityHashMap$ValueIterator0%   (0/1)0%   (0/2)0%   (0/11)0%   (0/4)
WeakIdentityHashMap$ValueIterator (WeakIdentityHashMap): void 0%   (0/1)0%   (0/7)0%   (0/3)
next (): Object 0%   (0/1)0%   (0/4)0%   (0/1)
     
class WeakIdentityHashMap$WeakEntry0%   (0/1)0%   (0/14)0%   (0/168)0%   (0/30)
WeakIdentityHashMap$WeakEntry (Object, Object, int, ReferenceQueue): void 0%   (0/1)0%   (0/11)0%   (0/4)
access$000 (WeakIdentityHashMap$WeakEntry): Object 0%   (0/1)0%   (0/3)0%   (0/1)
access$002 (WeakIdentityHashMap$WeakEntry, Object): Object 0%   (0/1)0%   (0/5)0%   (0/1)
access$100 (WeakIdentityHashMap$WeakEntry): WeakIdentityHashMap$WeakEntry 0%   (0/1)0%   (0/3)0%   (0/1)
access$102 (WeakIdentityHashMap$WeakEntry, WeakIdentityHashMap$WeakEntry): We... 0%   (0/1)0%   (0/5)0%   (0/1)
access$200 (WeakIdentityHashMap$WeakEntry): int 0%   (0/1)0%   (0/3)0%   (0/1)
access$302 (WeakIdentityHashMap$WeakEntry, boolean): boolean 0%   (0/1)0%   (0/5)0%   (0/1)
equals (Object): boolean 0%   (0/1)0%   (0/32)0%   (0/5)
getKey (): Object 0%   (0/1)0%   (0/14)0%   (0/4)
getValue (): Object 0%   (0/1)0%   (0/13)0%   (0/3)
hashCode (): int 0%   (0/1)0%   (0/7)0%   (0/1)
internalString (): String 0%   (0/1)0%   (0/24)0%   (0/3)
setValue (Object): Object 0%   (0/1)0%   (0/32)0%   (0/8)
toString (): String 0%   (0/1)0%   (0/11)0%   (0/1)
     
class WeakIdentityHashMap$WeakEntryIterator0%   (0/1)0%   (0/4)0%   (0/172)0%   (0/36)
WeakIdentityHashMap$WeakEntryIterator (WeakIdentityHashMap): void 0%   (0/1)0%   (0/46)0%   (0/8)
hasNext (): boolean 0%   (0/1)0%   (0/17)0%   (0/3)
nextElement (): Map$Entry 0%   (0/1)0%   (0/68)0%   (0/14)
remove (): void 0%   (0/1)0%   (0/41)0%   (0/11)

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 */
31package org.jomc.util;
32 
33import java.lang.ref.ReferenceQueue;
34import java.lang.ref.WeakReference;
35import java.util.AbstractCollection;
36import java.util.AbstractSet;
37import java.util.Collection;
38import java.util.ConcurrentModificationException;
39import java.util.Iterator;
40import java.util.Map;
41import java.util.NoSuchElementException;
42import 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 */
98public 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() )  &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}

[all classes][org.jomc.util]
EMMA 2.1.5320 (stable) (C) Vladimir Roubtsov