From 9702c4a5e2ecaa05533b6c9cfacfaf0120143b09 Mon Sep 17 00:00:00 2001 From: wenshao Date: Wed, 11 May 2011 06:44:20 +0000 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9License?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit git-svn-id: http://code.alibabatech.com/svn/druid/trunk@9 b9813039-fb51-4c41-a8b9-e21c2acb5095 --- .../com/alibaba/druid/util/IntHashMap.java | 922 ------------------ .../com/alibaba/druid/util/LongHashMap.java | 850 ---------------- 2 files changed, 1772 deletions(-) delete mode 100644 src/main/java/com/alibaba/druid/util/IntHashMap.java delete mode 100644 src/main/java/com/alibaba/druid/util/LongHashMap.java diff --git a/src/main/java/com/alibaba/druid/util/IntHashMap.java b/src/main/java/com/alibaba/druid/util/IntHashMap.java deleted file mode 100644 index 9cb9c3367c..0000000000 --- a/src/main/java/com/alibaba/druid/util/IntHashMap.java +++ /dev/null @@ -1,922 +0,0 @@ -/* - * Copyright 2011 Alibaba Group. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.alibaba.druid.util; - -import java.io.IOException; -import java.io.Serializable; -import java.util.AbstractCollection; -import java.util.AbstractSet; -import java.util.Collection; -import java.util.ConcurrentModificationException; -import java.util.Iterator; -import java.util.Map; -import java.util.NoSuchElementException; -import java.util.Set; - -public class IntHashMap implements Map, Cloneable, Serializable { - - /** - * The default initial capacity - MUST be a power of two. - */ - static final int DEFAULT_INITIAL_CAPACITY = 16; - - /** - * The maximum capacity, used if a higher value is implicitly specified - * by either of the constructors with arguments. - * MUST be a power of two <= 1<<30. - */ - static final int MAXIMUM_CAPACITY = 1 << 30; - - /** - * The load factor used when none specified in constructor. - */ - static final float DEFAULT_LOAD_FACTOR = 0.75f; - - /** - * The table, resized as necessary. Length MUST Always be a power of two. - */ - transient Entry[] table; - - /** - * The number of key-value mappings contained in this map. - */ - transient int size; - - /** - * The next size value at which to resize (capacity * load factor). - * @serial - */ - int threshold; - - /** - * The load factor for the hash table. - * - * @serial - */ - final float loadFactor; - - /** - * The number of times this HashMap has been structurally modified - * Structural modifications are those that change the number of mappings in - * the HashMap or otherwise modify its internal structure (e.g., - * rehash). This field is used to make iterators on Collection-views of - * the HashMap fail-fast. (See ConcurrentModificationException). - */ - transient volatile int modCount; - - transient volatile Set keySet = null; - transient volatile Collection values = null; - - /** - * Constructs an empty HashMap with the specified initial - * capacity and load factor. - * - * @param initialCapacity the initial capacity - * @param loadFactor the load factor - * @throws IllegalArgumentException if the initial capacity is negative - * or the load factor is nonpositive - */ - @SuppressWarnings("unchecked") - public IntHashMap(int initialCapacity, float loadFactor) { - if (initialCapacity < 0) - throw new IllegalArgumentException("Illegal initial capacity: " + - initialCapacity); - if (initialCapacity > MAXIMUM_CAPACITY) - initialCapacity = MAXIMUM_CAPACITY; - if (loadFactor <= 0 || Float.isNaN(loadFactor)) - throw new IllegalArgumentException("Illegal load factor: " + - loadFactor); - - // Find a power of 2 >= initialCapacity - int capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; - - this.loadFactor = loadFactor; - threshold = (int)(capacity * loadFactor); - table = new Entry[capacity]; - init(); - } - - /** - * Constructs an empty HashMap with the specified initial - * capacity and the default load factor (0.75). - * - * @param initialCapacity the initial capacity. - * @throws IllegalArgumentException if the initial capacity is negative. - */ - public IntHashMap(int initialCapacity) { - this(initialCapacity, DEFAULT_LOAD_FACTOR); - } - - /** - * Constructs an empty HashMap with the default initial capacity - * (16) and the default load factor (0.75). - */ - @SuppressWarnings("unchecked") - public IntHashMap() { - this.loadFactor = DEFAULT_LOAD_FACTOR; - threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); - table = new Entry[DEFAULT_INITIAL_CAPACITY]; - init(); - } - - /** - * Constructs a new HashMap with the same mappings as the - * specified Map. The HashMap is created with - * default load factor (0.75) and an initial capacity sufficient to - * hold the mappings in the specified Map. - * - * @param m the map whose mappings are to be placed in this map - * @throws NullPointerException if the specified map is null - */ - public IntHashMap(Map m) { - this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, - DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); - putAllForCreate(m); - } - - // internal utilities - - /** - * Initialization hook for subclasses. This method is called - * in all constructors and pseudo-constructors (clone, readObject) - * after HashMap has been initialized but before any entries have - * been inserted. (In the absence of this method, readObject would - * require explicit knowledge of subclasses.) - */ - void init() { - } - - /** - * Applies a supplemental hash function to a given hashCode, which - * defends against poor quality hash functions. This is critical - * because HashMap uses power-of-two length hash tables, that - * otherwise encounter collisions for hashCodes that do not differ - * in lower bits. Note: Null keys always map to hash 0, thus index 0. - */ - - - /** - * Returns index for hash code h. - */ - static int indexFor(int h, int length) { - return h & (length-1); - } - - /** - * Returns the number of key-value mappings in this map. - * - * @return the number of key-value mappings in this map - */ - public int size() { - return size; - } - - /** - * Returns true if this map contains no key-value mappings. - * - * @return true if this map contains no key-value mappings - */ - public boolean isEmpty() { - return size == 0; - } - - /** - * Returns the value to which the specified key is mapped, - * or {@code null} if this map contains no mapping for the key. - * - *

