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