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 protected static class KeySet extends AbstractSet { 895 896 protected final AbstractHashedMap parent; 897 898 protected KeySet(AbstractHashedMap parent) { 899 super(); 900 this.parent = parent; 901 } 902 903 public int size() { 904 return parent.size(); 905 } 906 907 public void clear() { 908 parent.clear(); 909 } 910 911 public boolean contains(Object key) { 912 return parent.containsKey(key); 913 } 914 915 public boolean remove(Object key) { 916 boolean result = parent.containsKey(key); 917 parent.remove(key); 918 return result; 919 } 920 921 public Iterator iterator() { 922 return parent.createKeySetIterator(); 923 } 924 } 925 926 929 protected static class KeySetIterator extends EntrySetIterator { 930 931 protected KeySetIterator(AbstractHashedMap parent) { 932 super(parent); 933 } 934 935 public Object next() { 936 return super.nextEntry().getKey(); 937 } 938 } 939 940 948 public Collection values() { 949 if (values == null) { 950 values = new Values(this); 951 } 952 return values; 953 } 954 955 961 protected Iterator createValuesIterator() { 962 if (size() == 0) { 963 return EmptyIterator.INSTANCE; 964 } 965 return new ValuesIterator(this); 966 } 967 968 971 protected static class Values extends AbstractCollection { 972 973 protected final AbstractHashedMap parent; 974 975 protected Values(AbstractHashedMap parent) { 976 super(); 977 this.parent = parent; 978 } 979 980 public int size() { 981 return parent.size(); 982 } 983 984 public void clear() { 985 parent.clear(); 986 } 987 988 public boolean contains(Object value) { 989 return parent.containsValue(value); 990 } 991 992 public Iterator iterator() { 993 return parent.createValuesIterator(); 994 } 995 } 996 997 1000 protected static class ValuesIterator extends HashIterator { 1001 1002 protected ValuesIterator(AbstractHashedMap parent) { 1003 super(parent); 1004 } 1005 1006 public Object next() { 1007 return super.nextEntry().getValue(); 1008 } 1009 } 1010 1011 1020 protected static class HashEntry implements Map.Entry , KeyValue { 1021 1022 protected HashEntry next; 1023 1024 protected int hashCode; 1025 1026 protected Object key; 1027 1028 protected Object value; 1029 1030 protected HashEntry(HashEntry next, int hashCode, Object key, Object value) { 1031 super(); 1032 this.next = next; 1033 this.hashCode = hashCode; 1034 this.key = key; 1035 this.value = value; 1036 } 1037 1038 public Object getKey() { 1039 return (key == NULL ? null : key); 1040 } 1041 1042 public Object getValue() { 1043 return value; 1044 } 1045 1046 public Object setValue(Object value) { 1047 Object old = this.value; 1048 this.value = value; 1049 return old; 1050 } 1051 1052 public boolean equals(Object obj) { 1053 if (obj == this) { 1054 return true; 1055 } 1056 if (obj instanceof Map.Entry == false) { 1057 return false; 1058 } 1059 Map.Entry other = (Map.Entry ) obj; 1060 return 1061 (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) && 1062 (getValue() == null ? other.getValue() == null : getValue().equals(other.getValue())); 1063 } 1064 1065 public int hashCode() { 1066 return (getKey() == null ? 0 : getKey().hashCode()) ^ 1067 (getValue() == null ? 0 : getValue().hashCode()); 1068 } 1069 1070 public String toString() { 1071 return new StringBuffer ().append(getKey()).append('=').append(getValue()).toString(); 1072 } 1073 } 1074 1075 1078 protected static abstract class HashIterator implements Iterator { 1079 1080 1081 protected final AbstractHashedMap parent; 1082 1083 protected int hashIndex; 1084 1085 protected HashEntry last; 1086 1087 protected HashEntry next; 1088 1089 protected int expectedModCount; 1090 1091 protected HashIterator(AbstractHashedMap parent) { 1092 super(); 1093 this.parent = parent; 1094 HashEntry[] data = parent.data; 1095 int i = data.length; 1096 HashEntry next = null; 1097 while (i > 0 && next == null) { 1098 next = data[--i]; 1099 } 1100 this.next = next; 1101 this.hashIndex = i; 1102 this.expectedModCount = parent.modCount; 1103 } 1104 1105 public boolean hasNext() { 1106 return (next != null); 1107 } 1108 1109 protected HashEntry nextEntry() { 1110 if (parent.modCount != expectedModCount) { 1111 throw new ConcurrentModificationException (); 1112 } 1113 HashEntry newCurrent = next; 1114 if (newCurrent == null) { 1115 throw new NoSuchElementException (AbstractHashedMap.NO_NEXT_ENTRY); 1116 } 1117 HashEntry[] data = parent.data; 1118 int i = hashIndex; 1119 HashEntry n = newCurrent.next; 1120 while (n == null && i > 0) { 1121 n = data[--i]; 1122 } 1123 next = n; 1124 hashIndex = i; 1125 last = newCurrent; 1126 return newCurrent; 1127 } 1128 1129 protected HashEntry currentEntry() { 1130 return last; 1131 } 1132 1133 public void remove() { 1134 if (last == null) { 1135 throw new IllegalStateException (AbstractHashedMap.REMOVE_INVALID); 1136 } 1137 if (parent.modCount != expectedModCount) { 1138 throw new ConcurrentModificationException (); 1139 } 1140 parent.remove(last.getKey()); 1141 last = null; 1142 expectedModCount = parent.modCount; 1143 } 1144 1145 public String toString() { 1146 if (last != null) { 1147 return "Iterator[" + last.getKey() + "=" + last.getValue() + "]"; 1148 } else { 1149 return "Iterator[]"; 1150 } 1151 } 1152 } 1153 1154 1174 protected void doWriteObject(ObjectOutputStream out) throws IOException { 1175 out.writeFloat(loadFactor); 1176 out.writeInt(data.length); 1177 out.writeInt(size); 1178 for (MapIterator it = mapIterator(); it.hasNext();) { 1179 out.writeObject(it.next()); 1180 out.writeObject(it.getValue()); 1181 } 1182 } 1183 1184 1202 protected void doReadObject(ObjectInputStream in) throws IOException , ClassNotFoundException { 1203 loadFactor = in.readFloat(); 1204 int capacity = in.readInt(); 1205 int size = in.readInt(); 1206 init(); 1207 data = new HashEntry[capacity]; 1208 for (int i = 0; i < size; i++) { 1209 Object key = in.readObject(); 1210 Object value = in.readObject(); 1211 put(key, value); 1212 } 1213 threshold = calculateThreshold(data.length, loadFactor); 1214 } 1215 1216 1225 protected Object clone() { 1226 try { 1227 AbstractHashedMap cloned = (AbstractHashedMap) super.clone(); 1228 cloned.data = new HashEntry[data.length]; 1229 cloned.entrySet = null; 1230 cloned.keySet = null; 1231 cloned.values = null; 1232 cloned.modCount = 0; 1233 cloned.size = 0; 1234 cloned.init(); 1235 cloned.putAll(this); 1236 return cloned; 1237 1238 } catch (CloneNotSupportedException ex) { 1239 return null; } 1241 } 1242 1243 1249 public boolean equals(Object obj) { 1250 if (obj == this) { 1251 return true; 1252 } 1253 if (obj instanceof Map == false) { 1254 return false; 1255 } 1256 Map map = (Map ) obj; 1257 if (map.size() != size()) { 1258 return false; 1259 } 1260 MapIterator it = mapIterator(); 1261 try { 1262 while (it.hasNext()) { 1263 Object key = it.next(); 1264 Object value = it.getValue(); 1265 if (value == null) { 1266 if (map.get(key) != null || map.containsKey(key) == false) { 1267 return false; 1268 } 1269 } else { 1270 if (value.equals(map.get(key)) == false) { 1271 return false; 1272 } 1273 } 1274 } 1275 } catch (ClassCastException ignored) { 1276 return false; 1277 } catch (NullPointerException ignored) { 1278 return false; 1279 } 1280 return true; 1281 } 1282 1283 1288 public int hashCode() { 1289 int total = 0; 1290 Iterator it = createEntrySetIterator(); 1291 while (it.hasNext()) { 1292 total += it.next().hashCode(); 1293 } 1294 return total; 1295 } 1296 1297 1302 public String toString() { 1303 if (size() == 0) { 1304 return "{}"; 1305 } 1306 StringBuffer buf = new StringBuffer (32 * size()); 1307 buf.append('{'); 1308 1309 MapIterator it = mapIterator(); 1310 boolean hasNext = it.hasNext(); 1311 while (hasNext) { 1312 Object key = it.next(); 1313 Object value = it.getValue(); 1314 buf.append(key == this ? "(this Map)" : key) 1315 .append('=') 1316 .append(value == this ? "(this Map)" : value); 1317 1318 hasNext = it.hasNext(); 1319 if (hasNext) { 1320 buf.append(',').append(' '); 1321 } 1322 } 1323 1324 buf.append('}'); 1325 return buf.toString(); 1326 } 1327} 1328 | Popular Tags |