1. /*
  2. * Copyright 2003-2004 The Apache Software Foundation
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. package org.apache.commons.collections.map;
  17. import java.io.IOException;
  18. import java.io.ObjectInputStream;
  19. import java.io.ObjectOutputStream;
  20. import java.util.AbstractCollection;
  21. import java.util.AbstractMap;
  22. import java.util.AbstractSet;
  23. import java.util.Collection;
  24. import java.util.ConcurrentModificationException;
  25. import java.util.Iterator;
  26. import java.util.Map;
  27. import java.util.NoSuchElementException;
  28. import java.util.Set;
  29. import org.apache.commons.collections.IterableMap;
  30. import org.apache.commons.collections.KeyValue;
  31. import org.apache.commons.collections.MapIterator;
  32. import org.apache.commons.collections.iterators.EmptyIterator;
  33. import org.apache.commons.collections.iterators.EmptyMapIterator;
  34. /**
  35. * An abstract implementation of a hash-based map which provides numerous points for
  36. * subclasses to override.
  37. * <p>
  38. * This class implements all the features necessary for a subclass hash-based map.
  39. * Key-value entries are stored in instances of the <code>HashEntry</code> class,
  40. * which can be overridden and replaced. The iterators can similarly be replaced,
  41. * without the need to replace the KeySet, EntrySet and Values view classes.
  42. * <p>
  43. * Overridable methods are provided to change the default hashing behaviour, and
  44. * to change how entries are added to and removed from the map. Hopefully, all you
  45. * need for unusual subclasses is here.
  46. * <p>
  47. * NOTE: From Commons Collections 3.1 this class extends AbstractMap.
  48. * This is to provide backwards compatibility for ReferenceMap between v3.0 and v3.1.
  49. * This extends clause will be removed in v4.0.
  50. *
  51. * @since Commons Collections 3.0
  52. * @version $Revision: 1.20 $ $Date: 2004/06/22 21:42:12 $
  53. *
  54. * @author java util HashMap
  55. * @author Stephen Colebourne
  56. */
  57. public class AbstractHashedMap extends AbstractMap implements IterableMap {
  58. protected static final String NO_NEXT_ENTRY = "No next() entry in the iteration";
  59. protected static final String NO_PREVIOUS_ENTRY = "No previous() entry in the iteration";
  60. protected static final String REMOVE_INVALID = "remove() can only be called once after next()";
  61. protected static final String GETKEY_INVALID = "getKey() can only be called after next() and before remove()";
  62. protected static final String GETVALUE_INVALID = "getValue() can only be called after next() and before remove()";
  63. protected static final String SETVALUE_INVALID = "setValue() can only be called after next() and before remove()";
  64. /** The default capacity to use */
  65. protected static final int DEFAULT_CAPACITY = 16;
  66. /** The default threshold to use */
  67. protected static final int DEFAULT_THRESHOLD = 12;
  68. /** The default load factor to use */
  69. protected static final float DEFAULT_LOAD_FACTOR = 0.75f;
  70. /** The maximum capacity allowed */
  71. protected static final int MAXIMUM_CAPACITY = 1 << 30;
  72. /** An object for masking null */
  73. protected static final Object NULL = new Object();
  74. /** Load factor, normally 0.75 */
  75. protected transient float loadFactor;
  76. /** The size of the map */
  77. protected transient int size;
  78. /** Map entries */
  79. protected transient HashEntry[] data;
  80. /** Size at which to rehash */
  81. protected transient int threshold;
  82. /** Modification count for iterators */
  83. protected transient int modCount;
  84. /** Entry set */
  85. protected transient EntrySet entrySet;
  86. /** Key set */
  87. protected transient KeySet keySet;
  88. /** Values */
  89. protected transient Values values;
  90. /**
  91. * Constructor only used in deserialization, do not use otherwise.
  92. */
  93. protected AbstractHashedMap() {
  94. super();
  95. }
  96. /**
  97. * Constructor which performs no validation on the passed in parameters.
  98. *
  99. * @param initialCapacity the initial capacity, must be a power of two
  100. * @param loadFactor the load factor, must be > 0.0f and generally < 1.0f
  101. * @param threshold the threshold, must be sensible
  102. */
  103. protected AbstractHashedMap(int initialCapacity, float loadFactor, int threshold) {
  104. super();
  105. this.loadFactor = loadFactor;
  106. this.data = new HashEntry[initialCapacity];
  107. this.threshold = threshold;
  108. init();
  109. }
  110. /**
  111. * Constructs a new, empty map with the specified initial capacity and
  112. * default load factor.
  113. *
  114. * @param initialCapacity the initial capacity
  115. * @throws IllegalArgumentException if the initial capacity is less than one
  116. */
  117. protected AbstractHashedMap(int initialCapacity) {
  118. this(initialCapacity, DEFAULT_LOAD_FACTOR);
  119. }
  120. /**
  121. * Constructs a new, empty map with the specified initial capacity and
  122. * load factor.
  123. *
  124. * @param initialCapacity the initial capacity
  125. * @param loadFactor the load factor
  126. * @throws IllegalArgumentException if the initial capacity is less than one
  127. * @throws IllegalArgumentException if the load factor is less than or equal to zero
  128. */
  129. protected AbstractHashedMap(int initialCapacity, float loadFactor) {
  130. super();
  131. if (initialCapacity < 1) {
  132. throw new IllegalArgumentException("Initial capacity must be greater than 0");
  133. }
  134. if (loadFactor <= 0.0f || Float.isNaN(loadFactor)) {
  135. throw new IllegalArgumentException("Load factor must be greater than 0");
  136. }
  137. this.loadFactor = loadFactor;
  138. this.threshold = calculateThreshold(initialCapacity, loadFactor);
  139. initialCapacity = calculateNewCapacity(initialCapacity);
  140. this.data = new HashEntry[initialCapacity];
  141. init();
  142. }
  143. /**
  144. * Constructor copying elements from another map.
  145. *
  146. * @param map the map to copy
  147. * @throws NullPointerException if the map is null
  148. */
  149. protected AbstractHashedMap(Map map) {
  150. this(Math.max(2 * map.size(), DEFAULT_CAPACITY), DEFAULT_LOAD_FACTOR);
  151. putAll(map);
  152. }
  153. /**
  154. * Initialise subclasses during construction, cloning or deserialization.
  155. */
  156. protected void init() {
  157. }
  158. //-----------------------------------------------------------------------
  159. /**
  160. * Gets the value mapped to the key specified.
  161. *
  162. * @param key the key
  163. * @return the mapped value, null if no match
  164. */
  165. public Object get(Object key) {
  166. key = convertKey(key);
  167. int hashCode = hash(key);
  168. HashEntry entry = data[hashIndex(hashCode, data.length)]; // no local for hash index
  169. while (entry != null) {
  170. if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) {
  171. return entry.getValue();
  172. }
  173. entry = entry.next;
  174. }
  175. return null;
  176. }
  177. /**
  178. * Gets the size of the map.
  179. *
  180. * @return the size
  181. */
  182. public int size() {
  183. return size;
  184. }
  185. /**
  186. * Checks whether the map is currently empty.
  187. *
  188. * @return true if the map is currently size zero
  189. */
  190. public boolean isEmpty() {
  191. return (size == 0);
  192. }
  193. //-----------------------------------------------------------------------
  194. /**
  195. * Checks whether the map contains the specified key.
  196. *
  197. * @param key the key to search for
  198. * @return true if the map contains the key
  199. */
  200. public boolean containsKey(Object key) {
  201. key = convertKey(key);
  202. int hashCode = hash(key);
  203. HashEntry entry = data[hashIndex(hashCode, data.length)]; // no local for hash index
  204. while (entry != null) {
  205. if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) {
  206. return true;
  207. }
  208. entry = entry.next;
  209. }
  210. return false;
  211. }
  212. /**
  213. * Checks whether the map contains the specified value.
  214. *
  215. * @param value the value to search for
  216. * @return true if the map contains the value
  217. */
  218. public boolean containsValue(Object value) {
  219. if (value == null) {
  220. for (int i = 0, isize = data.length; i < isize; i++) {
  221. HashEntry entry = data[i];
  222. while (entry != null) {
  223. if (entry.getValue() == null) {
  224. return true;
  225. }
  226. entry = entry.next;
  227. }
  228. }
  229. } else {
  230. for (int i = 0, isize = data.length; i < isize; i++) {
  231. HashEntry entry = data[i];
  232. while (entry != null) {
  233. if (isEqualValue(value, entry.getValue())) {
  234. return true;
  235. }
  236. entry = entry.next;
  237. }
  238. }
  239. }
  240. return false;
  241. }
  242. //-----------------------------------------------------------------------
  243. /**
  244. * Puts a key-value mapping into this map.
  245. *
  246. * @param key the key to add
  247. * @param value the value to add
  248. * @return the value previously mapped to this key, null if none
  249. */
  250. public Object put(Object key, Object value) {
  251. key = convertKey(key);
  252. int hashCode = hash(key);
  253. int index = hashIndex(hashCode, data.length);
  254. HashEntry entry = data[index];
  255. while (entry != null) {
  256. if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) {
  257. Object oldValue = entry.getValue();
  258. updateEntry(entry, value);
  259. return oldValue;
  260. }
  261. entry = entry.next;
  262. }
  263. addMapping(index, hashCode, key, value);
  264. return null;
  265. }
  266. /**
  267. * Puts all the values from the specified map into this map.
  268. * <p>
  269. * This implementation iterates around the specified map and
  270. * uses {@link #put(Object, Object)}.
  271. *
  272. * @param map the map to add
  273. * @throws NullPointerException if the map is null
  274. */
  275. public void putAll(Map map) {
  276. int mapSize = map.size();
  277. if (mapSize == 0) {
  278. return;
  279. }
  280. int newSize = (int) ((size + mapSize) / loadFactor + 1);
  281. ensureCapacity(calculateNewCapacity(newSize));
  282. for (Iterator it = map.entrySet().iterator(); it.hasNext();) {
  283. Map.Entry entry = (Map.Entry) it.next();
  284. put(entry.getKey(), entry.getValue());
  285. }
  286. }
  287. /**
  288. * Removes the specified mapping from this map.
  289. *
  290. * @param key the mapping to remove
  291. * @return the value mapped to the removed key, null if key not in map
  292. */
  293. public Object remove(Object key) {
  294. key = convertKey(key);
  295. int hashCode = hash(key);
  296. int index = hashIndex(hashCode, data.length);
  297. HashEntry entry = data[index];
  298. HashEntry previous = null;
  299. while (entry != null) {
  300. if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) {
  301. Object oldValue = entry.getValue();
  302. removeMapping(entry, index, previous);
  303. return oldValue;
  304. }
  305. previous = entry;
  306. entry = entry.next;
  307. }
  308. return null;
  309. }
  310. /**
  311. * Clears the map, resetting the size to zero and nullifying references
  312. * to avoid garbage collection issues.
  313. */
  314. public void clear() {
  315. modCount++;
  316. HashEntry[] data = this.data;
  317. for (int i = data.length - 1; i >= 0; i--) {
  318. data[i] = null;
  319. }
  320. size = 0;
  321. }
  322. //-----------------------------------------------------------------------
  323. /**
  324. * Converts input keys to another object for storage in the map.
  325. * This implementation masks nulls.
  326. * Subclasses can override this to perform alternate key conversions.
  327. * <p>
  328. * The reverse conversion can be changed, if required, by overriding the
  329. * getKey() method in the hash entry.
  330. *
  331. * @param key the key convert
  332. * @return the converted key
  333. */
  334. protected Object convertKey(Object key) {
  335. return (key == null ? NULL : key);
  336. }
  337. /**
  338. * Gets the hash code for the key specified.
  339. * This implementation uses the additional hashing routine from JDK1.4.
  340. * Subclasses can override this to return alternate hash codes.
  341. *
  342. * @param key the key to get a hash code for
  343. * @return the hash code
  344. */
  345. protected int hash(Object key) {
  346. // same as JDK 1.4
  347. int h = key.hashCode();
  348. h += ~(h << 9);
  349. h ^= (h >>> 14);
  350. h += (h << 4);
  351. h ^= (h >>> 10);
  352. return h;
  353. }
  354. /**
  355. * Compares two keys, in internal converted form, to see if they are equal.
  356. * This implementation uses the equals method and assumes neither key is null.
  357. * Subclasses can override this to match differently.
  358. *
  359. * @param key1 the first key to compare passed in from outside
  360. * @param key2 the second key extracted from the entry via <code>entry.key</code>
  361. * @return true if equal
  362. */
  363. protected boolean isEqualKey(Object key1, Object key2) {
  364. return (key1 == key2 || key1.equals(key2));
  365. }
  366. /**
  367. * Compares two values, in external form, to see if they are equal.
  368. * This implementation uses the equals method and assumes neither value is null.
  369. * Subclasses can override this to match differently.
  370. *
  371. * @param value1 the first value to compare passed in from outside
  372. * @param value2 the second value extracted from the entry via <code>getValue()</code>
  373. * @return true if equal
  374. */
  375. protected boolean isEqualValue(Object value1, Object value2) {
  376. return (value1 == value2 || value1.equals(value2));
  377. }
  378. /**
  379. * Gets the index into the data storage for the hashCode specified.
  380. * This implementation uses the least significant bits of the hashCode.
  381. * Subclasses can override this to return alternate bucketing.
  382. *
  383. * @param hashCode the hash code to use
  384. * @param dataSize the size of the data to pick a bucket from
  385. * @return the bucket index
  386. */
  387. protected int hashIndex(int hashCode, int dataSize) {
  388. return hashCode & (dataSize - 1);
  389. }
  390. //-----------------------------------------------------------------------
  391. /**
  392. * Gets the entry mapped to the key specified.
  393. * <p>
  394. * This method exists for subclasses that may need to perform a multi-step
  395. * process accessing the entry. The public methods in this class don't use this
  396. * method to gain a small performance boost.
  397. *
  398. * @param key the key
  399. * @return the entry, null if no match
  400. */
  401. protected HashEntry getEntry(Object key) {
  402. key = convertKey(key);
  403. int hashCode = hash(key);
  404. HashEntry entry = data[hashIndex(hashCode, data.length)]; // no local for hash index
  405. while (entry != null) {
  406. if (entry.hashCode == hashCode && isEqualKey(key, entry.key)) {
  407. return entry;
  408. }
  409. entry = entry.next;
  410. }
  411. return null;
  412. }
  413. //-----------------------------------------------------------------------
  414. /**
  415. * Updates an existing key-value mapping to change the value.
  416. * <p>
  417. * This implementation calls <code>setValue()</code> on the entry.
  418. * Subclasses could override to handle changes to the map.
  419. *
  420. * @param entry the entry to update
  421. * @param newValue the new value to store
  422. */
  423. protected void updateEntry(HashEntry entry, Object newValue) {
  424. entry.setValue(newValue);
  425. }
  426. /**
  427. * Reuses an existing key-value mapping, storing completely new data.
  428. * <p>
  429. * This implementation sets all the data fields on the entry.
  430. * Subclasses could populate additional entry fields.
  431. *
  432. * @param entry the entry to update, not null
  433. * @param hashIndex the index in the data array
  434. * @param hashCode the hash code of the key to add
  435. * @param key the key to add
  436. * @param value the value to add
  437. */
  438. protected void reuseEntry(HashEntry entry, int hashIndex, int hashCode, Object key, Object value) {
  439. entry.next = data[hashIndex];
  440. entry.hashCode = hashCode;
  441. entry.key = key;
  442. entry.value = value;
  443. }
  444. //-----------------------------------------------------------------------
  445. /**
  446. * Adds a new key-value mapping into this map.
  447. * <p>
  448. * This implementation calls <code>createEntry()</code>, <code>addEntry()</code>
  449. * and <code>checkCapacity()</code>.
  450. * It also handles changes to <code>modCount</code> and <code>size</code>.
  451. * Subclasses could override to fully control adds to the map.
  452. *
  453. * @param hashIndex the index into the data array to store at
  454. * @param hashCode the hash code of the key to add
  455. * @param key the key to add
  456. * @param value the value to add
  457. */
  458. protected void addMapping(int hashIndex, int hashCode, Object key, Object value) {
  459. modCount++;
  460. HashEntry entry = createEntry(data[hashIndex], hashCode, key, value);
  461. addEntry(entry, hashIndex);
  462. size++;
  463. checkCapacity();
  464. }
  465. /**
  466. * Creates an entry to store the key-value data.
  467. * <p>
  468. * This implementation creates a new HashEntry instance.
  469. * Subclasses can override this to return a different storage class,
  470. * or implement caching.
  471. *
  472. * @param next the next entry in sequence
  473. * @param hashCode the hash code to use
  474. * @param key the key to store
  475. * @param value the value to store
  476. * @return the newly created entry
  477. */
  478. protected HashEntry createEntry(HashEntry next, int hashCode, Object key, Object value) {
  479. return new HashEntry(next, hashCode, key, value);
  480. }
  481. /**
  482. * Adds an entry into this map.
  483. * <p>
  484. * This implementation adds the entry to the data storage table.
  485. * Subclasses could override to handle changes to the map.
  486. *
  487. * @param entry the entry to add
  488. * @param hashIndex the index into the data array to store at
  489. */
  490. protected void addEntry(HashEntry entry, int hashIndex) {
  491. data[hashIndex] = entry;
  492. }
  493. //-----------------------------------------------------------------------
  494. /**
  495. * Removes a mapping from the map.
  496. * <p>
  497. * This implementation calls <code>removeEntry()</code> and <code>destroyEntry()</code>.
  498. * It also handles changes to <code>modCount</code> and <code>size</code>.
  499. * Subclasses could override to fully control removals from the map.
  500. *
  501. * @param entry the entry to remove
  502. * @param hashIndex the index into the data structure
  503. * @param previous the previous entry in the chain
  504. */
  505. protected void removeMapping(HashEntry entry, int hashIndex, HashEntry previous) {
  506. modCount++;
  507. removeEntry(entry, hashIndex, previous);
  508. size--;
  509. destroyEntry(entry);
  510. }
  511. /**
  512. * Removes an entry from the chain stored in a particular index.
  513. * <p>
  514. * This implementation removes the entry from the data storage table.
  515. * The size is not updated.
  516. * Subclasses could override to handle changes to the map.
  517. *
  518. * @param entry the entry to remove
  519. * @param hashIndex the index into the data structure
  520. * @param previous the previous entry in the chain
  521. */
  522. protected void removeEntry(HashEntry entry, int hashIndex, HashEntry previous) {
  523. if (previous == null) {
  524. data[hashIndex] = entry.next;
  525. } else {
  526. previous.next = entry.next;
  527. }
  528. }
  529. /**
  530. * Kills an entry ready for the garbage collector.
  531. * <p>
  532. * This implementation prepares the HashEntry for garbage collection.
  533. * Subclasses can override this to implement caching (override clear as well).
  534. *
  535. * @param entry the entry to destroy
  536. */
  537. protected void destroyEntry(HashEntry entry) {
  538. entry.next = null;
  539. entry.key = null;
  540. entry.value = null;
  541. }
  542. //-----------------------------------------------------------------------
  543. /**
  544. * Checks the capacity of the map and enlarges it if necessary.
  545. * <p>
  546. * This implementation uses the threshold to check if the map needs enlarging
  547. */
  548. protected void checkCapacity() {
  549. if (size >= threshold) {
  550. int newCapacity = data.length * 2;
  551. if (newCapacity <= MAXIMUM_CAPACITY) {
  552. ensureCapacity(newCapacity);
  553. }
  554. }
  555. }
  556. /**
  557. * Changes the size of the data structure to the capacity proposed.
  558. *
  559. * @param newCapacity the new capacity of the array (a power of two, less or equal to max)
  560. */
  561. protected void ensureCapacity(int newCapacity) {
  562. int oldCapacity = data.length;
  563. if (newCapacity <= oldCapacity) {
  564. return;
  565. }
  566. if (size == 0) {
  567. threshold = calculateThreshold(newCapacity, loadFactor);
  568. data = new HashEntry[newCapacity];
  569. } else {
  570. HashEntry oldEntries[] = data;
  571. HashEntry newEntries[] = new HashEntry[newCapacity];
  572. modCount++;
  573. for (int i = oldCapacity - 1; i >= 0; i--) {
  574. HashEntry entry = oldEntries[i];
  575. if (entry != null) {
  576. oldEntries[i] = null; // gc
  577. do {
  578. HashEntry next = entry.next;
  579. int index = hashIndex(entry.hashCode, newCapacity);
  580. entry.next = newEntries[index];
  581. newEntries[index] = entry;
  582. entry = next;
  583. } while (entry != null);
  584. }
  585. }
  586. threshold = calculateThreshold(newCapacity, loadFactor);
  587. data = newEntries;
  588. }
  589. }
  590. /**
  591. * Calculates the new capacity of the map.
  592. * This implementation normalizes the capacity to a power of two.
  593. *
  594. * @param proposedCapacity the proposed capacity
  595. * @return the normalized new capacity
  596. */
  597. protected int calculateNewCapacity(int proposedCapacity) {
  598. int newCapacity = 1;
  599. if (proposedCapacity > MAXIMUM_CAPACITY) {
  600. newCapacity = MAXIMUM_CAPACITY;
  601. } else {
  602. while (newCapacity < proposedCapacity) {
  603. newCapacity <<= 1; // multiply by two
  604. }
  605. if (newCapacity > MAXIMUM_CAPACITY) {
  606. newCapacity = MAXIMUM_CAPACITY;
  607. }
  608. }
  609. return newCapacity;
  610. }
  611. /**
  612. * Calculates the new threshold of the map, where it will be resized.
  613. * This implementation uses the load factor.
  614. *
  615. * @param newCapacity the new capacity
  616. * @param factor the load factor
  617. * @return the new resize threshold
  618. */
  619. protected int calculateThreshold(int newCapacity, float factor) {
  620. return (int) (newCapacity * factor);
  621. }
  622. //-----------------------------------------------------------------------
  623. /**
  624. * Gets the <code>next</code> field from a <code>HashEntry</code>.
  625. * Used in subclasses that have no visibility of the field.
  626. *
  627. * @param entry the entry to query, must not be null
  628. * @return the <code>next</code> field of the entry
  629. * @throws NullPointerException if the entry is null
  630. * @since Commons Collections 3.1
  631. */
  632. protected HashEntry entryNext(HashEntry entry) {
  633. return entry.next;
  634. }
  635. /**
  636. * Gets the <code>hashCode</code> field from a <code>HashEntry</code>.
  637. * Used in subclasses that have no visibility of the field.
  638. *
  639. * @param entry the entry to query, must not be null
  640. * @return the <code>hashCode</code> field of the entry
  641. * @throws NullPointerException if the entry is null
  642. * @since Commons Collections 3.1
  643. */
  644. protected int entryHashCode(HashEntry entry) {
  645. return entry.hashCode;
  646. }
  647. /**
  648. * Gets the <code>key</code> field from a <code>HashEntry</code>.
  649. * Used in subclasses that have no visibility of the field.
  650. *
  651. * @param entry the entry to query, must not be null
  652. * @return the <code>key</code> field of the entry
  653. * @throws NullPointerException if the entry is null
  654. * @since Commons Collections 3.1
  655. */
  656. protected Object entryKey(HashEntry entry) {
  657. return entry.key;
  658. }
  659. /**
  660. * Gets the <code>value</code> field from a <code>HashEntry</code>.
  661. * Used in subclasses that have no visibility of the field.
  662. *
  663. * @param entry the entry to query, must not be null
  664. * @return the <code>value</code> field of the entry
  665. * @throws NullPointerException if the entry is null
  666. * @since Commons Collections 3.1
  667. */
  668. protected Object entryValue(HashEntry entry) {
  669. return entry.value;
  670. }
  671. //-----------------------------------------------------------------------
  672. /**
  673. * Gets an iterator over the map.
  674. * Changes made to the iterator affect this map.
  675. * <p>
  676. * A MapIterator returns the keys in the map. It also provides convenient
  677. * methods to get the key and value, and set the value.
  678. * It avoids the need to create an entrySet/keySet/values object.
  679. * It also avoids creating the Map.Entry object.
  680. *
  681. * @return the map iterator
  682. */
  683. public MapIterator mapIterator() {
  684. if (size == 0) {
  685. return EmptyMapIterator.INSTANCE;
  686. }
  687. return new HashMapIterator(this);
  688. }
  689. /**
  690. * MapIterator implementation.
  691. */
  692. protected static class HashMapIterator extends HashIterator implements MapIterator {
  693. protected HashMapIterator(AbstractHashedMap parent) {
  694. super(parent);
  695. }
  696. public Object next() {
  697. return super.nextEntry().getKey();
  698. }
  699. public Object getKey() {
  700. HashEntry current = currentEntry();
  701. if (current == null) {
  702. throw new IllegalStateException(AbstractHashedMap.GETKEY_INVALID);
  703. }
  704. return current.getKey();
  705. }
  706. public Object getValue() {
  707. HashEntry current = currentEntry();
  708. if (current == null) {
  709. throw new IllegalStateException(AbstractHashedMap.GETVALUE_INVALID);
  710. }
  711. return current.getValue();
  712. }
  713. public Object setValue(Object value) {
  714. HashEntry current = currentEntry();
  715. if (current == null) {
  716. throw new IllegalStateException(AbstractHashedMap.SETVALUE_INVALID);
  717. }
  718. return current.setValue(value);
  719. }
  720. }
  721. //-----------------------------------------------------------------------
  722. /**
  723. * Gets the entrySet view of the map.
  724. * Changes made to the view affect this map.
  725. * To simply iterate through the entries, use {@link #mapIterator()}.
  726. *
  727. * @return the entrySet view
  728. */
  729. public Set entrySet() {
  730. if (entrySet == null) {
  731. entrySet = new EntrySet(this);
  732. }
  733. return entrySet;
  734. }
  735. /**
  736. * Creates an entry set iterator.
  737. * Subclasses can override this to return iterators with different properties.
  738. *
  739. * @return the entrySet iterator
  740. */
  741. protected Iterator createEntrySetIterator() {
  742. if (size() == 0) {
  743. return EmptyIterator.INSTANCE;
  744. }
  745. return new EntrySetIterator(this);
  746. }
  747. /**
  748. * EntrySet implementation.
  749. */
  750. protected static class EntrySet extends AbstractSet {
  751. /** The parent map */
  752. protected final AbstractHashedMap parent;
  753. protected EntrySet(AbstractHashedMap parent) {
  754. super();
  755. this.parent = parent;
  756. }
  757. public int size() {
  758. return parent.size();
  759. }
  760. public void clear() {
  761. parent.clear();
  762. }
  763. public boolean contains(Object entry) {
  764. if (entry instanceof Map.Entry) {
  765. Map.Entry e = (Map.Entry) entry;
  766. Entry match = parent.getEntry(e.getKey());
  767. return (match != null && match.equals(e));
  768. }
  769. return false;
  770. }
  771. public boolean remove(Object obj) {
  772. if (obj instanceof Map.Entry == false) {
  773. return false;
  774. }
  775. if (contains(obj) == false) {
  776. return false;
  777. }
  778. Map.Entry entry = (Map.Entry) obj;
  779. Object key = entry.getKey();
  780. parent.remove(key);
  781. return true;
  782. }
  783. public Iterator iterator() {
  784. return parent.createEntrySetIterator();
  785. }
  786. }
  787. /**
  788. * EntrySet iterator.
  789. */
  790. protected static class EntrySetIterator extends HashIterator {
  791. protected EntrySetIterator(AbstractHashedMap parent) {
  792. super(parent);
  793. }
  794. public Object next() {
  795. return super.nextEntry();
  796. }
  797. }
  798. //-----------------------------------------------------------------------
  799. /**
  800. * Gets the keySet view of the map.
  801. * Changes made to the view affect this map.
  802. * To simply iterate through the keys, use {@link #mapIterator()}.
  803. *
  804. * @return the keySet view
  805. */
  806. public Set keySet() {
  807. if (keySet == null) {
  808. keySet = new KeySet(this);
  809. }
  810. return keySet;
  811. }
  812. /**
  813. * Creates a key set iterator.
  814. * Subclasses can override this to return iterators with different properties.
  815. *
  816. * @return the keySet iterator
  817. */
  818. protected Iterator createKeySetIterator() {
  819. if (size() == 0) {
  820. return EmptyIterator.INSTANCE;
  821. }
  822. return new KeySetIterator(this);
  823. }
  824. /**
  825. * KeySet implementation.
  826. */
  827. protected static class KeySet extends AbstractSet {
  828. /** The parent map */
  829. protected final AbstractHashedMap parent;
  830. protected KeySet(AbstractHashedMap parent) {
  831. super();
  832. this.parent = parent;
  833. }
  834. public int size() {
  835. return parent.size();
  836. }
  837. public void clear() {
  838. parent.clear();
  839. }
  840. public boolean contains(Object key) {
  841. return parent.containsKey(key);
  842. }
  843. public boolean remove(Object key) {
  844. boolean result = parent.containsKey(key);
  845. parent.remove(key);
  846. return result;
  847. }
  848. public Iterator iterator() {
  849. return parent.createKeySetIterator();
  850. }
  851. }
  852. /**
  853. * KeySet iterator.
  854. */
  855. protected static class KeySetIterator extends EntrySetIterator {
  856. protected KeySetIterator(AbstractHashedMap parent) {
  857. super(parent);
  858. }
  859. public Object next() {
  860. return super.nextEntry().getKey();
  861. }
  862. }
  863. //-----------------------------------------------------------------------
  864. /**
  865. * Gets the values view of the map.
  866. * Changes made to the view affect this map.
  867. * To simply iterate through the values, use {@link #mapIterator()}.
  868. *
  869. * @return the values view
  870. */
  871. public Collection values() {
  872. if (values == null) {
  873. values = new Values(this);
  874. }
  875. return values;
  876. }
  877. /**
  878. * Creates a values iterator.
  879. * Subclasses can override this to return iterators with different properties.
  880. *
  881. * @return the values iterator
  882. */
  883. protected Iterator createValuesIterator() {
  884. if (size() == 0) {
  885. return EmptyIterator.INSTANCE;
  886. }
  887. return new ValuesIterator(this);
  888. }
  889. /**
  890. * Values implementation.
  891. */
  892. protected static class Values extends AbstractCollection {
  893. /** The parent map */
  894. protected final AbstractHashedMap parent;
  895. protected Values(AbstractHashedMap parent) {
  896. super();
  897. this.parent = parent;
  898. }
  899. public int size() {
  900. return parent.size();
  901. }
  902. public void clear() {
  903. parent.clear();
  904. }
  905. public boolean contains(Object value) {
  906. return parent.containsValue(value);
  907. }
  908. public Iterator iterator() {
  909. return parent.createValuesIterator();
  910. }
  911. }
  912. /**
  913. * Values iterator.
  914. */
  915. protected static class ValuesIterator extends HashIterator {
  916. protected ValuesIterator(AbstractHashedMap parent) {
  917. super(parent);
  918. }
  919. public Object next() {
  920. return super.nextEntry().getValue();
  921. }
  922. }
  923. //-----------------------------------------------------------------------
  924. /**
  925. * HashEntry used to store the data.
  926. * <p>
  927. * If you subclass <code>AbstractHashedMap</code> but not <code>HashEntry</code>
  928. * then you will not be able to access the protected fields.
  929. * The <code>entryXxx()</code> methods on <code>AbstractHashedMap</code> exist
  930. * to provide the necessary access.
  931. */
  932. protected static class HashEntry implements Map.Entry, KeyValue {
  933. /** The next entry in the hash chain */
  934. protected HashEntry next;
  935. /** The hash code of the key */
  936. protected int hashCode;
  937. /** The key */
  938. protected Object key;
  939. /** The value */
  940. protected Object value;
  941. protected HashEntry(HashEntry next, int hashCode, Object key, Object value) {
  942. super();
  943. this.next = next;
  944. this.hashCode = hashCode;
  945. this.key = key;
  946. this.value = value;
  947. }
  948. public Object getKey() {
  949. return (key == NULL ? null : key);
  950. }
  951. public Object getValue() {
  952. return value;
  953. }
  954. public Object setValue(Object value) {
  955. Object old = this.value;
  956. this.value = value;
  957. return old;
  958. }
  959. public boolean equals(Object obj) {
  960. if (obj == this) {
  961. return true;
  962. }
  963. if (obj instanceof Map.Entry == false) {
  964. return false;
  965. }
  966. Map.Entry other = (Map.Entry) obj;
  967. return
  968. (getKey() == null ? other.getKey() == null : getKey().equals(other.getKey())) &&
  969. (getValue() == null ? other.getValue() == null : getValue().equals(other.getValue()));
  970. }
  971. public int hashCode() {
  972. return (getKey() == null ? 0 : getKey().hashCode()) ^
  973. (getValue() == null ? 0 : getValue().hashCode());
  974. }
  975. public String toString() {
  976. return new StringBuffer().append(getKey()).append('=').append(getValue()).toString();
  977. }
  978. }
  979. /**
  980. * Base Iterator
  981. */
  982. protected static abstract class HashIterator implements Iterator {
  983. /** The parent map */
  984. protected final AbstractHashedMap parent;
  985. /** The current index into the array of buckets */
  986. protected int hashIndex;
  987. /** The last returned entry */
  988. protected HashEntry last;
  989. /** The next entry */
  990. protected HashEntry next;
  991. /** The modification count expected */
  992. protected int expectedModCount;
  993. protected HashIterator(AbstractHashedMap parent) {
  994. super();
  995. this.parent = parent;
  996. HashEntry[] data = parent.data;
  997. int i = data.length;
  998. HashEntry next = null;
  999. while (i > 0 && next == null) {
  1000. next = data[--i];
  1001. }
  1002. this.next = next;
  1003. this.hashIndex = i;
  1004. this.expectedModCount = parent.modCount;
  1005. }
  1006. public boolean hasNext() {
  1007. return (next != null);
  1008. }
  1009. protected HashEntry nextEntry() {
  1010. if (parent.modCount != expectedModCount) {
  1011. throw new ConcurrentModificationException();
  1012. }
  1013. HashEntry newCurrent = next;
  1014. if (newCurrent == null) {
  1015. throw new NoSuchElementException(AbstractHashedMap.NO_NEXT_ENTRY);
  1016. }
  1017. HashEntry[] data = parent.data;
  1018. int i = hashIndex;
  1019. HashEntry n = newCurrent.next;
  1020. while (n == null && i > 0) {
  1021. n = data[--i];
  1022. }
  1023. next = n;
  1024. hashIndex = i;
  1025. last = newCurrent;
  1026. return newCurrent;
  1027. }
  1028. protected HashEntry currentEntry() {
  1029. return last;
  1030. }
  1031. public void remove() {
  1032. if (last == null) {
  1033. throw new IllegalStateException(AbstractHashedMap.REMOVE_INVALID);
  1034. }
  1035. if (parent.modCount != expectedModCount) {
  1036. throw new ConcurrentModificationException();
  1037. }
  1038. parent.remove(last.getKey());
  1039. last = null;
  1040. expectedModCount = parent.modCount;
  1041. }
  1042. public String toString() {
  1043. if (last != null) {
  1044. return "Iterator[" + last.getKey() + "=" + last.getValue() + "]";
  1045. } else {
  1046. return "Iterator[]";
  1047. }
  1048. }
  1049. }
  1050. //-----------------------------------------------------------------------
  1051. /**
  1052. * Writes the map data to the stream. This method must be overridden if a
  1053. * subclass must be setup before <code>put()</code> is used.
  1054. * <p>
  1055. * Serialization is not one of the JDK's nicest topics. Normal serialization will
  1056. * initialise the superclass before the subclass. Sometimes however, this isn't
  1057. * what you want, as in this case the <code>put()</code> method on read can be
  1058. * affected by subclass state.
  1059. * <p>
  1060. * The solution adopted here is to serialize the state data of this class in
  1061. * this protected method. This method must be called by the
  1062. * <code>writeObject()</code> of the first serializable subclass.
  1063. * <p>
  1064. * Subclasses may override if they have a specific field that must be present
  1065. * on read before this implementation will work. Generally, the read determines
  1066. * what must be serialized here, if anything.
  1067. *
  1068. * @param out the output stream
  1069. */
  1070. protected void doWriteObject(ObjectOutputStream out) throws IOException {
  1071. out.writeFloat(loadFactor);
  1072. out.writeInt(data.length);
  1073. out.writeInt(size);
  1074. for (MapIterator it = mapIterator(); it.hasNext();) {
  1075. out.writeObject(it.next());
  1076. out.writeObject(it.getValue());
  1077. }
  1078. }
  1079. /**
  1080. * Reads the map data from the stream. This method must be overridden if a
  1081. * subclass must be setup before <code>put()</code> is used.
  1082. * <p>
  1083. * Serialization is not one of the JDK's nicest topics. Normal serialization will
  1084. * initialise the superclass before the subclass. Sometimes however, this isn't
  1085. * what you want, as in this case the <code>put()</code> method on read can be
  1086. * affected by subclass state.
  1087. * <p>
  1088. * The solution adopted here is to deserialize the state data of this class in
  1089. * this protected method. This method must be called by the
  1090. * <code>readObject()</code> of the first serializable subclass.
  1091. * <p>
  1092. * Subclasses may override if the subclass has a specific field that must be present
  1093. * before <code>put()</code> or <code>calculateThreshold()</code> will work correctly.
  1094. *
  1095. * @param in the input stream
  1096. */
  1097. protected void doReadObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
  1098. loadFactor = in.readFloat();
  1099. int capacity = in.readInt();
  1100. int size = in.readInt();
  1101. init();
  1102. data = new HashEntry[capacity];
  1103. for (int i = 0; i < size; i++) {
  1104. Object key = in.readObject();
  1105. Object value = in.readObject();
  1106. put(key, value);
  1107. }
  1108. threshold = calculateThreshold(data.length, loadFactor);
  1109. }
  1110. //-----------------------------------------------------------------------
  1111. /**
  1112. * Clones the map without cloning the keys or values.
  1113. * <p>
  1114. * To implement <code>clone()</code>, a subclass must implement the
  1115. * <code>Cloneable</code> interface and make this method public.
  1116. *
  1117. * @return a shallow clone
  1118. */
  1119. protected Object clone() {
  1120. try {
  1121. AbstractHashedMap cloned = (AbstractHashedMap) super.clone();
  1122. cloned.data = new HashEntry[data.length];
  1123. cloned.entrySet = null;
  1124. cloned.keySet = null;
  1125. cloned.values = null;
  1126. cloned.modCount = 0;
  1127. cloned.size = 0;
  1128. cloned.init();
  1129. cloned.putAll(this);
  1130. return cloned;
  1131. } catch (CloneNotSupportedException ex) {
  1132. return null; // should never happen
  1133. }
  1134. }
  1135. /**
  1136. * Compares this map with another.
  1137. *
  1138. * @param obj the object to compare to
  1139. * @return true if equal
  1140. */
  1141. public boolean equals(Object obj) {
  1142. if (obj == this) {
  1143. return true;
  1144. }
  1145. if (obj instanceof Map == false) {
  1146. return false;
  1147. }
  1148. Map map = (Map) obj;
  1149. if (map.size() != size()) {
  1150. return false;
  1151. }
  1152. MapIterator it = mapIterator();
  1153. try {
  1154. while (it.hasNext()) {
  1155. Object key = it.next();
  1156. Object value = it.getValue();
  1157. if (value == null) {
  1158. if (map.get(key) != null || map.containsKey(key) == false) {
  1159. return false;
  1160. }
  1161. } else {
  1162. if (value.equals(map.get(key)) == false) {
  1163. return false;
  1164. }
  1165. }
  1166. }
  1167. } catch (ClassCastException ignored) {
  1168. return false;
  1169. } catch (NullPointerException ignored) {
  1170. return false;
  1171. }
  1172. return true;
  1173. }
  1174. /**
  1175. * Gets the standard Map hashCode.
  1176. *
  1177. * @return the hash code defined in the Map interface
  1178. */
  1179. public int hashCode() {
  1180. int total = 0;
  1181. Iterator it = createEntrySetIterator();
  1182. while (it.hasNext()) {
  1183. total += it.next().hashCode();
  1184. }
  1185. return total;
  1186. }
  1187. /**
  1188. * Gets the map as a String.
  1189. *
  1190. * @return a string version of the map
  1191. */
  1192. public String toString() {
  1193. if (size() == 0) {
  1194. return "{}";
  1195. }
  1196. StringBuffer buf = new StringBuffer(32 * size());
  1197. buf.append('{');
  1198. MapIterator it = mapIterator();
  1199. boolean hasNext = it.hasNext();
  1200. while (hasNext) {
  1201. Object key = it.next();
  1202. Object value = it.getValue();
  1203. buf.append(key == this ? "(this Map)" : key)
  1204. .append('=')
  1205. .append(value == this ? "(this Map)" : value);
  1206. hasNext = it.hasNext();
  1207. if (hasNext) {
  1208. buf.append(',').append(' ');
  1209. }
  1210. }
  1211. buf.append('}');
  1212. return buf.toString();
  1213. }
  1214. }