| 1 16 package org.apache.commons.collections.map; 17 18 import java.io.IOException ; 19 import java.io.ObjectInputStream ; 20 import java.io.ObjectOutputStream ; 21 import java.util.AbstractCollection ; 22 import java.util.AbstractMap ; 23 import java.util.AbstractSet ; 24 import java.util.Collection ; 25 import java.util.ConcurrentModificationException ; 26 import java.util.Iterator ; 27 import java.util.Map ; 28 import java.util.NoSuchElementException ; 29 import java.util.Set ; 30 31 import org.apache.commons.collections.IterableMap; 32 import org.apache.commons.collections.KeyValue; 33 import org.apache.commons.collections.MapIterator; 34 import org.apache.commons.collections.iterators.EmptyIterator; 35 import org.apache.commons.collections.iterators.EmptyMapIterator; 36 37 60 public class AbstractHashedMap extends AbstractMap implements IterableMap { 61 62 protected static final String NO_NEXT_ENTRY = "No next() entry in the iteration"; 63 protected static final String NO_PREVIOUS_ENTRY = "No previous() entry in the iteration"; 64 protected static final String REMOVE_INVALID = "remove() can only be called once after next()"; 65 protected static final String GETKEY_INVALID = "getKey() can only be called after next() and before remove()"; 66 protected static final String GETVALUE_INVALID = "getValue() can only be called after next() and before remove()"; 67 protected static final String SETVALUE_INVALID = "setValue() can only be called after next() and before remove()"; 68 69 70 protected static final int DEFAULT_CAPACITY = 16; 71 72 protected static final int DEFAULT_THRESHOLD = 12; 73 74 protected static final float DEFAULT_LOAD_FACTOR = 0.75f; 75 76 protected static final int MAXIMUM_CAPACITY = 1 << 30; 77 78 protected static final Object NULL = new Object (); 79 80 81 protected transient float loadFactor; 82 83 protected transient int size; 84 85 protected transient HashEntry[] data; 86 87 protected transient int threshold; 88 89 protected transient int modCount; 90 91 protected transient EntrySet entrySet; 92 93 protected transient KeySet keySet; 94 95 protected transient Values values; 96 97 100 protected AbstractHashedMap() { 101 super(); 102 } 103 104 111 protected AbstractHashedMap(int initialCapacity, float loadFactor, int threshold) { 112 super(); 113 this.loadFactor = loadFactor; 114 this.data = new HashEntry[initialCapacity]; 115 this.threshold = threshold; 116 init(); 117 } 118 119 126 protected AbstractHashedMap(int initialCapacity) { 127 this(initialCapacity, DEFAULT_LOAD_FACTOR); 128 } 129 130 139 protected AbstractHashedMap(int initialCapacity, float loadFactor) { 140 super(); 141 if (initialCapacity < 1) { 142 throw new IllegalArgumentException ("Initial capacity must be greater than 0"); 143 } 144 if (loadFactor <= 0.0f || Float.isNaN(loadFactor)) { 145 throw new IllegalArgumentException ("Load factor must be greater than 0"); 146 } 147 this.loadFactor = loadFactor; 148 this.threshold = calculateThreshold(initialCapacity, loadFactor); 149 initialCapacity = calculateNewCapacity(initialCapacity); 150 this.data = new HashEntry[initialCapacity]; 151 init(); 152 } 153 154 160 protected AbstractHashedMap(Map map) { 161 this(Math.max(2 * map.size(), DEFAULT_CAPACITY), DEFAULT_LOAD_FACTOR); 162 putAll(map); 163 } 164 165 168 protected void init() { 169 } 170 171 178 public Object get(Object key) { 179 key = convertKey(key); 180 int hashCode = hash(key); 181 HashEntry entry = data[hashIndex(hashCode, data.length)]; while (entry != null) { 183 if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) { 184 return entry.getValue(); 185 } 186 entry = entry.next; 187 } 188 return null; 189 } 190 191 196 public int size() { 197 return size; 198 } 199 200 205 public boolean isEmpty() { 206 return (size == 0); 207 } 208 209 216 public boolean containsKey(Object key) { 217 key = convertKey(key); 218 int hashCode = hash(key); 219 HashEntry entry = data[hashIndex(hashCode, data.length)]; while (entry != null) { 221 if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) { 222 return true; 223 } 224 entry = entry.next; 225 } 226 return false; 227 } 228 229 235 public boolean containsValue(Object value) { 236 if (value == null) { 237 for (int i = 0, isize = data.length; i < isize; i++) { 238 HashEntry entry = data[i]; 239 while (entry != null) { 240 if (entry.getValue() == null) { 241 return true; 242 } 243 entry = entry.next; 244 } 245 } 246 } else { 247 for (int i = 0, isize = data.length; i < isize; i++) { 248 HashEntry entry = data[i]; 249 while (entry != null) { 250 if (isEqualValue(value, entry.getValue())) { 251 return true; 252 } 253 entry = entry.next; 254 } 255 } 256 } 257 return false; 258 } 259 260 268 public Object put(Object key, Object value) { 269 key = convertKey(key); 270 int hashCode = hash(key); 271 int index = hashIndex(hashCode, data.length); 272 HashEntry entry = data[index]; 273 while (entry != null) { 274 if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) { 275 Object oldValue = entry.getValue(); 276 updateEntry(entry, value); 277 return oldValue; 278 } 279 entry = entry.next; 280 } 281 282 addMapping(index, hashCode, key, value); 283 return null; 284 } 285 286 295 public void putAll(Map map) { 296 int mapSize = map.size(); 297 if (mapSize == 0) { 298 return; 299 } 300 int newSize = (int) ((size + mapSize) / loadFactor + 1); 301 ensureCapacity(calculateNewCapacity(newSize)); 302 for (Iterator it = map.entrySet().iterator(); it.hasNext();) { 303 Map.Entry entry = (Map.Entry ) it.next(); 304 put(entry.getKey(), entry.getValue()); 305 } 306 } 307 308 314 public Object remove(Object key) { 315 key = convertKey(key); 316 int hashCode = hash(key); 317 int index = hashIndex(hashCode, data.length); 318 HashEntry entry = data[index]; 319 HashEntry previous = null; 320 while (entry != null) { 321 if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) { 322 Object oldValue = entry.getValue(); 323 removeMapping(entry, index, previous); 324 return oldValue; 325 } 326 previous = entry; 327 entry = entry.next; 328 } 329 return null; 330 } 331 332 336 public void clear() { 337 modCount++; 338 HashEntry[] data = this.data; 339 for (int i = data.length - 1; i >= 0; i--) { 340 data[i] = null; 341 } 342 size = 0; 343 } 344 345 357 protected Object convertKey(Object key) { 358 return (key == null ? NULL : key); 359 } 360 361 369 protected int hash(Object key) { 370 int h = key.hashCode(); 372 h += ~(h << 9); 373 h ^= (h >>> 14); 374 h += (h << 4); 375 h ^= (h >>> 10); 376 return h; 377 } 378 379 388 protected boolean isEqualKey(Object key1, Object key2) { 389 return (key1 == key2 || key1.equals(key2)); 390 } 391 392 401 protected boolean isEqualValue(Object value1, Object value2) { 402 return (value1 == value2 || value1.equals(value2)); 403 } 404 405 414 protected int hashIndex(int hashCode, int dataSize) { 415 return hashCode & (dataSize - 1); 416 } 417 418 429 protected HashEntry getEntry(Object key) { 430 key = convertKey(key); 431 int hashCode = hash(key); 432 HashEntry entry = data[hashIndex(hashCode, data.length)]; while (entry != null) { 434 if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) { 435 return entry; 436 } 437 entry = entry.next; 438 } 439 return null; 440 } 441 442 452 protected void updateEntry(HashEntry entry, Object newValue) { 453 entry.setValue(newValue); 454 } 455 456 468 protected void reuseEntry(HashEntry entry, int hashIndex, int hashCode, Object key, Object value) { 469 entry.next = data[hashIndex]; 470 entry.hashCode = hashCode; 471 entry.key = key; 472 entry.value = value; 473 } 474 475 489 protected void addMapping(int hashIndex, int hashCode, Object key, Object value) { 490 modCount++; 491 HashEntry entry = createEntry(data[hashIndex], hashCode, key, value); 492 addEntry(entry, hashIndex); 493 size++; 494 checkCapacity(); 495 } 496 497 510 protected HashEntry createEntry(HashEntry next, int hashCode, Object key, Object value) { 511 return new HashEntry(next, hashCode, key, value); 512 } 513 514 523 protected void addEntry(HashEntry entry, int hashIndex) { 524 data[hashIndex] = entry; 525 } 526 527 539 protected void removeMapping(HashEntry entry, int hashIndex, HashEntry previous) { 540 modCount++; 541 removeEntry(entry, hashIndex, previous); 542 size--; 543 destroyEntry(entry); 544 } 545 546 557 protected void removeEntry(HashEntry entry, int hashIndex, HashEntry previous) { 558 if (previous == null) { 559 data[hashIndex] = entry.next; 560 } else { 561 previous.next = entry.next; 562 } 563 } 564 565 573 protected void destroyEntry(HashEntry entry) { 574 entry.next = null; 575 entry.key = null; 576 entry.value = null; 577 } 578 579 585 protected void checkCapacity() { 586 if (size >= threshold) { 587 int newCapacity = data.length * 2; 588 if (newCapacity <= MAXIMUM_CAPACITY) { 589 ensureCapacity(newCapacity); 590 } 591 } 592 } 593 594 599 protected void ensureCapacity(int newCapacity) { 600 int oldCapacity = data.length; 601 if (newCapacity <= oldCapacity) { 602 return; 603 } 604 if (size == 0) { 605 threshold = calculateThreshold(newCapacity, loadFactor); 606 data = new HashEntry[newCapacity]; 607 } else { 608 HashEntry oldEntries[] = data; 609 HashEntry newEntries[] = new HashEntry[newCapacity]; 610 611 modCount++; 612 for (int i = oldCapacity - 1; i >= 0; i--) { 613 HashEntry entry = oldEntries[i]; 614 if (entry != null) { 615 oldEntries[i] = null; do { 617 HashEntry next = entry.next; 618 int index = hashIndex(entry.hashCode, newCapacity); 619 entry.next = newEntries[index]; 620 newEntries[index] = entry; 621 entry = next; 622 } while (entry != null); 623 } 624 } 625 threshold = calculateThreshold(newCapacity, loadFactor); 626 data = newEntries; 627 } 628 } 629 630 637 protected int calculateNewCapacity(int proposedCapacity) { 638 int newCapacity = 1; 639 if (proposedCapacity > MAXIMUM_CAPACITY) { 640 newCapacity = MAXIMUM_CAPACITY; 641 } else { 642 while (newCapacity < proposedCapacity) { 643 newCapacity <<= 1; } 645 if (newCapacity > MAXIMUM_CAPACITY) { 646 newCapacity = MAXIMUM_CAPACITY; 647 } 648 } 649 return newCapacity; 650 } 651 652 660 protected int calculateThreshold(int newCapacity, float factor) { 661 return (int) (newCapacity * factor); 662 } 663 664 674 protected HashEntry entryNext(HashEntry entry) { 675 return entry.next; 676 } 677 678 687 protected int entryHashCode(HashEntry entry) { 688 return entry.hashCode; 689 } 690 691 700 protected Object entryKey(HashEntry entry) { 701 return entry.key; 702 } 703 704 713 protected Object entryValue(HashEntry entry) { 714 return entry.value; 715 } 716 717 729 public MapIterator mapIterator() { 730 if (size == 0) { 731 return EmptyMapIterator.INSTANCE; 732 } 733 return new HashMapIterator(this); 734 } 735 736 739 protected static class HashMapIterator extends HashIterator implements MapIterator { 740 741 protected HashMapIterator(AbstractHashedMap parent) { 742 super(parent); 743 } 744 745 public Object next() { 746 return super.nextEntry().getKey(); 747 } 748 749 public Object getKey() { 750 HashEntry current = currentEntry(); 751 if (current == null) { 752 throw new IllegalStateException (AbstractHashedMap.GETKEY_INVALID); 753 } 754 return current.getKey(); 755 } 756 757 public Object getValue() { 758 HashEntry current = currentEntry(); 759 if (current == null) { 760 throw new IllegalStateException (AbstractHashedMap.GETVALUE_INVALID); 761 } 762 return current.getValue(); 763 } 764 765 public Object setValue(Object value) { 766 HashEntry current = currentEntry(); 767 if (current == null) { 768 throw new IllegalStateException (AbstractHashedMap.SETVALUE_INVALID); 769 } 770 return current.setValue(value); 771 } 772 } 773 774 782 public Set entrySet() { 783 if (entrySet == null) { 784 entrySet = new EntrySet(this); 785 } 786 return entrySet; 787 } 788 789 795 protected Iterator createEntrySetIterator() { 796 if (size() == 0) { 797 return EmptyIterator.INSTANCE; 798 } 799 return new EntrySetIterator(this); 800 } 801 802 805 protected static class EntrySet extends AbstractSet { 806 807 protected final AbstractHashedMap parent; 808 809 protected EntrySet(AbstractHashedMap parent) { 810 super(); 811 this.parent = parent; 812 } 813 814 public int size() { 815 return parent.size(); 816 } 817 818 public void clear() { 819 parent.clear(); 820 } 821 822 public boolean contains(Object entry) { 823 if (entry instanceof Map.Entry ) { 824 Map.Entry e = (Map.Entry ) entry; 825 Entry match = parent.getEntry(e.getKey()); 826 return (match != null && match.equals(e)); 827 } 828 return false; 829 } 830 831 public boolean remove(Object obj) { 832 if (obj instanceof Map.Entry == false) { 833 return false; 834 } 835 if (contains(obj) == false) { 836 return false; 837 } 838 Map.Entry entry = (Map.Entry ) obj; 839 Object key = entry.getKey(); 840 parent.remove(key); 841 return true; 842 } 843 844 public Iterator iterator() { 845 return parent.createEntrySetIterator(); 846 } 847 } 848 849 852 protected static class EntrySetIterator extends HashIterator { 853 854 protected EntrySetIterator(AbstractHashedMap parent) { 855 super(parent); 856 } 857 858 public Object next() { 859 return super.nextEntry(); 860 } 861 } 862 863 871 public Set keySet() { 872 if (keySet == null) { 873 keySet = new KeySet(this); 874 } 875 return keySet; 876 } 877 878 884 protected Iterator createKeySetIterator() { 885 if (size() == 0) { 886 return EmptyIterator.INSTANCE; 887 } 888 return new KeySetIterator(this); 889 } 890 891 894 |