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