More formally, if this map contains a mapping from a key - * {@code k} to a value {@code v} such that {@code (key==null ? k==null : - * key.equals(k))}, then this method returns {@code v}; otherwise - * it returns {@code null}. (There can be at most one such mapping.) - * - *

A return value of {@code null} does not necessarily - * indicate that the map contains no mapping for the key; it's also - * possible that the map explicitly maps the key to {@code null}. - * The {@link #containsKey containsKey} operation may be used to - * distinguish these two cases. - * - * @see #put(Object, Object) - */ - public V get(Object key) { - return get(((Integer) key).intValue()); - } - - public V get(int key) { - int hash = key; - for (Entry e = table[indexFor(hash, table.length)]; - e != null; - e = e.next) { - if (e.hash == hash && e.key == key) - return e.value; - } - return null; - } - - /** - * Returns true if this map contains a mapping for the - * specified key. - * - * @param key The key whose presence in this map is to be tested - * @return true if this map contains a mapping for the specified - * key. - */ - public boolean containsKey(Object key) { - return containsKey(((Integer)key).intValue()); - } - - public boolean containsKey(int key) { - return getEntry(key) != null; - } - - /** - * Returns the entry associated with the specified key in the - * HashMap. Returns null if the HashMap contains no mapping - * for the key. - */ - final Entry getEntry(int key) { - int hash = key; - for (Entry e = table[indexFor(hash, table.length)]; - e != null; - e = e.next) { - if (e.hash == hash && key == e.key) - return e; - } - return null; - } - - - /** - * Associates the specified value with the specified key in this map. - * If the map previously contained a mapping for the key, the old - * value is replaced. - * - * @param key key with which the specified value is to be associated - * @param value value to be associated with the specified key - * @return the previous value associated with key, or - * null if there was no mapping for key. - * (A null return can also indicate that the map - * previously associated null with key.) - */ - public V put(Integer key, V value) { - return put(key.intValue(), value); - } - - public V put(int key, V value) { - int hash = key; - int i = indexFor(hash, table.length); - for (Entry e = table[i]; e != null; e = e.next) { - if (e.hash == hash && (e.key == key)) { - V oldValue = e.value; - e.value = value; - return oldValue; - } - } - - modCount++; - addEntry(hash, key, value, i); - return null; - } - - /** - * This method is used instead of put by constructors and - * pseudoconstructors (clone, readObject). It does not resize the table, - * check for comodification, etc. It calls createEntry rather than - * addEntry. - */ - private void putForCreate(int key, V value) { - int hash = key; - int i = indexFor(hash, table.length); - - /** - * Look for preexisting entry for key. This will never happen for - * clone or deserialize. It will only happen for construction if the - * input Map is a sorted map whose ordering is inconsistent w/ equals. - */ - for (Entry e = table[i]; e != null; e = e.next) { - if (e.hash == hash && key == e.key) { - e.value = value; - return; - } - } - - createEntry(hash, key, value, i); - } - - private void putAllForCreate(Map m) { - for (Iterator> i = m.entrySet().iterator(); i.hasNext(); ) { - Map.Entry e = i.next(); - putForCreate(e.getKey(), e.getValue()); - } - } - - /** - * Rehashes the contents of this map into a new array with a - * larger capacity. This method is called automatically when the - * number of keys in this map reaches its threshold. - * - * If current capacity is MAXIMUM_CAPACITY, this method does not - * resize the map, but sets threshold to Integer.MAX_VALUE. - * This has the effect of preventing future calls. - * - * @param newCapacity the new capacity, MUST be a power of two; - * must be greater than current capacity unless current - * capacity is MAXIMUM_CAPACITY (in which case value - * is irrelevant). - */ - @SuppressWarnings("unchecked") - void resize(int newCapacity) { - Entry[] oldTable = table; - int oldCapacity = oldTable.length; - if (oldCapacity == MAXIMUM_CAPACITY) { - threshold = Integer.MAX_VALUE; - return; - } - - Entry[] newTable = new Entry[newCapacity]; - transfer(newTable); - table = newTable; - threshold = (int)(newCapacity * loadFactor); - } - - /** - * Transfers all entries from current table to newTable. - */ - void transfer(Entry[] newTable) { - Entry[] src = table; - int newCapacity = newTable.length; - for (int j = 0; j < src.length; j++) { - Entry e = src[j]; - if (e != null) { - src[j] = null; - do { - Entry next = e.next; - int i = indexFor(e.hash, newCapacity); - e.next = newTable[i]; - newTable[i] = e; - e = next; - } while (e != null); - } - } - } - - /** - * Copies all of the mappings from the specified map to this map. - * These mappings will replace any mappings that this map had for - * any of the keys currently in the specified map. - * - * @param m mappings to be stored in this map - * @throws NullPointerException if the specified map is null - */ - public void putAll(Map m) { - int numKeysToBeAdded = m.size(); - if (numKeysToBeAdded == 0) - return; - - /* - * Expand the map if the map if the number of mappings to be added - * is greater than or equal to threshold. This is conservative; the - * obvious condition is (m.size() + size) >= threshold, but this - * condition could result in a map with twice the appropriate capacity, - * if the keys to be added overlap with the keys already in this map. - * By using the conservative calculation, we subject ourself - * to at most one extra resize. - */ - if (numKeysToBeAdded > threshold) { - int targetCapacity = (int)(numKeysToBeAdded / loadFactor + 1); - if (targetCapacity > MAXIMUM_CAPACITY) - targetCapacity = MAXIMUM_CAPACITY; - int newCapacity = table.length; - while (newCapacity < targetCapacity) - newCapacity <<= 1; - if (newCapacity > table.length) - resize(newCapacity); - } - - for (Iterator> i = m.entrySet().iterator(); i.hasNext(); ) { - Map.Entry e = i.next(); - put(e.getKey(), e.getValue()); - } - } - - /** - * Removes the mapping for the specified key from this map if present. - * - * @param key key whose mapping is to be removed from the map - * @return the previous value associated with key, or - * null if there was no mapping for key. - * (A null return can also indicate that the map - * previously associated null with key.) - */ - public V remove(Object key) { - return remove(((Integer) key).intValue()); - } - - public V remove(int key) { - Entry e = removeEntryForKey(key); - return (e == null ? null : e.value); - } - - /** - * Removes and returns the entry associated with the specified key - * in the HashMap. Returns null if the HashMap contains no mapping - * for this key. - */ - final Entry removeEntryForKey(int key) { - int hash = key; - int i = indexFor(hash, table.length); - Entry prev = table[i]; - Entry e = prev; - - while (e != null) { - Entry next = e.next; - if (e.hash == hash && key == e.key) { - modCount++; - size--; - if (prev == e) - table[i] = next; - else - prev.next = next; - return e; - } - prev = e; - e = next; - } - - return e; - } - - /** - * Special version of remove for EntrySet. - */ - @SuppressWarnings("unchecked") - final Entry removeMapping(Object o) { - if (!(o instanceof Map.Entry)) - return null; - - Map.Entry entry = (Map.Entry) o; - int key = ((Integer)entry.getKey()).intValue(); - int hash = key; - int i = indexFor(hash, table.length); - Entry prev = table[i]; - Entry e = prev; - - while (e != null) { - Entry next = e.next; - if (e.hash == hash && e.equals(entry)) { - modCount++; - size--; - if (prev == e) - table[i] = next; - else - prev.next = next; - return e; - } - prev = e; - e = next; - } - - return e; - } - - /** - * Removes all of the mappings from this map. - * The map will be empty after this call returns. - */ - public void clear() { - modCount++; - Entry[] tab = table; - for (int i = 0; i < tab.length; i++) - tab[i] = null; - size = 0; - } - - /** - * Returns true if this map maps one or more keys to the - * specified value. - * - * @param value value whose presence in this map is to be tested - * @return true if this map maps one or more keys to the - * specified value - */ - public boolean containsValue(Object value) { - if (value == null) - return containsNullValue(); - - Entry[] tab = table; - for (int i = 0; i < tab.length ; i++) - for (Entry e = tab[i] ; e != null ; e = e.next) - if (value.equals(e.value)) - return true; - return false; - } - - /** - * Special-case code for containsValue with null argument - */ - private boolean containsNullValue() { - Entry[] tab = table; - for (int i = 0; i < tab.length ; i++) - for (Entry e = tab[i] ; e != null ; e = e.next) - if (e.value == null) - return true; - return false; - } - - /** - * Returns a shallow copy of this HashMap instance: the keys and - * values themselves are not cloned. - * - * @return a shallow copy of this map - */ - @SuppressWarnings("unchecked") - public Object clone() { - IntHashMap result = null; - try { - result = (IntHashMap)super.clone(); - } catch (CloneNotSupportedException e) { - // assert false; - } - result.table = new Entry[table.length]; - result.entrySet = null; - result.modCount = 0; - result.size = 0; - result.init(); - result.putAllForCreate(this); - - return result; - } - - static class Entry implements Map.Entry { - final int key; - V value; - Entry next; - final int hash; - - /** - * Creates new entry. - */ - Entry(int h, int k, V v, Entry n) { - value = v; - next = n; - key = k; - hash = h; - } - - public final Integer getKey() { - return key; - } - - public final int getIntKey() { - return key; - } - - public final V getValue() { - return value; - } - - public final V setValue(V newValue) { - V oldValue = value; - value = newValue; - return oldValue; - } - - @SuppressWarnings("rawtypes") - public final boolean equals(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry)o; - Object k1 = getKey(); - Object k2 = e.getKey(); - if (k1 == k2 || (k1 != null && k1.equals(k2))) { - Object v1 = getValue(); - Object v2 = e.getValue(); - if (v1 == v2 || (v1 != null && v1.equals(v2))) - return true; - } - return false; - } - - public final int hashCode() { - return hash; - } - - public final String toString() { - return getKey() + "=" + getValue(); - } - - } - - /** - * Adds a new entry with the specified key, value and hash code to - * the specified bucket. It is the responsibility of this - * method to resize the table if appropriate. - * - * Subclass overrides this to alter the behavior of put method. - */ - void addEntry(int hash, Integer key, V value, int bucketIndex) { - Entry e = table[bucketIndex]; - table[bucketIndex] = new Entry(hash, key, value, e); - if (size++ >= threshold) - resize(2 * table.length); - } - - /** - * Like addEntry except that this version is used when creating entries - * as part of Map construction or "pseudo-construction" (cloning, - * deserialization). This version needn't worry about resizing the table. - * - * Subclass overrides this to alter the behavior of HashMap(Map), - * clone, and readObject. - */ - void createEntry(int hash, int key, V value, int bucketIndex) { - Entry e = table[bucketIndex]; - table[bucketIndex] = new Entry(hash, key, value, e); - size++; - } - - private abstract class HashIterator implements Iterator { - Entry next; // next entry to return - int expectedModCount; // For fast-fail - int index; // current slot - Entry current; // current entry - - HashIterator() { - expectedModCount = modCount; - if (size > 0) { // advance to first entry - Entry[] t = table; - while (index < t.length && (next = t[index++]) == null) - ; - } - } - - public final boolean hasNext() { - return next != null; - } - - final Entry nextEntry() { - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); - Entry e = next; - if (e == null) - throw new NoSuchElementException(); - - if ((next = e.next) == null) { - Entry[] t = table; - while (index < t.length && (next = t[index++]) == null) - ; - } - current = e; - return e; - } - - public void remove() { - if (current == null) - throw new IllegalStateException(); - if (modCount != expectedModCount) - throw new ConcurrentModificationException(); - int k = current.key; - current = null; - IntHashMap.this.removeEntryForKey(k); - expectedModCount = modCount; - } - - } - - private final class ValueIterator extends HashIterator { - public V next() { - return nextEntry().value; - } - } - - private final class KeyIterator extends HashIterator { - public Integer next() { - return nextEntry().getKey(); - } - } - - private final class EntryIterator extends HashIterator> { - public Map.Entry next() { - return nextEntry(); - } - } - - // Subclass overrides these to alter behavior of views' iterator() method - Iterator newKeyIterator() { - return new KeyIterator(); - } - Iterator newValueIterator() { - return new ValueIterator(); - } - Iterator> newEntryIterator() { - return new EntryIterator(); - } - - - // Views - - private transient Set> entrySet = null; - - /** - * Returns a {@link Set} view of the keys contained in this map. - * The set is backed by the map, so changes to the map are - * reflected in the set, and vice-versa. If the map is modified - * while an iteration over the set is in progress (except through - * the iterator's own remove operation), the results of - * the iteration are undefined. The set supports element removal, - * which removes the corresponding mapping from the map, via the - * Iterator.remove, Set.remove, - * removeAll, retainAll, and clear - * operations. It does not support the add or addAll - * operations. - */ - public Set keySet() { - Set ks = keySet; - return (ks != null ? ks : (keySet = new KeySet())); - } - - private final class KeySet extends AbstractSet { - public Iterator iterator() { - return newKeyIterator(); - } - public int size() { - return size; - } - public boolean contains(Object o) { - return containsKey(o); - } - - public boolean remove(Object o) { - return IntHashMap.this.removeEntryForKey(((Integer)o).intValue()) != null; - } - - public void clear() { - IntHashMap.this.clear(); - } - } - - /** - * Returns a {@link Collection} view of the values contained in this map. - * The collection is backed by the map, so changes to the map are - * reflected in the collection, and vice-versa. If the map is - * modified while an iteration over the collection is in progress - * (except through the iterator's own remove operation), - * the results of the iteration are undefined. The collection - * supports element removal, which removes the corresponding - * mapping from the map, via the Iterator.remove, - * Collection.remove, removeAll, - * retainAll and clear operations. It does not - * support the add or addAll operations. - */ - public Collection values() { - Collection vs = values; - return (vs != null ? vs : (values = new Values())); - } - - private final class Values extends AbstractCollection { - public Iterator iterator() { - return newValueIterator(); - } - public int size() { - return size; - } - public boolean contains(Object o) { - return containsValue(o); - } - public void clear() { - IntHashMap.this.clear(); - } - } - - /** - * Returns a {@link Set} view of the mappings contained in this map. - * The set is backed by the map, so changes to the map are - * reflected in the set, and vice-versa. If the map is modified - * while an iteration over the set is in progress (except through - * the iterator's own remove operation, or through the - * setValue operation on a map entry returned by the - * iterator) the results of the iteration are undefined. The set - * supports element removal, which removes the corresponding - * mapping from the map, via the Iterator.remove, - * Set.remove, removeAll, retainAll and - * clear operations. It does not support the - * add or addAll operations. - * - * @return a set view of the mappings contained in this map - */ - public Set> entrySet() { - return entrySet0(); - } - - private Set> entrySet0() { - Set> es = entrySet; - return es != null ? es : (entrySet = new EntrySet()); - } - - private final class EntrySet extends AbstractSet> { - public Iterator> iterator() { - return newEntryIterator(); - } - @SuppressWarnings("unchecked") - public boolean contains(Object o) { - if (!(o instanceof Map.Entry)) - return false; - Map.Entry e = (Map.Entry) o; - Entry candidate = getEntry(e.getKey()); - return candidate != null && candidate.equals(e); - } - public boolean remove(Object o) { - return removeMapping(o) != null; - } - public int size() { - return size; - } - public void clear() { - IntHashMap.this.clear(); - } - } - - /** - * Save the state of the HashMap instance to a stream (i.e., - * serialize it). - * - * @serialData The capacity of the HashMap (the length of the - * bucket array) is emitted (int), followed by the - * size (an int, the number of key-value - * mappings), followed by the key (Object) and value (Object) - * for each key-value mapping. The key-value mappings are - * emitted in no particular order. - */ - private void writeObject(java.io.ObjectOutputStream s) - throws IOException - { - Iterator> i = - (size > 0) ? entrySet0().iterator() : null; - - // Write out the threshold, loadfactor, and any hidden stuff - s.defaultWriteObject(); - - // Write out number of buckets - s.writeInt(table.length); - - // Write out size (number of Mappings) - s.writeInt(size); - - // Write out keys and values (alternating) - if (i != null) { - while (i.hasNext()) { - Map.Entry e = i.next(); - s.writeInt(e.getKey()); - s.writeObject(e.getValue()); - } - } - } - - private static final long serialVersionUID = 362498820763181265L; - - /** - * Reconstitute the HashMap instance from a stream (i.e., - * deserialize it). - */ - @SuppressWarnings("unchecked") - private void readObject(java.io.ObjectInputStream s) - throws IOException, ClassNotFoundException - { - // Read in the threshold, loadfactor, and any hidden stuff - s.defaultReadObject(); - - // Read in number of buckets and allocate the bucket array; - int numBuckets = s.readInt(); - table = new Entry[numBuckets]; - - init(); // Give subclass a chance to do its thing. - - // Read in size (number of Mappings) - int size = s.readInt(); - - // Read the keys and values, and put the mappings in the HashMap - for (int i=0; i implements Map, Cloneable, Serializable { - - /** - * The default initial capacity - MUST be a power of two. - */ - static final int DEFAULT_INITIAL_CAPACITY = 16; - - /** - * The maximum capacity, used if a higher value is implicitly specified by either of the constructors with - * arguments. MUST be a power of two <= 1<<30. - */ - static final int MAXIMUM_CAPACITY = 1 << 30; - - /** - * The load factor used when none specified in constructor. - */ - static final float DEFAULT_LOAD_FACTOR = 0.75f; - - /** - * The table, resized as necessary. Length MUST Always be a power of two. - */ - transient Entry[] table; - - /** - * The number of key-value mappings contained in this map. - */ - transient int size; - - /** - * The next size value at which to resize (capacity * load factor). - * - * @serial - */ - int threshold; - - /** - * The load factor for the hash table. - * - * @serial - */ - final float loadFactor; - - /** - * The number of times this HashMap has been structurally modified Structural modifications are those that change - * the number of mappings in the HashMap or otherwise modify its internal structure (e.g., rehash). This field is - * used to make iterators on Collection-views of the HashMap fail-fast. (See ConcurrentModificationException). - */ - transient volatile int modCount; - - transient volatile Set keySet = null; - transient volatile Collection values = null; - - /** - * Constructs an empty HashMap with the specified initial capacity and load factor. - * - * @param initialCapacity the initial capacity - * @param loadFactor the load factor - * @throws IllegalArgumentException if the initial capacity is negative or the load factor is nonpositive - */ - @SuppressWarnings("unchecked") - public LongHashMap(int initialCapacity, float loadFactor){ - if (initialCapacity < 0) throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity); - if (initialCapacity > MAXIMUM_CAPACITY) initialCapacity = MAXIMUM_CAPACITY; - if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal load factor: " - + loadFactor); - - // Find a power of 2 >= initialCapacity - int capacity = 1; - while (capacity < initialCapacity) - capacity <<= 1; - - this.loadFactor = loadFactor; - threshold = (int) (capacity * loadFactor); - table = new Entry[capacity]; - init(); - } - - /** - * Constructs an empty HashMap with the specified initial capacity and the default load factor (0.75). - * - * @param initialCapacity the initial capacity. - * @throws IllegalArgumentException if the initial capacity is negative. - */ - public LongHashMap(int initialCapacity){ - this(initialCapacity, DEFAULT_LOAD_FACTOR); - } - - /** - * Constructs an empty HashMap with the default initial capacity (16) and the default load factor (0.75). - */ - @SuppressWarnings("unchecked") - public LongHashMap(){ - this.loadFactor = DEFAULT_LOAD_FACTOR; - threshold = (int) (DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR); - table = new Entry[DEFAULT_INITIAL_CAPACITY]; - init(); - } - - /** - * Constructs a new HashMap with the same mappings as the specified Map. The HashMap is - * created with default load factor (0.75) and an initial capacity sufficient to hold the mappings in the specified - * Map. - * - * @param m the map whose mappings are to be placed in this map - * @throws NullPointerException if the specified map is null - */ - public LongHashMap(Map m){ - this(Math.max((int) (m.size() / DEFAULT_LOAD_FACTOR) + 1, DEFAULT_INITIAL_CAPACITY), DEFAULT_LOAD_FACTOR); - putAllForCreate(m); - } - - // internal utilities - - /** - * Initialization hook for subclasses. This method is called in all constructors and pseudo-constructors (clone, - * readObject) after HashMap has been initialized but before any entries have been inserted. (In the absence of this - * method, readObject would require explicit knowledge of subclasses.) - */ - void init() { - } - - /** - * Applies a supplemental hash function to a given hashCode, which defends against poor quality hash functions. This - * is critical because HashMap uses power-of-two length hash tables, that otherwise encounter collisions for - * hashCodes that do not differ in lower bits. Note: Null keys always map to hash 0, thus index 0. - */ - - /** - * Returns index for hash code h. - */ - static int indexFor(int h, int length) { - return h & (length - 1); - } - - /** - * Returns the number of key-value mappings in this map. - * - * @return the number of key-value mappings in this map - */ - public int size() { - return size; - } - - /** - * Returns true if this map contains no key-value mappings. - * - * @return true if this map contains no key-value mappings - */ - public boolean isEmpty() { - return size == 0; - } - - /** - * Returns the value to which the specified key is mapped, or {@code null} if this map contains no mapping for the - * key. - *

- * More formally, if this map contains a mapping from a key {@code k} to a value {@code v} such that - * {@code (key==null ? k==null : - * key.equals(k))}, then this method returns {@code v}; otherwise it returns {@code null}. (There can be at most one - * such mapping.) - *

- * A return value of {@code null} does not necessarily indicate that the map contains no mapping for the key; - * it's also possible that the map explicitly maps the key to {@code null}. The {@link #containsKey containsKey} - * operation may be used to distinguish these two cases. - * - * @see #put(Object, Object) - */ - public V get(Object key) { - return get(((Long) key).intValue()); - } - - public V get(int key) { - int hash = key; - for (Entry e = table[indexFor(hash, table.length)]; e != null; e = e.next) { - if (e.hash == hash && e.key == key) return e.value; - } - return null; - } - - /** - * Returns true if this map contains a mapping for the specified key. - * - * @param key The key whose presence in this map is to be tested - * @return true if this map contains a mapping for the specified key. - */ - public boolean containsKey(Object key) { - return containsKey(((Long) key).intValue()); - } - - public boolean containsKey(int key) { - return getEntry(key) != null; - } - - /** - * Returns the entry associated with the specified key in the HashMap. Returns null if the HashMap contains no - * mapping for the key. - */ - final Entry getEntry(long key) { - int hash = hash(key); - for (Entry e = table[indexFor(hash, table.length)]; e != null; e = e.next) { - if (e.hash == hash && key == e.key) return e; - } - return null; - } - - /** - * Associates the specified value with the specified key in this map. If the map previously contained a mapping for - * the key, the old value is replaced. - * - * @param key key with which the specified value is to be associated - * @param value value to be associated with the specified key - * @return the previous value associated with key, or null if there was no mapping for - * key. (A null return can also indicate that the map previously associated null with - * key.) - */ - public V put(Long key, V value) { - return put(key.intValue(), value); - } - - static int hash(long value) { - return (int) (value ^ (value >>> 32)); - } - - public V put(long key, V value) { - int hash = hash(key); - int i = indexFor(hash, table.length); - for (Entry e = table[i]; e != null; e = e.next) { - if (e.hash == hash && (e.key == key)) { - V oldValue = e.value; - e.value = value; - return oldValue; - } - } - - modCount++; - addEntry(hash, key, value, i); - return null; - } - - /** - * This method is used instead of put by constructors and pseudoconstructors (clone, readObject). It does not resize - * the table, check for comodification, etc. It calls createEntry rather than addEntry. - */ - private void putForCreate(long key, V value) { - int hash = hash(key); - int i = indexFor(hash, table.length); - - /** - * Look for preexisting entry for key. This will never happen for clone or deserialize. It will only happen for - * construction if the input Map is a sorted map whose ordering is inconsistent w/ equals. - */ - for (Entry e = table[i]; e != null; e = e.next) { - if (e.hash == hash && key == e.key) { - e.value = value; - return; - } - } - - createEntry(hash, key, value, i); - } - - private void putAllForCreate(Map m) { - for (Iterator> i = m.entrySet().iterator(); i.hasNext();) { - Map.Entry e = i.next(); - putForCreate(e.getKey(), e.getValue()); - } - } - - /** - * Rehashes the contents of this map into a new array with a larger capacity. This method is called automatically - * when the number of keys in this map reaches its threshold. If current capacity is MAXIMUM_CAPACITY, this method - * does not resize the map, but sets threshold to Long.MAX_VALUE. This has the effect of preventing future calls. - * - * @param newCapacity the new capacity, MUST be a power of two; must be greater than current capacity unless current - * capacity is MAXIMUM_CAPACITY (in which case value is irrelevant). - */ - @SuppressWarnings("unchecked") - void resize(int newCapacity) { - Entry[] oldTable = table; - int oldCapacity = oldTable.length; - if (oldCapacity == MAXIMUM_CAPACITY) { - threshold = Integer.MAX_VALUE; - return; - } - - Entry[] newTable = new Entry[newCapacity]; - transfer(newTable); - table = newTable; - threshold = (int) (newCapacity * loadFactor); - } - - /** - * Transfers all entries from current table to newTable. - */ - void transfer(Entry[] newTable) { - Entry[] src = table; - int newCapacity = newTable.length; - for (int j = 0; j < src.length; j++) { - Entry e = src[j]; - if (e != null) { - src[j] = null; - do { - Entry next = e.next; - int i = indexFor(e.hash, newCapacity); - e.next = newTable[i]; - newTable[i] = e; - e = next; - } while (e != null); - } - } - } - - /** - * Copies all of the mappings from the specified map to this map. These mappings will replace any mappings that this - * map had for any of the keys currently in the specified map. - * - * @param m mappings to be stored in this map - * @throws NullPointerException if the specified map is null - */ - public void putAll(Map m) { - int numKeysToBeAdded = m.size(); - if (numKeysToBeAdded == 0) return; - - /* - * Expand the map if the map if the number of mappings to be added is greater than or equal to threshold. This - * is conservative; the obvious condition is (m.size() + size) >= threshold, but this condition could result in - * a map with twice the appropriate capacity, if the keys to be added overlap with the keys already in this map. - * By using the conservative calculation, we subject ourself to at most one extra resize. - */ - if (numKeysToBeAdded > threshold) { - int targetCapacity = (int) (numKeysToBeAdded / loadFactor + 1); - if (targetCapacity > MAXIMUM_CAPACITY) targetCapacity = MAXIMUM_CAPACITY; - int newCapacity = table.length; - while (newCapacity < targetCapacity) - newCapacity <<= 1; - if (newCapacity > table.length) resize(newCapacity); - } - - for (Iterator> i = m.entrySet().iterator(); i.hasNext();) { - Map.Entry e = i.next(); - put(e.getKey(), e.getValue()); - } - } - - /** - * Removes the mapping for the specified key from this map if present. - * - * @param key key whose mapping is to be removed from the map - * @return the previous value associated with key, or null if there was no mapping for - * key. (A null return can also indicate that the map previously associated null with - * key.) - */ - public V remove(Object key) { - return remove(((Long) key).intValue()); - } - - public V remove(int key) { - Entry e = removeEntryForKey(key); - return (e == null ? null : e.value); - } - - /** - * Removes and returns the entry associated with the specified key in the HashMap. Returns null if the HashMap - * contains no mapping for this key. - */ - final Entry removeEntryForKey(long key) { - int hash = hash(key); - int i = indexFor(hash, table.length); - Entry prev = table[i]; - Entry e = prev; - - while (e != null) { - Entry next = e.next; - if (e.hash == hash && key == e.key) { - modCount++; - size--; - if (prev == e) table[i] = next; - else prev.next = next; - return e; - } - prev = e; - e = next; - } - - return e; - } - - /** - * Special version of remove for EntrySet. - */ - @SuppressWarnings("unchecked") - final Entry removeMapping(Object o) { - if (!(o instanceof Map.Entry)) return null; - - Map.Entry entry = (Map.Entry) o; - int key = ((Long) entry.getKey()).intValue(); - int hash = key; - int i = indexFor(hash, table.length); - Entry prev = table[i]; - Entry e = prev; - - while (e != null) { - Entry next = e.next; - if (e.hash == hash && e.equals(entry)) { - modCount++; - size--; - if (prev == e) table[i] = next; - else prev.next = next; - return e; - } - prev = e; - e = next; - } - - return e; - } - - /** - * Removes all of the mappings from this map. The map will be empty after this call returns. - */ - public void clear() { - modCount++; - Entry[] tab = table; - for (int i = 0; i < tab.length; i++) - tab[i] = null; - size = 0; - } - - /** - * Returns true if this map maps one or more keys to the specified value. - * - * @param value value whose presence in this map is to be tested - * @return true if this map maps one or more keys to the specified value - */ - public boolean containsValue(Object value) { - if (value == null) return containsNullValue(); - - Entry[] tab = table; - for (int i = 0; i < tab.length; i++) - for (Entry e = tab[i]; e != null; e = e.next) - if (value.equals(e.value)) return true; - return false; - } - - /** - * Special-case code for containsValue with null argument - */ - private boolean containsNullValue() { - Entry[] tab = table; - for (int i = 0; i < tab.length; i++) - for (Entry e = tab[i]; e != null; e = e.next) - if (e.value == null) return true; - return false; - } - - /** - * Returns a shallow copy of this HashMap instance: the keys and values themselves are not cloned. - * - * @return a shallow copy of this map - */ - @SuppressWarnings("unchecked") - public Object clone() { - LongHashMap result = null; - try { - result = (LongHashMap) super.clone(); - } catch (CloneNotSupportedException e) { - // assert false; - } - result.table = new Entry[table.length]; - result.entrySet = null; - result.modCount = 0; - result.size = 0; - result.init(); - result.putAllForCreate(this); - - return result; - } - - static class Entry implements Map.Entry { - - final long key; - V value; - Entry next; - final int hash; - - /** - * Creates new entry. - */ - Entry(int h, long k, V v, Entry n){ - value = v; - next = n; - key = k; - hash = h; - } - - public final Long getKey() { - return key; - } - - public final long getIntKey() { - return key; - } - - public final V getValue() { - return value; - } - - public final V setValue(V newValue) { - V oldValue = value; - value = newValue; - return oldValue; - } - - @SuppressWarnings("rawtypes") - public final boolean equals(Object o) { - if (!(o instanceof Map.Entry)) return false; - Map.Entry e = (Map.Entry) o; - Object k1 = getKey(); - Object k2 = e.getKey(); - if (k1 == k2 || (k1 != null && k1.equals(k2))) { - Object v1 = getValue(); - Object v2 = e.getValue(); - if (v1 == v2 || (v1 != null && v1.equals(v2))) return true; - } - return false; - } - - public final int hashCode() { - return hash; - } - - public final String toString() { - return getKey() + "=" + getValue(); - } - - } - - /** - * Adds a new entry with the specified key, value and hash code to the specified bucket. It is the responsibility of - * this method to resize the table if appropriate. Subclass overrides this to alter the behavior of put method. - */ - void addEntry(int hash, Long key, V value, int bucketIndex) { - Entry e = table[bucketIndex]; - table[bucketIndex] = new Entry(hash, key, value, e); - if (size++ >= threshold) resize(2 * table.length); - } - - /** - * Like addEntry except that this version is used when creating entries as part of Map construction or - * "pseudo-construction" (cloning, deserialization). This version needn't worry about resizing the table. Subclass - * overrides this to alter the behavior of HashMap(Map), clone, and readObject. - */ - void createEntry(int hash, long key, V value, int bucketIndex) { - Entry e = table[bucketIndex]; - table[bucketIndex] = new Entry(hash, key, value, e); - size++; - } - - private abstract class HashIterator implements Iterator { - - Entry next; // next entry to return - int expectedModCount; // For fast-fail - int index; // current slot - Entry current; // current entry - - HashIterator(){ - expectedModCount = modCount; - if (size > 0) { // advance to first entry - Entry[] t = table; - while (index < t.length && (next = t[index++]) == null) - ; - } - } - - public final boolean hasNext() { - return next != null; - } - - final Entry nextEntry() { - if (modCount != expectedModCount) throw new ConcurrentModificationException(); - Entry e = next; - if (e == null) throw new NoSuchElementException(); - - if ((next = e.next) == null) { - Entry[] t = table; - while (index < t.length && (next = t[index++]) == null) - ; - } - current = e; - return e; - } - - public void remove() { - if (current == null) throw new IllegalStateException(); - if (modCount != expectedModCount) throw new ConcurrentModificationException(); - long k = current.key; - current = null; - LongHashMap.this.removeEntryForKey(k); - expectedModCount = modCount; - } - - } - - private final class ValueIterator extends HashIterator { - - public V next() { - return nextEntry().value; - } - } - - private final class KeyIterator extends HashIterator { - - public Long next() { - return nextEntry().getKey(); - } - } - - private final class EntryIterator extends HashIterator> { - - public Map.Entry next() { - return nextEntry(); - } - } - - // Subclass overrides these to alter behavior of views' iterator() method - Iterator newKeyIterator() { - return new KeyIterator(); - } - - Iterator newValueIterator() { - return new ValueIterator(); - } - - Iterator> newEntryIterator() { - return new EntryIterator(); - } - - // Views - - private transient Set> entrySet = null; - - /** - * Returns a {@link Set} view of the keys contained in this map. The set is backed by the map, so changes to the map - * are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in progress - * (except through the iterator's own remove operation), the results of the iteration are undefined. The - * set supports element removal, which removes the corresponding mapping from the map, via the - * Iterator.remove, Set.remove, removeAll, retainAll, and clear - * operations. It does not support the add or addAll operations. - */ - public Set keySet() { - Set ks = keySet; - return (ks != null ? ks : (keySet = new KeySet())); - } - - private final class KeySet extends AbstractSet { - - public Iterator iterator() { - return newKeyIterator(); - } - - public int size() { - return size; - } - - public boolean contains(Object o) { - return containsKey(o); - } - - public boolean remove(Object o) { - return LongHashMap.this.removeEntryForKey(((Long) o).intValue()) != null; - } - - public void clear() { - LongHashMap.this.clear(); - } - } - - /** - * Returns a {@link Collection} view of the values contained in this map. The collection is backed by the map, so - * changes to the map are reflected in the collection, and vice-versa. If the map is modified while an iteration - * over the collection is in progress (except through the iterator's own remove operation), the results of - * the iteration are undefined. The collection supports element removal, which removes the corresponding mapping - * from the map, via the Iterator.remove, Collection.remove, removeAll, - * retainAll and clear operations. It does not support the add or addAll - * operations. - */ - public Collection values() { - Collection vs = values; - return (vs != null ? vs : (values = new Values())); - } - - private final class Values extends AbstractCollection { - - public Iterator iterator() { - return newValueIterator(); - } - - public int size() { - return size; - } - - public boolean contains(Object o) { - return containsValue(o); - } - - public void clear() { - LongHashMap.this.clear(); - } - } - - /** - * Returns a {@link Set} view of the mappings contained in this map. The set is backed by the map, so changes to the - * map are reflected in the set, and vice-versa. If the map is modified while an iteration over the set is in - * progress (except through the iterator's own remove operation, or through the setValue operation - * on a map entry returned by the iterator) the results of the iteration are undefined. The set supports element - * removal, which removes the corresponding mapping from the map, via the Iterator.remove, - * Set.remove, removeAll, retainAll and clear operations. It does not support - * the add or addAll operations. - * - * @return a set view of the mappings contained in this map - */ - public Set> entrySet() { - return entrySet0(); - } - - private Set> entrySet0() { - Set> es = entrySet; - return es != null ? es : (entrySet = new EntrySet()); - } - - private final class EntrySet extends AbstractSet> { - - public Iterator> iterator() { - return newEntryIterator(); - } - - @SuppressWarnings("unchecked") - public boolean contains(Object o) { - if (!(o instanceof Map.Entry)) return false; - Map.Entry e = (Map.Entry) o; - Entry candidate = getEntry(e.getKey()); - return candidate != null && candidate.equals(e); - } - - public boolean remove(Object o) { - return removeMapping(o) != null; - } - - public int size() { - return size; - } - - public void clear() { - LongHashMap.this.clear(); - } - } - - /** - * Save the state of the HashMap instance to a stream (i.e., serialize it). - * - * @serialData The capacity of the HashMap (the length of the bucket array) is emitted (int), followed by the - * size (an int, the number of key-value mappings), followed by the key (Object) and value (Object) for each - * key-value mapping. The key-value mappings are emitted in no particular order. - */ - private void writeObject(java.io.ObjectOutputStream s) throws IOException { - Iterator> i = (size > 0) ? entrySet0().iterator() : null; - - // Write out the threshold, loadfactor, and any hidden stuff - s.defaultWriteObject(); - - // Write out number of buckets - s.writeInt(table.length); - - // Write out size (number of Mappings) - s.writeInt(size); - - // Write out keys and values (alternating) - if (i != null) { - while (i.hasNext()) { - Map.Entry e = i.next(); - s.writeLong(e.getKey()); - s.writeObject(e.getValue()); - } - } - } - - private static final long serialVersionUID = 362498820763181265L; - - /** - * Reconstitute the HashMap instance from a stream (i.e., deserialize it). - */ - @SuppressWarnings("unchecked") - private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { - // Read in the threshold, loadfactor, and any hidden stuff - s.defaultReadObject(); - - // Read in number of buckets and allocate the bucket array; - int numBuckets = s.readInt(); - table = new Entry[numBuckets]; - - init(); // Give subclass a chance to do its thing. - - // Read in size (number of Mappings) - int size = s.readInt(); - - // Read the keys and values, and put the mappings in the HashMap - for (int i = 0; i < size; i++) { - int key = s.readInt(); - V value = (V) s.readObject(); - putForCreate(key, value); - } - } - - // These methods are used when serializing HashSets - int capacity() { - return table.length; - } - - float loadFactor() { - return loadFactor; - } -}