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