001/* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * https://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.commons.collections4.map; 018 019import java.io.IOException; 020import java.io.InvalidObjectException; 021import java.io.ObjectInputStream; 022import java.io.ObjectOutputStream; 023import java.util.AbstractCollection; 024import java.util.AbstractMap; 025import java.util.AbstractSet; 026import java.util.Arrays; 027import java.util.Collection; 028import java.util.ConcurrentModificationException; 029import java.util.Iterator; 030import java.util.Map; 031import java.util.NoSuchElementException; 032import java.util.Objects; 033import java.util.Set; 034 035import org.apache.commons.collections4.CollectionUtils; 036import org.apache.commons.collections4.IterableMap; 037import org.apache.commons.collections4.KeyValue; 038import org.apache.commons.collections4.MapIterator; 039import org.apache.commons.collections4.iterators.EmptyIterator; 040import org.apache.commons.collections4.iterators.EmptyMapIterator; 041 042/** 043 * An abstract implementation of a hash-based map which provides numerous points for 044 * subclasses to override. 045 * <p> 046 * This class implements all the features necessary for a subclass hash-based map. 047 * Key-value entries are stored in instances of the {@code HashEntry} class, 048 * which can be overridden and replaced. The iterators can similarly be replaced, 049 * without the need to replace the KeySet, EntrySet and Values view classes. 050 * </p> 051 * <p> 052 * Overridable methods are provided to change the default hashing behavior, and 053 * to change how entries are added to and removed from the map. Hopefully, all you 054 * need for unusual subclasses is here. 055 * </p> 056 * <p> 057 * NOTE: From Commons Collections 3.1 this class extends AbstractMap. 058 * This is to provide backwards compatibility for ReferenceMap between v3.0 and v3.1. 059 * This extends clause will be removed in v5.0. 060 * </p> 061 * 062 * @param <K> The type of the keys in this map 063 * @param <V> The type of the values in this map 064 * @since 3.0 065 */ 066public class AbstractHashedMap<K, V> extends AbstractMap<K, V> implements IterableMap<K, V> { 067 068 /** 069 * EntrySet implementation. 070 * 071 * @param <K> The type of the keys in the map 072 * @param <V> The type of the values in the map 073 */ 074 protected static class EntrySet<K, V> extends AbstractSet<Map.Entry<K, V>> { 075 076 /** The parent map */ 077 private final AbstractHashedMap<K, V> parent; 078 079 /** 080 * Constructs a new instance. 081 * 082 * @param parent The parent map. 083 */ 084 protected EntrySet(final AbstractHashedMap<K, V> parent) { 085 this.parent = parent; 086 } 087 088 @Override 089 public void clear() { 090 parent.clear(); 091 } 092 093 @Override 094 public boolean contains(final Object entry) { 095 if (entry instanceof Map.Entry) { 096 final Map.Entry<?, ?> e = (Map.Entry<?, ?>) entry; 097 final Entry<K, V> match = parent.getEntry(e.getKey()); 098 return match != null && match.equals(e); 099 } 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}