• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // GenericsNote: Converted -- However, null keys will now be represented in the internal structures, a big change.
2 /*
3  *  Copyright 2003-2004 The Apache Software Foundation
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17 package org.jivesoftware.smack.util.collections;
18 
19 import java.io.IOException;
20 import java.io.ObjectInputStream;
21 import java.io.ObjectOutputStream;
22 import java.util.*;
23 
24 /**
25  * An abstract implementation of a hash-based map which provides numerous points for
26  * subclasses to override.
27  * <p/>
28  * This class implements all the features necessary for a subclass hash-based map.
29  * Key-value entries are stored in instances of the <code>HashEntry</code> class,
30  * which can be overridden and replaced. The iterators can similarly be replaced,
31  * without the need to replace the KeySet, EntrySet and Values view classes.
32  * <p/>
33  * Overridable methods are provided to change the default hashing behaviour, and
34  * to change how entries are added to and removed from the map. Hopefully, all you
35  * need for unusual subclasses is here.
36  * <p/>
37  * NOTE: From Commons Collections 3.1 this class extends AbstractMap.
38  * This is to provide backwards compatibility for ReferenceMap between v3.0 and v3.1.
39  * This extends clause will be removed in v4.0.
40  *
41  * @author java util HashMap
42  * @author Matt Hall, John Watkinson, Stephen Colebourne
43  * @version $Revision: 1.1 $ $Date: 2005/10/11 17:05:32 $
44  * @since Commons Collections 3.0
45  */
46 public class AbstractHashedMap <K,V> extends AbstractMap<K, V> implements IterableMap<K, V> {
47 
48     protected static final String NO_NEXT_ENTRY = "No next() entry in the iteration";
49     protected static final String NO_PREVIOUS_ENTRY = "No previous() entry in the iteration";
50     protected static final String REMOVE_INVALID = "remove() can only be called once after next()";
51     protected static final String GETKEY_INVALID = "getKey() can only be called after next() and before remove()";
52     protected static final String GETVALUE_INVALID = "getValue() can only be called after next() and before remove()";
53     protected static final String SETVALUE_INVALID = "setValue() can only be called after next() and before remove()";
54 
55     /**
56      * The default capacity to use
57      */
58     protected static final int DEFAULT_CAPACITY = 16;
59     /**
60      * The default threshold to use
61      */
62     protected static final int DEFAULT_THRESHOLD = 12;
63     /**
64      * The default load factor to use
65      */
66     protected static final float DEFAULT_LOAD_FACTOR = 0.75f;
67     /**
68      * The maximum capacity allowed
69      */
70     protected static final int MAXIMUM_CAPACITY = 1 << 30;
71     /**
72      * An object for masking null
73      */
74     protected static final Object NULL = new Object();
75 
76     /**
77      * Load factor, normally 0.75
78      */
79     protected transient float loadFactor;
80     /**
81      * The size of the map
82      */
83     protected transient int size;
84     /**
85      * Map entries
86      */
87     protected transient HashEntry<K, V>[] data;
88     /**
89      * Size at which to rehash
90      */
91     protected transient int threshold;
92     /**
93      * Modification count for iterators
94      */
95     protected transient int modCount;
96     /**
97      * Entry set
98      */
99     protected transient EntrySet<K, V> entrySet;
100     /**
101      * Key set
102      */
103     protected transient KeySet<K, V> keySet;
104     /**
105      * Values
106      */
107     protected transient Values<K, V> values;
108 
109     /**
110      * Constructor only used in deserialization, do not use otherwise.
111      */
AbstractHashedMap()112     protected AbstractHashedMap() {
113         super();
114     }
115 
116     /**
117      * Constructor which performs no validation on the passed in parameters.
118      *
119      * @param initialCapacity the initial capacity, must be a power of two
120      * @param loadFactor      the load factor, must be &gt; 0.0f and generally &lt; 1.0f
121      * @param threshold       the threshold, must be sensible
122      */
AbstractHashedMap(int initialCapacity, float loadFactor, int threshold)123     protected AbstractHashedMap(int initialCapacity, float loadFactor, int threshold) {
124         super();
125         this.loadFactor = loadFactor;
126         this.data = new HashEntry[initialCapacity];
127         this.threshold = threshold;
128         init();
129     }
130 
131     /**
132      * Constructs a new, empty map with the specified initial capacity and
133      * default load factor.
134      *
135      * @param initialCapacity the initial capacity
136      * @throws IllegalArgumentException if the initial capacity is less than one
137      */
AbstractHashedMap(int initialCapacity)138     protected AbstractHashedMap(int initialCapacity) {
139         this(initialCapacity, DEFAULT_LOAD_FACTOR);
140     }
141 
142     /**
143      * Constructs a new, empty map with the specified initial capacity and
144      * load factor.
145      *
146      * @param initialCapacity the initial capacity
147      * @param loadFactor      the load factor
148      * @throws IllegalArgumentException if the initial capacity is less than one
149      * @throws IllegalArgumentException if the load factor is less than or equal to zero
150      */
AbstractHashedMap(int initialCapacity, float loadFactor)151     protected AbstractHashedMap(int initialCapacity, float loadFactor) {
152         super();
153         if (initialCapacity < 1) {
154             throw new IllegalArgumentException("Initial capacity must be greater than 0");
155         }
156         if (loadFactor <= 0.0f || Float.isNaN(loadFactor)) {
157             throw new IllegalArgumentException("Load factor must be greater than 0");
158         }
159         this.loadFactor = loadFactor;
160         this.threshold = calculateThreshold(initialCapacity, loadFactor);
161         initialCapacity = calculateNewCapacity(initialCapacity);
162         this.data = new HashEntry[initialCapacity];
163         init();
164     }
165 
166     /**
167      * Constructor copying elements from another map.
168      *
169      * @param map the map to copy
170      * @throws NullPointerException if the map is null
171      */
AbstractHashedMap(Map<? extends K, ? extends V> map)172     protected AbstractHashedMap(Map<? extends K, ? extends V> map) {
173         this(Math.max(2 * map.size(), DEFAULT_CAPACITY), DEFAULT_LOAD_FACTOR);
174         putAll(map);
175     }
176 
177     /**
178      * Initialise subclasses during construction, cloning or deserialization.
179      */
init()180     protected void init() {
181     }
182 
183     //-----------------------------------------------------------------------
184     /**
185      * Gets the value mapped to the key specified.
186      *
187      * @param key the key
188      * @return the mapped value, null if no match
189      */
get(Object key)190     public V get(Object key) {
191         int hashCode = hash((key == null) ? NULL : key);
192         HashEntry<K, V> entry = data[hashIndex(hashCode, data.length)]; // no local for hash index
193         while (entry != null) {
194             if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) {
195                 return entry.getValue();
196             }
197             entry = entry.next;
198         }
199         return null;
200     }
201 
202     /**
203      * Gets the size of the map.
204      *
205      * @return the size
206      */
size()207     public int size() {
208         return size;
209     }
210 
211     /**
212      * Checks whether the map is currently empty.
213      *
214      * @return true if the map is currently size zero
215      */
isEmpty()216     public boolean isEmpty() {
217         return (size == 0);
218     }
219 
220     //-----------------------------------------------------------------------
221     /**
222      * Checks whether the map contains the specified key.
223      *
224      * @param key the key to search for
225      * @return true if the map contains the key
226      */
containsKey(Object key)227     public boolean containsKey(Object key) {
228         int hashCode = hash((key == null) ? NULL : key);
229         HashEntry entry = data[hashIndex(hashCode, data.length)]; // no local for hash index
230         while (entry != null) {
231             if (entry.hashCode == hashCode && isEqualKey(key, entry.getKey())) {
232                 return true;
233             }
234             entry = entry.next;
235         }
236         return false;
237     }
238 
239     /**
240      * Checks whether the map contains the specified value.
241      *
242      * @param value the value to search for
243      * @return true if the map contains the value
244      */
containsValue(Object value)245     public boolean containsValue(Object value) {
246         if (value == null) {
247             for (int i = 0, isize = data.length; i < isize; i++) {
248                 HashEntry entry = data[i];
249                 while (entry != null) {
250                     if (entry.getValue() == null) {
251                         return true;
252                     }
253                     entry = entry.next;
254                 }
255             }
256         } else {
257             for (int i = 0, isize = data.length; i < isize; i++) {
258                 HashEntry entry = data[i];
259                 while (entry != null) {
260                     if (isEqualValue(value, entry.getValue())) {
261                         return true;
262                     }
263                     entry = entry.next;
264                 }
265             }
266         }
267         return false;
268     }
269 
270     //-----------------------------------------------------------------------
271     /**
272      * Puts a key-value mapping into this map.
273      *
274      * @param key   the key to add
275      * @param value the value to add
276      * @return the value previously mapped to this key, null if none
277      */
put(K key, V value)278     public V put(K key, V value) {
279         int hashCode = hash((key == null) ? NULL : key);
280         int index = hashIndex(hashCode, data.length);
281         HashEntry<K, V> entry = data[index];
282         while (entry != null) {
283             if (entry.hashCode == hashCode && isEqualKey(key, entry.getKey())) {
284                 V oldValue = entry.getValue();
285                 updateEntry(entry, value);
286                 return oldValue;
287             }
288             entry = entry.next;
289         }
290         addMapping(index, hashCode, key, value);
291         return null;
292     }
293 
294     /**
295      * Puts all the values from the specified map into this map.
296      * <p/>
297      * This implementation iterates around the specified map and
298      * uses {@link #put(Object, Object)}.
299      *
300      * @param map the map to add
301      * @throws NullPointerException if the map is null
302      */
putAll(Map<? extends K, ? extends V> map)303     public void putAll(Map<? extends K, ? extends V> map) {
304         int mapSize = map.size();
305         if (mapSize == 0) {
306             return;
307         }
308         int newSize = (int) ((size + mapSize) / loadFactor + 1);
309         ensureCapacity(calculateNewCapacity(newSize));
310         // Have to cast here because of compiler inference problems.
311         for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
312             Map.Entry<? extends K, ? extends V> entry = (Map.Entry<? extends K, ? extends V>) it.next();
313             put(entry.getKey(), entry.getValue());
314         }
315     }
316 
317     /**
318      * Removes the specified mapping from this map.
319      *
320      * @param key the mapping to remove
321      * @return the value mapped to the removed key, null if key not in map
322      */
remove(Object key)323     public V remove(Object key) {
324         int hashCode = hash((key == null) ? NULL : key);
325         int index = hashIndex(hashCode, data.length);
326         HashEntry<K, V> entry = data[index];
327         HashEntry<K, V> previous = null;
328         while (entry != null) {
329             if (entry.hashCode == hashCode && isEqualKey(key, entry.getKey())) {
330                 V oldValue = entry.getValue();
331                 removeMapping(entry, index, previous);
332                 return oldValue;
333             }
334             previous = entry;
335             entry = entry.next;
336         }
337         return null;
338     }
339 
340     /**
341      * Clears the map, resetting the size to zero and nullifying references
342      * to avoid garbage collection issues.
343      */
clear()344     public void clear() {
345         modCount++;
346         HashEntry[] data = this.data;
347         for (int i = data.length - 1; i >= 0; i--) {
348             data[i] = null;
349         }
350         size = 0;
351     }
352 
353     /**
354      * Gets the hash code for the key specified.
355      * This implementation uses the additional hashing routine from JDK1.4.
356      * Subclasses can override this to return alternate hash codes.
357      *
358      * @param key the key to get a hash code for
359      * @return the hash code
360      */
hash(Object key)361     protected int hash(Object key) {
362         // same as JDK 1.4
363         int h = key.hashCode();
364         h += ~(h << 9);
365         h ^= (h >>> 14);
366         h += (h << 4);
367         h ^= (h >>> 10);
368         return h;
369     }
370 
371     /**
372      * Compares two keys, in internal converted form, to see if they are equal.
373      * This implementation uses the equals method.
374      * Subclasses can override this to match differently.
375      *
376      * @param key1 the first key to compare passed in from outside
377      * @param key2 the second key extracted from the entry via <code>entry.key</code>
378      * @return true if equal
379      */
isEqualKey(Object key1, Object key2)380     protected boolean isEqualKey(Object key1, Object key2) {
381         return (key1 == key2 || ((key1 != null) && key1.equals(key2)));
382     }
383 
384     /**
385      * Compares two values, in external form, to see if they are equal.
386      * This implementation uses the equals method and assumes neither value is null.
387      * Subclasses can override this to match differently.
388      *
389      * @param value1 the first value to compare passed in from outside
390      * @param value2 the second value extracted from the entry via <code>getValue()</code>
391      * @return true if equal
392      */
isEqualValue(Object value1, Object value2)393     protected boolean isEqualValue(Object value1, Object value2) {
394         return (value1 == value2 || value1.equals(value2));
395     }
396 
397     /**
398      * Gets the index into the data storage for the hashCode specified.
399      * This implementation uses the least significant bits of the hashCode.
400      * Subclasses can override this to return alternate bucketing.
401      *
402      * @param hashCode the hash code to use
403      * @param dataSize the size of the data to pick a bucket from
404      * @return the bucket index
405      */
hashIndex(int hashCode, int dataSize)406     protected int hashIndex(int hashCode, int dataSize) {
407         return hashCode & (dataSize - 1);
408     }
409 
410     //-----------------------------------------------------------------------
411     /**
412      * Gets the entry mapped to the key specified.
413      * <p/>
414      * This method exists for subclasses that may need to perform a multi-step
415      * process accessing the entry. The public methods in this class don't use this
416      * method to gain a small performance boost.
417      *
418      * @param key the key
419      * @return the entry, null if no match
420      */
getEntry(Object key)421     protected HashEntry<K, V> getEntry(Object key) {
422         int hashCode = hash((key == null) ? NULL : key);
423         HashEntry<K, V> entry = data[hashIndex(hashCode, data.length)]; // no local for hash index
424         while (entry != null) {
425             if (entry.hashCode == hashCode && isEqualKey(key, entry.getKey())) {
426                 return entry;
427             }
428             entry = entry.next;
429         }
430         return null;
431     }
432 
433     //-----------------------------------------------------------------------
434     /**
435      * Updates an existing key-value mapping to change the value.
436      * <p/>
437      * This implementation calls <code>setValue()</code> on the entry.
438      * Subclasses could override to handle changes to the map.
439      *
440      * @param entry    the entry to update
441      * @param newValue the new value to store
442      */
updateEntry(HashEntry<K, V> entry, V newValue)443     protected void updateEntry(HashEntry<K, V> entry, V newValue) {
444         entry.setValue(newValue);
445     }
446 
447     /**
448      * Reuses an existing key-value mapping, storing completely new data.
449      * <p/>
450      * This implementation sets all the data fields on the entry.
451      * Subclasses could populate additional entry fields.
452      *
453      * @param entry     the entry to update, not null
454      * @param hashIndex the index in the data array
455      * @param hashCode  the hash code of the key to add
456      * @param key       the key to add
457      * @param value     the value to add
458      */
reuseEntry(HashEntry<K, V> entry, int hashIndex, int hashCode, K key, V value)459     protected void reuseEntry(HashEntry<K, V> entry, int hashIndex, int hashCode, K key, V value) {
460         entry.next = data[hashIndex];
461         entry.hashCode = hashCode;
462         entry.key = key;
463         entry.value = value;
464     }
465 
466     //-----------------------------------------------------------------------
467     /**
468      * Adds a new key-value mapping into this map.
469      * <p/>
470      * This implementation calls <code>createEntry()</code>, <code>addEntry()</code>
471      * and <code>checkCapacity()</code>.
472      * It also handles changes to <code>modCount</code> and <code>size</code>.
473      * Subclasses could override to fully control adds to the map.
474      *
475      * @param hashIndex the index into the data array to store at
476      * @param hashCode  the hash code of the key to add
477      * @param key       the key to add
478      * @param value     the value to add
479      */
addMapping(int hashIndex, int hashCode, K key, V value)480     protected void addMapping(int hashIndex, int hashCode, K key, V value) {
481         modCount++;
482         HashEntry<K, V> entry = createEntry(data[hashIndex], hashCode, key, value);
483         addEntry(entry, hashIndex);
484         size++;
485         checkCapacity();
486     }
487 
488     /**
489      * Creates an entry to store the key-value data.
490      * <p/>
491      * This implementation creates a new HashEntry instance.
492      * Subclasses can override this to return a different storage class,
493      * or implement caching.
494      *
495      * @param next     the next entry in sequence
496      * @param hashCode the hash code to use
497      * @param key      the key to store
498      * @param value    the value to store
499      * @return the newly created entry
500      */
createEntry(HashEntry<K, V> next, int hashCode, K key, V value)501     protected HashEntry<K, V> createEntry(HashEntry<K, V> next, int hashCode, K key, V value) {
502         return new HashEntry<K, V>(next, hashCode, key, value);
503     }
504 
505     /**
506      * Adds an entry into this map.
507      * <p/>
508      * This implementation adds the entry to the data storage table.
509      * Subclasses could override to handle changes to the map.
510      *
511      * @param entry     the entry to add
512      * @param hashIndex the index into the data array to store at
513      */
addEntry(HashEntry<K, V> entry, int hashIndex)514     protected void addEntry(HashEntry<K, V> entry, int hashIndex) {
515         data[hashIndex] = entry;
516     }
517 
518     //-----------------------------------------------------------------------
519     /**
520      * Removes a mapping from the map.
521      * <p/>
522      * This implementation calls <code>removeEntry()</code> and <code>destroyEntry()</code>.
523      * It also handles changes to <code>modCount</code> and <code>size</code>.
524      * Subclasses could override to fully control removals from the map.
525      *
526      * @param entry     the entry to remove
527      * @param hashIndex the index into the data structure
528      * @param previous  the previous entry in the chain
529      */
removeMapping(HashEntry<K, V> entry, int hashIndex, HashEntry<K, V> previous)530     protected void removeMapping(HashEntry<K, V> entry, int hashIndex, HashEntry<K, V> previous) {
531         modCount++;
532         removeEntry(entry, hashIndex, previous);
533         size--;
534         destroyEntry(entry);
535     }
536 
537     /**
538      * Removes an entry from the chain stored in a particular index.
539      * <p/>
540      * This implementation removes the entry from the data storage table.
541      * The size is not updated.
542      * Subclasses could override to handle changes to the map.
543      *
544      * @param entry     the entry to remove
545      * @param hashIndex the index into the data structure
546      * @param previous  the previous entry in the chain
547      */
removeEntry(HashEntry<K, V> entry, int hashIndex, HashEntry<K, V> previous)548     protected void removeEntry(HashEntry<K, V> entry, int hashIndex, HashEntry<K, V> previous) {
549         if (previous == null) {
550             data[hashIndex] = entry.next;
551         } else {
552             previous.next = entry.next;
553         }
554     }
555 
556     /**
557      * Kills an entry ready for the garbage collector.
558      * <p/>
559      * This implementation prepares the HashEntry for garbage collection.
560      * Subclasses can override this to implement caching (override clear as well).
561      *
562      * @param entry the entry to destroy
563      */
destroyEntry(HashEntry<K, V> entry)564     protected void destroyEntry(HashEntry<K, V> entry) {
565         entry.next = null;
566         entry.key = null;
567         entry.value = null;
568     }
569 
570     //-----------------------------------------------------------------------
571     /**
572      * Checks the capacity of the map and enlarges it if necessary.
573      * <p/>
574      * This implementation uses the threshold to check if the map needs enlarging
575      */
checkCapacity()576     protected void checkCapacity() {
577         if (size >= threshold) {
578             int newCapacity = data.length * 2;
579             if (newCapacity <= MAXIMUM_CAPACITY) {
580                 ensureCapacity(newCapacity);
581             }
582         }
583     }
584 
585     /**
586      * Changes the size of the data structure to the capacity proposed.
587      *
588      * @param newCapacity the new capacity of the array (a power of two, less or equal to max)
589      */
ensureCapacity(int newCapacity)590     protected void ensureCapacity(int newCapacity) {
591         int oldCapacity = data.length;
592         if (newCapacity <= oldCapacity) {
593             return;
594         }
595         if (size == 0) {
596             threshold = calculateThreshold(newCapacity, loadFactor);
597             data = new HashEntry[newCapacity];
598         } else {
599             HashEntry<K, V> oldEntries[] = data;
600             HashEntry<K, V> newEntries[] = new HashEntry[newCapacity];
601 
602             modCount++;
603             for (int i = oldCapacity - 1; i >= 0; i--) {
604                 HashEntry<K, V> entry = oldEntries[i];
605                 if (entry != null) {
606                     oldEntries[i] = null;  // gc
607                     do {
608                         HashEntry<K, V> next = entry.next;
609                         int index = hashIndex(entry.hashCode, newCapacity);
610                         entry.next = newEntries[index];
611                         newEntries[index] = entry;
612                         entry = next;
613                     } while (entry != null);
614                 }
615             }
616             threshold = calculateThreshold(newCapacity, loadFactor);
617             data = newEntries;
618         }
619     }
620 
621     /**
622      * Calculates the new capacity of the map.
623      * This implementation normalizes the capacity to a power of two.
624      *
625      * @param proposedCapacity the proposed capacity
626      * @return the normalized new capacity
627      */
calculateNewCapacity(int proposedCapacity)628     protected int calculateNewCapacity(int proposedCapacity) {
629         int newCapacity = 1;
630         if (proposedCapacity > MAXIMUM_CAPACITY) {
631             newCapacity = MAXIMUM_CAPACITY;
632         } else {
633             while (newCapacity < proposedCapacity) {
634                 newCapacity <<= 1;  // multiply by two
635             }
636             if (newCapacity > MAXIMUM_CAPACITY) {
637                 newCapacity = MAXIMUM_CAPACITY;
638             }
639         }
640         return newCapacity;
641     }
642 
643     /**
644      * Calculates the new threshold of the map, where it will be resized.
645      * This implementation uses the load factor.
646      *
647      * @param newCapacity the new capacity
648      * @param factor      the load factor
649      * @return the new resize threshold
650      */
calculateThreshold(int newCapacity, float factor)651     protected int calculateThreshold(int newCapacity, float factor) {
652         return (int) (newCapacity * factor);
653     }
654 
655     //-----------------------------------------------------------------------
656     /**
657      * Gets the <code>next</code> field from a <code>HashEntry</code>.
658      * Used in subclasses that have no visibility of the field.
659      *
660      * @param entry the entry to query, must not be null
661      * @return the <code>next</code> field of the entry
662      * @throws NullPointerException if the entry is null
663      * @since Commons Collections 3.1
664      */
entryNext(HashEntry<K, V> entry)665     protected HashEntry<K, V> entryNext(HashEntry<K, V> entry) {
666         return entry.next;
667     }
668 
669     /**
670      * Gets the <code>hashCode</code> field from a <code>HashEntry</code>.
671      * Used in subclasses that have no visibility of the field.
672      *
673      * @param entry the entry to query, must not be null
674      * @return the <code>hashCode</code> field of the entry
675      * @throws NullPointerException if the entry is null
676      * @since Commons Collections 3.1
677      */
entryHashCode(HashEntry<K, V> entry)678     protected int entryHashCode(HashEntry<K, V> entry) {
679         return entry.hashCode;
680     }
681 
682     /**
683      * Gets the <code>key</code> field from a <code>HashEntry</code>.
684      * Used in subclasses that have no visibility of the field.
685      *
686      * @param entry the entry to query, must not be null
687      * @return the <code>key</code> field of the entry
688      * @throws NullPointerException if the entry is null
689      * @since Commons Collections 3.1
690      */
entryKey(HashEntry<K, V> entry)691     protected K entryKey(HashEntry<K, V> entry) {
692         return entry.key;
693     }
694 
695     /**
696      * Gets the <code>value</code> field from a <code>HashEntry</code>.
697      * Used in subclasses that have no visibility of the field.
698      *
699      * @param entry the entry to query, must not be null
700      * @return the <code>value</code> field of the entry
701      * @throws NullPointerException if the entry is null
702      * @since Commons Collections 3.1
703      */
entryValue(HashEntry<K, V> entry)704     protected V entryValue(HashEntry<K, V> entry) {
705         return entry.value;
706     }
707 
708     //-----------------------------------------------------------------------
709     /**
710      * Gets an iterator over the map.
711      * Changes made to the iterator affect this map.
712      * <p/>
713      * A MapIterator returns the keys in the map. It also provides convenient
714      * methods to get the key and value, and set the value.
715      * It avoids the need to create an entrySet/keySet/values object.
716      * It also avoids creating the Map.Entry object.
717      *
718      * @return the map iterator
719      */
mapIterator()720     public MapIterator<K, V> mapIterator() {
721         if (size == 0) {
722             return EmptyMapIterator.INSTANCE;
723         }
724         return new HashMapIterator<K, V>(this);
725     }
726 
727     /**
728      * MapIterator implementation.
729      */
730     protected static class HashMapIterator <K,V> extends HashIterator<K, V> implements MapIterator<K, V> {
731 
HashMapIterator(AbstractHashedMap<K, V> parent)732         protected HashMapIterator(AbstractHashedMap<K, V> parent) {
733             super(parent);
734         }
735 
next()736         public K next() {
737             return super.nextEntry().getKey();
738         }
739 
getKey()740         public K getKey() {
741             HashEntry<K, V> current = currentEntry();
742             if (current == null) {
743                 throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
744             }
745             return current.getKey();
746         }
747 
getValue()748         public V getValue() {
749             HashEntry<K, V> current = currentEntry();
750             if (current == null) {
751                 throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
752             }
753             return current.getValue();
754         }
755 
setValue(V value)756         public V setValue(V value) {
757             HashEntry<K, V> current = currentEntry();
758             if (current == null) {
759                 throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
760             }
761             return current.setValue(value);
762         }
763     }
764 
765     //-----------------------------------------------------------------------
766     /**
767      * Gets the entrySet view of the map.
768      * Changes made to the view affect this map.
769      * To simply iterate through the entries, use {@link #mapIterator()}.
770      *
771      * @return the entrySet view
772      */
entrySet()773     public Set<Map.Entry<K, V>> entrySet() {
774         if (entrySet == null) {
775             entrySet = new EntrySet<K, V>(this);
776         }
777         return entrySet;
778     }
779 
780     /**
781      * Creates an entry set iterator.
782      * Subclasses can override this to return iterators with different properties.
783      *
784      * @return the entrySet iterator
785      */
createEntrySetIterator()786     protected Iterator<Map.Entry<K, V>> createEntrySetIterator() {
787         if (size() == 0) {
788             return EmptyIterator.INSTANCE;
789         }
790         return new EntrySetIterator<K, V>(this);
791     }
792 
793     /**
794      * EntrySet implementation.
795      */
796     protected static class EntrySet <K,V> extends AbstractSet<Map.Entry<K, V>> {
797         /**
798          * The parent map
799          */
800         protected final AbstractHashedMap<K, V> parent;
801 
EntrySet(AbstractHashedMap<K, V> parent)802         protected EntrySet(AbstractHashedMap<K, V> parent) {
803             super();
804             this.parent = parent;
805         }
806 
size()807         public int size() {
808             return parent.size();
809         }
810 
clear()811         public void clear() {
812             parent.clear();
813         }
814 
contains(Map.Entry<K, V> entry)815         public boolean contains(Map.Entry<K, V> entry) {
816             Map.Entry<K, V> e = entry;
817             Entry<K, V> match = parent.getEntry(e.getKey());
818             return (match != null && match.equals(e));
819         }
820 
remove(Object obj)821         public boolean remove(Object obj) {
822             if (obj instanceof Map.Entry == false) {
823                 return false;
824             }
825             if (contains(obj) == false) {
826                 return false;
827             }
828             Map.Entry<K, V> entry = (Map.Entry<K, V>) obj;
829             K key = entry.getKey();
830             parent.remove(key);
831             return true;
832         }
833 
iterator()834         public Iterator<Map.Entry<K, V>> iterator() {
835             return parent.createEntrySetIterator();
836         }
837     }
838 
839     /**
840      * EntrySet iterator.
841      */
842     protected static class EntrySetIterator <K,V> extends HashIterator<K, V> implements Iterator<Map.Entry<K, V>> {
843 
EntrySetIterator(AbstractHashedMap<K, V> parent)844         protected EntrySetIterator(AbstractHashedMap<K, V> parent) {
845             super(parent);
846         }
847 
next()848         public HashEntry<K, V> next() {
849             return super.nextEntry();
850         }
851     }
852 
853     //-----------------------------------------------------------------------
854     /**
855      * Gets the keySet view of the map.
856      * Changes made to the view affect this map.
857      * To simply iterate through the keys, use {@link #mapIterator()}.
858      *
859      * @return the keySet view
860      */
keySet()861     public Set<K> keySet() {
862         if (keySet == null) {
863             keySet = new KeySet<K, V>(this);
864         }
865         return keySet;
866     }
867 
868     /**
869      * Creates a key set iterator.
870      * Subclasses can override this to return iterators with different properties.
871      *
872      * @return the keySet iterator
873      */
createKeySetIterator()874     protected Iterator<K> createKeySetIterator() {
875         if (size() == 0) {
876             return EmptyIterator.INSTANCE;
877         }
878         return new KeySetIterator<K, V>(this);
879     }
880 
881     /**
882      * KeySet implementation.
883      */
884     protected static class KeySet <K,V> extends AbstractSet<K> {
885         /**
886          * The parent map
887          */
888         protected final AbstractHashedMap<K, V> parent;
889 
KeySet(AbstractHashedMap<K, V> parent)890         protected KeySet(AbstractHashedMap<K, V> parent) {
891             super();
892             this.parent = parent;
893         }
894 
size()895         public int size() {
896             return parent.size();
897         }
898 
clear()899         public void clear() {
900             parent.clear();
901         }
902 
contains(Object key)903         public boolean contains(Object key) {
904             return parent.containsKey(key);
905         }
906 
remove(Object key)907         public boolean remove(Object key) {
908             boolean result = parent.containsKey(key);
909             parent.remove(key);
910             return result;
911         }
912 
iterator()913         public Iterator<K> iterator() {
914             return parent.createKeySetIterator();
915         }
916     }
917 
918     /**
919      * KeySet iterator.
920      */
921     protected static class KeySetIterator <K,V> extends HashIterator<K, V> implements Iterator<K> {
922 
KeySetIterator(AbstractHashedMap<K, V> parent)923         protected KeySetIterator(AbstractHashedMap<K, V> parent) {
924             super(parent);
925         }
926 
next()927         public K next() {
928             return super.nextEntry().getKey();
929         }
930     }
931 
932     //-----------------------------------------------------------------------
933     /**
934      * Gets the values view of the map.
935      * Changes made to the view affect this map.
936      * To simply iterate through the values, use {@link #mapIterator()}.
937      *
938      * @return the values view
939      */
values()940     public Collection<V> values() {
941         if (values == null) {
942             values = new Values(this);
943         }
944         return values;
945     }
946 
947     /**
948      * Creates a values iterator.
949      * Subclasses can override this to return iterators with different properties.
950      *
951      * @return the values iterator
952      */
createValuesIterator()953     protected Iterator<V> createValuesIterator() {
954         if (size() == 0) {
955             return EmptyIterator.INSTANCE;
956         }
957         return new ValuesIterator<K, V>(this);
958     }
959 
960     /**
961      * Values implementation.
962      */
963     protected static class Values <K,V> extends AbstractCollection<V> {
964         /**
965          * The parent map
966          */
967         protected final AbstractHashedMap<K, V> parent;
968 
Values(AbstractHashedMap<K, V> parent)969         protected Values(AbstractHashedMap<K, V> parent) {
970             super();
971             this.parent = parent;
972         }
973 
size()974         public int size() {
975             return parent.size();
976         }
977 
clear()978         public void clear() {
979             parent.clear();
980         }
981 
contains(Object value)982         public boolean contains(Object value) {
983             return parent.containsValue(value);
984         }
985 
iterator()986         public Iterator<V> iterator() {
987             return parent.createValuesIterator();
988         }
989     }
990 
991     /**
992      * Values iterator.
993      */
994     protected static class ValuesIterator <K,V> extends HashIterator<K, V> implements Iterator<V> {
995 
ValuesIterator(AbstractHashedMap<K, V> parent)996         protected ValuesIterator(AbstractHashedMap<K, V> parent) {
997             super(parent);
998         }
999 
next()1000         public V next() {
1001             return super.nextEntry().getValue();
1002         }
1003     }
1004 
1005     //-----------------------------------------------------------------------
1006     /**
1007      * HashEntry used to store the data.
1008      * <p/>
1009      * If you subclass <code>AbstractHashedMap</code> but not <code>HashEntry</code>
1010      * then you will not be able to access the protected fields.
1011      * The <code>entryXxx()</code> methods on <code>AbstractHashedMap</code> exist
1012      * to provide the necessary access.
1013      */
1014     protected static class HashEntry <K,V> implements Map.Entry<K, V>, KeyValue<K, V> {
1015         /**
1016          * The next entry in the hash chain
1017          */
1018         protected HashEntry<K, V> next;
1019         /**
1020          * The hash code of the key
1021          */
1022         protected int hashCode;
1023         /**
1024          * The key
1025          */
1026         private K key;
1027         /**
1028          * The value
1029          */
1030         private V value;
1031 
HashEntry(HashEntry<K, V> next, int hashCode, K key, V value)1032         protected HashEntry(HashEntry<K, V> next, int hashCode, K key, V value) {
1033             super();
1034             this.next = next;
1035             this.hashCode = hashCode;
1036             this.key = key;
1037             this.value = value;
1038         }
1039 
getKey()1040         public K getKey() {
1041             return key;
1042         }
1043 
setKey(K key)1044         public void setKey(K key) {
1045             this.key = key;
1046         }
1047 
getValue()1048         public V getValue() {
1049             return value;
1050         }
1051 
setValue(V value)1052         public V setValue(V value) {
1053             V old = this.value;
1054             this.value = value;
1055             return old;
1056         }
1057 
equals(Object obj)1058         public boolean equals(Object obj) {
1059             if (obj == this) {
1060                 return true;
1061             }
1062             if (obj instanceof Map.Entry == false) {
1063                 return false;
1064             }
1065             Map.Entry other = (Map.Entry) obj;
1066             return (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) && (getValue() == null ? other.getValue() == null : getValue().equals(other.getValue()));
1067         }
1068 
hashCode()1069         public int hashCode() {
1070             return (getKey() == null ? 0 : getKey().hashCode()) ^ (getValue() == null ? 0 : getValue().hashCode());
1071         }
1072 
toString()1073         public String toString() {
1074             return new StringBuilder().append(getKey()).append('=').append(getValue()).toString();
1075         }
1076     }
1077 
1078     /**
1079      * Base Iterator
1080      */
1081     protected static abstract class HashIterator <K,V> {
1082 
1083         /**
1084          * The parent map
1085          */
1086         protected final AbstractHashedMap parent;
1087         /**
1088          * The current index into the array of buckets
1089          */
1090         protected int hashIndex;
1091         /**
1092          * The last returned entry
1093          */
1094         protected HashEntry<K, V> last;
1095         /**
1096          * The next entry
1097          */
1098         protected HashEntry<K, V> next;
1099         /**
1100          * The modification count expected
1101          */
1102         protected int expectedModCount;
1103 
HashIterator(AbstractHashedMap<K, V> parent)1104         protected HashIterator(AbstractHashedMap<K, V> parent) {
1105             super();
1106             this.parent = parent;
1107             HashEntry<K, V>[] data = parent.data;
1108             int i = data.length;
1109             HashEntry<K, V> next = null;
1110             while (i > 0 && next == null) {
1111                 next = data[--i];
1112             }
1113             this.next = next;
1114             this.hashIndex = i;
1115             this.expectedModCount = parent.modCount;
1116         }
1117 
hasNext()1118         public boolean hasNext() {
1119             return (next != null);
1120         }
1121 
nextEntry()1122         protected HashEntry<K, V> nextEntry() {
1123             if (parent.modCount != expectedModCount) {
1124                 throw new ConcurrentModificationException();
1125             }
1126             HashEntry<K, V> newCurrent = next;
1127             if (newCurrent == null) {
1128                 throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
1129             }
1130             HashEntry<K, V>[] data = parent.data;
1131             int i = hashIndex;
1132             HashEntry<K, V> n = newCurrent.next;
1133             while (n == null && i > 0) {
1134                 n = data[--i];
1135             }
1136             next = n;
1137             hashIndex = i;
1138             last = newCurrent;
1139             return newCurrent;
1140         }
1141 
currentEntry()1142         protected HashEntry<K, V> currentEntry() {
1143             return last;
1144         }
1145 
remove()1146         public void remove() {
1147             if (last == null) {
1148                 throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID);
1149             }
1150             if (parent.modCount != expectedModCount) {
1151                 throw new ConcurrentModificationException();
1152             }
1153             parent.remove(last.getKey());
1154             last = null;
1155             expectedModCount = parent.modCount;
1156         }
1157 
toString()1158         public String toString() {
1159             if (last != null) {
1160                 return "Iterator[" + last.getKey() + "=" + last.getValue() + "]";
1161             } else {
1162                 return "Iterator[]";
1163             }
1164         }
1165     }
1166 
1167     //-----------------------------------------------------------------------
1168     /**
1169      * Writes the map data to the stream. This method must be overridden if a
1170      * subclass must be setup before <code>put()</code> is used.
1171      * <p/>
1172      * Serialization is not one of the JDK's nicest topics. Normal serialization will
1173      * initialise the superclass before the subclass. Sometimes however, this isn't
1174      * what you want, as in this case the <code>put()</code> method on read can be
1175      * affected by subclass state.
1176      * <p/>
1177      * The solution adopted here is to serialize the state data of this class in
1178      * this protected method. This method must be called by the
1179      * <code>writeObject()</code> of the first serializable subclass.
1180      * <p/>
1181      * Subclasses may override if they have a specific field that must be present
1182      * on read before this implementation will work. Generally, the read determines
1183      * what must be serialized here, if anything.
1184      *
1185      * @param out the output stream
1186      */
doWriteObject(ObjectOutputStream out)1187     protected void doWriteObject(ObjectOutputStream out) throws IOException {
1188         out.writeFloat(loadFactor);
1189         out.writeInt(data.length);
1190         out.writeInt(size);
1191         for (MapIterator it = mapIterator(); it.hasNext();) {
1192             out.writeObject(it.next());
1193             out.writeObject(it.getValue());
1194         }
1195     }
1196 
1197     /**
1198      * Reads the map data from the stream. This method must be overridden if a
1199      * subclass must be setup before <code>put()</code> is used.
1200      * <p/>
1201      * Serialization is not one of the JDK's nicest topics. Normal serialization will
1202      * initialise the superclass before the subclass. Sometimes however, this isn't
1203      * what you want, as in this case the <code>put()</code> method on read can be
1204      * affected by subclass state.
1205      * <p/>
1206      * The solution adopted here is to deserialize the state data of this class in
1207      * this protected method. This method must be called by the
1208      * <code>readObject()</code> of the first serializable subclass.
1209      * <p/>
1210      * Subclasses may override if the subclass has a specific field that must be present
1211      * before <code>put()</code> or <code>calculateThreshold()</code> will work correctly.
1212      *
1213      * @param in the input stream
1214      */
doReadObject(ObjectInputStream in)1215     protected void doReadObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
1216         loadFactor = in.readFloat();
1217         int capacity = in.readInt();
1218         int size = in.readInt();
1219         init();
1220         data = new HashEntry[capacity];
1221         for (int i = 0; i < size; i++) {
1222             K key = (K) in.readObject();
1223             V value = (V) in.readObject();
1224             put(key, value);
1225         }
1226         threshold = calculateThreshold(data.length, loadFactor);
1227     }
1228 
1229     //-----------------------------------------------------------------------
1230     /**
1231      * Clones the map without cloning the keys or values.
1232      * <p/>
1233      * To implement <code>clone()</code>, a subclass must implement the
1234      * <code>Cloneable</code> interface and make this method public.
1235      *
1236      * @return a shallow clone
1237      */
clone()1238     protected Object clone() {
1239         try {
1240             AbstractHashedMap cloned = (AbstractHashedMap) super.clone();
1241             cloned.data = new HashEntry[data.length];
1242             cloned.entrySet = null;
1243             cloned.keySet = null;
1244             cloned.values = null;
1245             cloned.modCount = 0;
1246             cloned.size = 0;
1247             cloned.init();
1248             cloned.putAll(this);
1249             return cloned;
1250 
1251         } catch (CloneNotSupportedException ex) {
1252             return null;  // should never happen
1253         }
1254     }
1255 
1256     /**
1257      * Compares this map with another.
1258      *
1259      * @param obj the object to compare to
1260      * @return true if equal
1261      */
equals(Object obj)1262     public boolean equals(Object obj) {
1263         if (obj == this) {
1264             return true;
1265         }
1266         if (obj instanceof Map == false) {
1267             return false;
1268         }
1269         Map map = (Map) obj;
1270         if (map.size() != size()) {
1271             return false;
1272         }
1273         MapIterator it = mapIterator();
1274         try {
1275             while (it.hasNext()) {
1276                 Object key = it.next();
1277                 Object value = it.getValue();
1278                 if (value == null) {
1279                     if (map.get(key) != null || map.containsKey(key) == false) {
1280                         return false;
1281                     }
1282                 } else {
1283                     if (value.equals(map.get(key)) == false) {
1284                         return false;
1285                     }
1286                 }
1287             }
1288         } catch (ClassCastException ignored) {
1289             return false;
1290         } catch (NullPointerException ignored) {
1291             return false;
1292         }
1293         return true;
1294     }
1295 
1296     /**
1297      * Gets the standard Map hashCode.
1298      *
1299      * @return the hash code defined in the Map interface
1300      */
hashCode()1301     public int hashCode() {
1302         int total = 0;
1303         Iterator it = createEntrySetIterator();
1304         while (it.hasNext()) {
1305             total += it.next().hashCode();
1306         }
1307         return total;
1308     }
1309 
1310     /**
1311      * Gets the map as a String.
1312      *
1313      * @return a string version of the map
1314      */
toString()1315     public String toString() {
1316         if (size() == 0) {
1317             return "{}";
1318         }
1319         StringBuilder buf = new StringBuilder(32 * size());
1320         buf.append('{');
1321 
1322         MapIterator it = mapIterator();
1323         boolean hasNext = it.hasNext();
1324         while (hasNext) {
1325             Object key = it.next();
1326             Object value = it.getValue();
1327             buf.append(key == this ? "(this Map)" : key).append('=').append(value == this ? "(this Map)" : value);
1328 
1329             hasNext = it.hasNext();
1330             if (hasNext) {
1331                 buf.append(',').append(' ');
1332             }
1333         }
1334 
1335         buf.append('}');
1336         return buf.toString();
1337     }
1338 }
1339