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