/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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. */ #ifndef _DECAF_UTIL_HASHMAP_H_ #define _DECAF_UTIL_HASHMAP_H_ #include #include #include #include #include #include #include #include namespace decaf { namespace util { /** * Hash table based implementation of the Map interface. This implementation provides all * of the optional map operations, and permits null values and the null key. This class * makes no guarantees as to the order of the map; in particular, it does not guarantee * that the order will remain constant over time. * * This implementation provides constant-time performance for the basic operations (get * and put), assuming the hash function disperses the elements properly among the buckets. * Iteration over collection views requires time proportional to the "capacity" of the * HashMap instance (the number of buckets) plus its size (the number of key-value mappings). * Thus, it's very important not to set the initial capacity too high (or the load factor too * low) if iteration performance is important. * * An instance of HashMap has two parameters that affect its performance: initial capacity * and load factor. The capacity is the number of buckets in the hash table, and the initial * capacity is simply the capacity at the time the hash table is created. The load factor is * a measure of how full the hash table is allowed to get before its capacity is automatically * increased. When the number of entries in the hash table exceeds the product of the load * factor and the current capacity, the hash table is rehashed (that is, internal data * structures are rebuilt) so that the hash table has approximately twice the number of buckets. * * As a general rule, the default load factor (.75) offers a good tradeoff between time and * space costs. Higher values decrease the space overhead but increase the lookup cost * (reflected in most of the operations of the HashMap class, including get and put). The * expected number of entries in the map and its load factor should be taken into account * when setting its initial capacity, so as to minimize the number of rehash operations. If * the initial capacity is greater than the maximum number of entries divided by the load * factor, no rehash operations will ever occur. * * If many mappings are to be stored in a HashMap instance, creating it with a sufficiently * large capacity will allow the mappings to be stored more efficiently than letting it * perform automatic rehashing as needed to grow the table. * * Note that this implementation is not synchronized. If multiple threads access a hash map * concurrently, and at least one of the threads modifies the map structurally, it must be * synchronized externally. (A structural modification is any operation that adds or deletes * one or more mappings; merely changing the value associated with a key that an instance * already contains is not a structural modification.) This is typically accomplished by * synchronizing on some object that naturally encapsulates the map. If no such object * exists, the map should be "wrapped" using the Collections::synchronizedMap method. * This is best done at creation time, to prevent accidental unsynchronized access to the map: * * Map* map = Collections::synchronizedMap(new HashMap()); * * The iterators returned by all of this class's "collection view methods" are fail-fast: * if the map is structurally modified at any time after the iterator is created, in any * way except through the iterator's own remove method, the iterator will throw a * ConcurrentModificationException. Thus, in the face of concurrent modification, the * iterator fails quickly and cleanly, rather than risking arbitrary, non-deterministic * behavior at an undetermined time in the future. * * Note that the fail-fast behavior of an iterator cannot be guaranteed as it is, generally * speaking, impossible to make any hard guarantees in the presence of unsynchronized * concurrent modification. Fail-fast iterators throw ConcurrentModificationException on a * best-effort basis. Therefore, it would be wrong to write a program that depended on this * exception for its correctness: the fail-fast behavior of iterators should be used only * to detect bugs. * * @since 1.0 */ template > class HashMap : public AbstractMap { protected: class HashMapEntry : public MapEntry { private: HashMapEntry(const HashMapEntry&); HashMapEntry& operator= (const HashMapEntry&); public: int origKeyHash; HashMapEntry* next; HashMapEntry(const K& key, const V& value, int hash) : MapEntry(), origKeyHash(hash), next(NULL) { this->setKey(key); this->setValue(value); this->origKeyHash = hash; } HashMapEntry(const K& key, const V& value) : MapEntry(key, value), origKeyHash(0), next(NULL){ this->origKeyHash = HASHCODE()(key); } }; private: class AbstractMapIterator { protected: mutable int position; int expectedModCount; HashMapEntry* futureEntry; HashMapEntry* currentEntry; HashMapEntry* prevEntry; HashMap* associatedMap; private: AbstractMapIterator(const AbstractMapIterator&); AbstractMapIterator& operator= (const AbstractMapIterator&); public: AbstractMapIterator(HashMap* parent) : position(0), expectedModCount(parent->modCount), futureEntry(NULL), currentEntry(NULL), prevEntry(NULL), associatedMap(parent) { } virtual ~AbstractMapIterator() {} virtual bool checkHasNext() const { if (futureEntry != NULL) { return true; } while (position < associatedMap->elementData.length()) { if (associatedMap->elementData[position] == NULL) { position++; } else { return true; } } return false; } void checkConcurrentMod() const { if (expectedModCount != associatedMap->modCount) { throw ConcurrentModificationException( __FILE__, __LINE__, "HashMap modified outside this iterator"); } } void makeNext() { checkConcurrentMod(); if (!checkHasNext()) { throw NoSuchElementException(__FILE__, __LINE__, "No next element"); } if (futureEntry == NULL) { currentEntry = associatedMap->elementData[position++]; futureEntry = currentEntry->next; prevEntry = NULL; } else { if (currentEntry != NULL){ prevEntry = currentEntry; } currentEntry = futureEntry; futureEntry = futureEntry->next; } } virtual void doRemove() { checkConcurrentMod(); if (currentEntry == NULL) { throw decaf::lang::exceptions::IllegalStateException( __FILE__, __LINE__, "Remove called before call to next()"); } if (prevEntry == NULL){ int index = currentEntry->origKeyHash & (associatedMap->elementData.length() - 1); associatedMap->elementData[index] = associatedMap->elementData[index]->next; } else { prevEntry->next = currentEntry->next; } delete currentEntry; currentEntry = NULL; expectedModCount++; associatedMap->modCount++; associatedMap->elementCount--; } }; class EntryIterator : public Iterator< MapEntry >, public AbstractMapIterator { private: EntryIterator(const EntryIterator&); EntryIterator& operator= (const EntryIterator&); public: EntryIterator(HashMap* parent) : AbstractMapIterator(parent) { } virtual ~EntryIterator() {} virtual bool hasNext() const { return this->checkHasNext(); } virtual MapEntry next() { this->makeNext(); return *(this->currentEntry); } virtual void remove() { this->doRemove(); } }; class KeyIterator : public Iterator, public AbstractMapIterator { private: KeyIterator(const KeyIterator&); KeyIterator& operator= (const KeyIterator&); public: KeyIterator(HashMap* parent) : AbstractMapIterator(parent) { } virtual ~KeyIterator() {} virtual bool hasNext() const { return this->checkHasNext(); } virtual K next() { this->makeNext(); return this->currentEntry->getKey(); } virtual void remove() { this->doRemove(); } }; class ValueIterator : public Iterator, public AbstractMapIterator { private: ValueIterator(const ValueIterator&); ValueIterator& operator= (const ValueIterator&); public: ValueIterator(HashMap* parent) : AbstractMapIterator(parent) { } virtual ~ValueIterator() {} virtual bool hasNext() const { return this->checkHasNext(); } virtual V next() { this->makeNext(); return this->currentEntry->getValue(); } virtual void remove() { this->doRemove(); } }; private: class ConstAbstractMapIterator { protected: mutable int position; int expectedModCount; const HashMapEntry* futureEntry; const HashMapEntry* currentEntry; const HashMapEntry* prevEntry; const HashMap* associatedMap; private: ConstAbstractMapIterator(const ConstAbstractMapIterator&); ConstAbstractMapIterator& operator= (const ConstAbstractMapIterator&); public: ConstAbstractMapIterator(const HashMap* parent) : position(0), expectedModCount(parent->modCount), futureEntry(NULL), currentEntry(NULL), prevEntry(NULL), associatedMap(parent) { } virtual ~ConstAbstractMapIterator() {} virtual bool checkHasNext() const { if (futureEntry != NULL) { return true; } while (position < associatedMap->elementData.length()) { if (associatedMap->elementData[position] == NULL) { position++; } else { return true; } } return false; } void checkConcurrentMod() const { if (expectedModCount != associatedMap->modCount) { throw ConcurrentModificationException( __FILE__, __LINE__, "HashMap modified outside this iterator"); } } void makeNext() { checkConcurrentMod(); if (!checkHasNext()) { throw NoSuchElementException(__FILE__, __LINE__, "No next element"); } if (futureEntry == NULL) { currentEntry = associatedMap->elementData[position++]; futureEntry = currentEntry->next; prevEntry = NULL; } else { if (currentEntry != NULL){ prevEntry = currentEntry; } currentEntry = futureEntry; futureEntry = futureEntry->next; } } }; class ConstEntryIterator : public Iterator< MapEntry >, public ConstAbstractMapIterator { private: ConstEntryIterator(const ConstEntryIterator&); ConstEntryIterator& operator= (const ConstEntryIterator&); public: ConstEntryIterator(const HashMap* parent) : ConstAbstractMapIterator(parent) { } virtual ~ConstEntryIterator() {} virtual bool hasNext() const { return this->checkHasNext(); } virtual MapEntry next() { this->makeNext(); return *(this->currentEntry); } virtual void remove() { throw lang::exceptions::UnsupportedOperationException( __FILE__, __LINE__, "Cannot write to a const Iterator." ); } }; class ConstKeyIterator : public Iterator, public ConstAbstractMapIterator { private: ConstKeyIterator(const ConstKeyIterator&); ConstKeyIterator& operator= (const ConstKeyIterator&); public: ConstKeyIterator(const HashMap* parent) : ConstAbstractMapIterator(parent) { } virtual ~ConstKeyIterator() {} virtual bool hasNext() const { return this->checkHasNext(); } virtual K next() { this->makeNext(); return this->currentEntry->getKey(); } virtual void remove() { throw lang::exceptions::UnsupportedOperationException( __FILE__, __LINE__, "Cannot write to a const Iterator." ); } }; class ConstValueIterator : public Iterator, public ConstAbstractMapIterator { private: ConstValueIterator(const ConstValueIterator&); ConstValueIterator& operator= (const ConstValueIterator&); public: ConstValueIterator(const HashMap* parent) : ConstAbstractMapIterator(parent) { } virtual ~ConstValueIterator() {} virtual bool hasNext() const { return this->checkHasNext(); } virtual V next() { this->makeNext(); return this->currentEntry->getValue(); } virtual void remove() { throw lang::exceptions::UnsupportedOperationException( __FILE__, __LINE__, "Cannot write to a const Iterator." ); } }; protected: // Special Set implementation that is backed by this HashMap class HashMapEntrySet : public AbstractSet< MapEntry > { private: HashMap* associatedMap; private: HashMapEntrySet(const HashMapEntrySet&); HashMapEntrySet& operator= (const HashMapEntrySet&); public: HashMapEntrySet(HashMap* parent) : AbstractSet< MapEntry >(), associatedMap(parent) { } virtual ~HashMapEntrySet() {} virtual int size() const { return associatedMap->elementCount; } virtual void clear() { associatedMap->clear(); } virtual bool remove(const MapEntry& entry) { HashMapEntry* result = associatedMap->getEntry(entry.getKey()); if (result != NULL && entry.getValue() == result->getValue()) { associatedMap->removeEntry(result); return true; } return false; } virtual bool contains(const MapEntry& entry) { HashMapEntry* result = associatedMap->getEntry(entry.getKey()); if (result != NULL && entry.getValue() == result->getValue()) { return true; } return false; } virtual Iterator< MapEntry >* iterator() { return new EntryIterator(associatedMap); } virtual Iterator< MapEntry >* iterator() const { return new ConstEntryIterator(associatedMap); } }; // Special Set implementation that is backed by this HashMap class ConstHashMapEntrySet : public AbstractSet< MapEntry > { private: const HashMap* associatedMap; private: ConstHashMapEntrySet(const ConstHashMapEntrySet&); ConstHashMapEntrySet& operator= (const ConstHashMapEntrySet&); public: ConstHashMapEntrySet(const HashMap* parent) : AbstractSet< MapEntry >(), associatedMap(parent) { } virtual ~ConstHashMapEntrySet() {} virtual int size() const { return associatedMap->elementCount; } virtual void clear() { throw decaf::lang::exceptions::UnsupportedOperationException( __FILE__, __LINE__, "Can't clear a const collection"); } virtual bool remove(const MapEntry& entry DECAF_UNUSED) { throw decaf::lang::exceptions::UnsupportedOperationException( __FILE__, __LINE__, "Can't remove from const collection"); } virtual bool contains(const MapEntry& entry) { HashMapEntry* result = associatedMap->getEntry(entry.getKey()); if (result != NULL && entry.getValue() == result->getValue()) { return true; } return false; } virtual Iterator< MapEntry >* iterator() { throw decaf::lang::exceptions::UnsupportedOperationException( __FILE__, __LINE__, "Can't return a non-const iterator for a const collection"); } virtual Iterator< MapEntry >* iterator() const { return new ConstEntryIterator(associatedMap); } }; protected: class HashMapKeySet : public AbstractSet { private: HashMap* associatedMap; private: HashMapKeySet(const HashMapKeySet&); HashMapKeySet& operator= (const HashMapKeySet&); public: HashMapKeySet(HashMap* parent) : AbstractSet(), associatedMap(parent) { } virtual ~HashMapKeySet() {} virtual bool contains(const K& key) const { return this->associatedMap->containsKey(key); } virtual int size() const { return this->associatedMap->size(); } virtual void clear() { this->associatedMap->clear(); } virtual bool remove(const K& key) { HashMapEntry* entry = this->associatedMap->removeEntry(key); if (entry != NULL) { delete entry; return true; } return false; } virtual Iterator* iterator() { return new KeyIterator(this->associatedMap); } virtual Iterator* iterator() const { return new ConstKeyIterator(this->associatedMap); } }; class ConstHashMapKeySet : public AbstractSet { private: const HashMap* associatedMap; private: ConstHashMapKeySet(const ConstHashMapKeySet&); ConstHashMapKeySet& operator= (const ConstHashMapKeySet&); public: ConstHashMapKeySet(const HashMap* parent) : AbstractSet(), associatedMap(parent) { } virtual ~ConstHashMapKeySet() {} virtual bool contains(const K& key) const { return this->associatedMap->containsKey(key); } virtual int size() const { return this->associatedMap->size(); } virtual void clear() { throw decaf::lang::exceptions::UnsupportedOperationException( __FILE__, __LINE__, "Can't modify a const collection"); } virtual bool remove(const K& key DECAF_UNUSED) { throw decaf::lang::exceptions::UnsupportedOperationException( __FILE__, __LINE__, "Can't modify a const collection"); } virtual Iterator* iterator() { throw decaf::lang::exceptions::UnsupportedOperationException( __FILE__, __LINE__, "Can't return a non-const iterator for a const collection"); } virtual Iterator* iterator() const { return new ConstKeyIterator(this->associatedMap); } }; protected: class HashMapValueCollection : public AbstractCollection { private: HashMap* associatedMap; private: HashMapValueCollection(const HashMapValueCollection&); HashMapValueCollection& operator= (const HashMapValueCollection&); public: HashMapValueCollection(HashMap* parent) : AbstractCollection(), associatedMap(parent) { } virtual ~HashMapValueCollection() {} virtual bool contains(const V& value) const { return this->associatedMap->containsValue(value); } virtual int size() const { return this->associatedMap->size(); } virtual void clear() { this->associatedMap->clear(); } virtual Iterator* iterator() { return new ValueIterator(this->associatedMap); } virtual Iterator* iterator() const { return new ConstValueIterator(this->associatedMap); } }; class ConstHashMapValueCollection : public AbstractCollection { private: const HashMap* associatedMap; private: ConstHashMapValueCollection(const ConstHashMapValueCollection&); ConstHashMapValueCollection& operator= (const ConstHashMapValueCollection&); public: ConstHashMapValueCollection(const HashMap* parent) : AbstractCollection(), associatedMap(parent) { } virtual ~ConstHashMapValueCollection() {} virtual bool contains(const V& value) const { return this->associatedMap->containsValue(value); } virtual int size() const { return this->associatedMap->size(); } virtual void clear() { throw decaf::lang::exceptions::UnsupportedOperationException( __FILE__, __LINE__, "Can't modify a const collection"); } virtual Iterator* iterator() { throw decaf::lang::exceptions::UnsupportedOperationException( __FILE__, __LINE__, "Can't return a non-const iterator for a const collection"); } virtual Iterator* iterator() const { return new ConstValueIterator(this->associatedMap); } }; protected: /** * The Hash Code generator for this map's keys. */ HASHCODE hashFunc; /* * Actual count of entries */ int elementCount; /* * The internal data structure to hold Entries, Array of MapEntry pointers. */ decaf::lang::ArrayPointer elementData; /* * modification count, to keep track of structural modifications between the * HashMap and the iterator */ int modCount; /* * maximum ratio of (stored elements)/(storage size) which does not lead to rehash */ float loadFactor; /* * maximum number of elements that can be put in this map before having to rehash */ int threshold; // Cached values that are only initialized once a request for them is made. decaf::lang::Pointer cachedEntrySet; decaf::lang::Pointer cachedKeySet; decaf::lang::Pointer cachedValueCollection; // Cached values that are only initialized once a request for them is made. mutable decaf::lang::Pointer cachedConstEntrySet; mutable decaf::lang::Pointer cachedConstKeySet; mutable decaf::lang::Pointer cachedConstValueCollection; private: void computeThreshold() { threshold = (int) ((float) elementData.length() * loadFactor); } static int calculateCapacity(int x) { if (x >= 1 << 30) { return 1 << 30; } if (x == 0) { return 16; } x = x - 1; x |= x >> 1; x |= x >> 2; x |= x >> 4; x |= x >> 8; x |= x >> 16; return x + 1; } public: /** * Creates a new empty HashMap with default configuration settings. */ HashMap() : AbstractMap(), hashFunc(), elementCount(0), elementData(), modCount(0), loadFactor(0.75), threshold(0), cachedEntrySet(), cachedKeySet(), cachedValueCollection(), cachedConstEntrySet(), cachedConstKeySet(), cachedConstValueCollection() { int capacity = calculateCapacity(12); elementCount = 0; elementData = decaf::lang::ArrayPointer(capacity); computeThreshold(); } /** * Constructs a new HashMap instance with the specified capacity. * * @param capacity * The initial capacity of this hash map. * * @throws IllegalArgumentException when the capacity is less than zero. */ HashMap(int capacity) : AbstractMap(), hashFunc(), elementCount(0), elementData(), modCount(0), loadFactor(0.75), threshold(0), cachedEntrySet(), cachedKeySet(), cachedValueCollection(), cachedConstEntrySet(), cachedConstKeySet(), cachedConstValueCollection() { if (capacity >= 0) { capacity = calculateCapacity(capacity); elementCount = 0; elementData = decaf::lang::ArrayPointer(capacity); computeThreshold(); } else { throw decaf::lang::exceptions::IllegalArgumentException( __FILE__, __LINE__, "Invalid capacity configuration"); } } /** * Constructs a new HashMap instance with the specified capacity. * * @param capacity * The initial capacity of this hash map. * @param loadFactor * The load factor to use for this hash map. * * @throws IllegalArgumentException when the capacity is less than zero. */ HashMap(int capacity, float loadFactor) : AbstractMap(), hashFunc(), elementCount(0), elementData(), modCount(0), loadFactor(0.75), threshold(0), cachedEntrySet(), cachedKeySet(), cachedValueCollection(), cachedConstEntrySet(), cachedConstKeySet(), cachedConstValueCollection() { if (capacity >= 0 && loadFactor > 0) { capacity = calculateCapacity(capacity); elementCount = 0; elementData = decaf::lang::ArrayPointer(capacity); this->loadFactor = loadFactor; computeThreshold(); } else { throw decaf::lang::exceptions::IllegalArgumentException( __FILE__, __LINE__, "Invalid configuration"); } } /** * Creates a new HashMap with default configuration settings and fills it with the contents * of the given source Map instance. * * @param map * The Map instance whose elements are copied into this HashMap instance. */ HashMap(const HashMap& map) : AbstractMap(), hashFunc(), elementCount(0), elementData(), modCount(0), loadFactor(0.75), threshold(0), cachedEntrySet(), cachedKeySet(), cachedValueCollection(), cachedConstEntrySet(), cachedConstKeySet(), cachedConstValueCollection() { int capacity = calculateCapacity(map.size()); elementCount = 0; elementData = decaf::lang::ArrayPointer(capacity); computeThreshold(); putAll(map); } /** * Creates a new HashMap with default configuration settings and fills it with the contents * of the given source Map instance. * * @param map * The Map instance whose elements are copied into this HashMap instance. */ HashMap(const Map& map) : AbstractMap(), hashFunc(), elementCount(0), elementData(), modCount(0), loadFactor(0.75), threshold(0), cachedEntrySet(), cachedKeySet(), cachedValueCollection(), cachedConstEntrySet(), cachedConstKeySet(), cachedConstValueCollection() { int capacity = calculateCapacity(map.size()); elementCount = 0; elementData = decaf::lang::ArrayPointer(capacity); computeThreshold(); putAll(map); } virtual ~HashMap() { for (int i = 0; i < elementData.length(); i++) { HashMapEntry* entry = elementData[i]; while (entry != NULL) { HashMapEntry* temp = entry; entry = entry->next; delete temp; } } } public: bool operator==(const Map& other) const { return this->equals(other); } bool operator!=(const Map& other) const { return !this->equals(other); } public: virtual void clear() { if (elementCount > 0) { elementCount = 0; for (int i = 0; i < elementData.length(); ++i) { HashMapEntry* entry = elementData[i]; elementData[i] = NULL; while (entry != NULL) { HashMapEntry* temp = entry; entry = entry->next; delete temp; } } modCount++; } } virtual bool isEmpty() const { return elementCount == 0; } virtual int size() const { return elementCount; } virtual bool containsKey(const K& key) const { const HashMapEntry* entry = getEntry(key); return entry != NULL; } virtual bool containsValue(const V& value) const { for (int i = 0; i < elementData.length(); i++) { const HashMapEntry* entry = elementData[i]; while (entry != NULL) { if (value == entry->getValue()) { return true; } entry = entry->next; } } return false; } virtual V& get(const K& key) { HashMapEntry* entry = getEntry(key); if (entry != NULL) { return entry->getValue(); } throw NoSuchElementException( __FILE__, __LINE__, "The specified key is not present in the Map"); } virtual const V& get(const K& key) const { const HashMapEntry* entry = getEntry(key); if (entry != NULL) { return entry->getValue(); } throw NoSuchElementException( __FILE__, __LINE__, "The specified key is not present in the Map"); } virtual bool put(const K& key, const V& value) { return this->putImpl(key, value); } virtual bool put(const K& key, const V& value, V& oldValue) { return this->putImpl(key, value, oldValue); } virtual void putAll(const Map& map) { if (!map.isEmpty()) { putAllImpl(map); } } virtual V remove(const K& key) { HashMapEntry* entry = removeEntry(key); if (entry != NULL) { V oldValue = entry->getValue(); delete entry; return oldValue; } throw NoSuchElementException( __FILE__, __LINE__, "Specified key not present in the Map."); } virtual Set< MapEntry >& entrySet() { if (this->cachedEntrySet == NULL) { this->cachedEntrySet.reset(new HashMapEntrySet(this)); } return *(this->cachedEntrySet); } virtual const Set< MapEntry >& entrySet() const { if (this->cachedConstEntrySet == NULL) { this->cachedConstEntrySet.reset(new ConstHashMapEntrySet(this)); } return *(this->cachedConstEntrySet); } virtual Set& keySet() { if (this->cachedKeySet == NULL) { this->cachedKeySet.reset(new HashMapKeySet(this)); } return *(this->cachedKeySet); } virtual const Set& keySet() const { if (this->cachedConstKeySet == NULL) { this->cachedConstKeySet.reset(new ConstHashMapKeySet(this)); } return *(this->cachedConstKeySet); } virtual Collection& values() { if (this->cachedValueCollection == NULL) { this->cachedValueCollection.reset(new HashMapValueCollection(this)); } return *(this->cachedValueCollection); } virtual const Collection& values() const { if (this->cachedConstValueCollection == NULL) { this->cachedConstValueCollection.reset(new ConstHashMapValueCollection(this)); } return *(this->cachedConstValueCollection); } virtual bool equals(const Map& source) const { if (this == &source) { return true; } if (size() != source.size()) { return false; } try { decaf::lang::Pointer > > iter(entrySet().iterator()); while (iter->hasNext() ) { MapEntry entry = iter->next(); K key = entry.getKey(); V mine = entry.getValue(); if (!source.containsKey(key)) { return false; } if (source.get(key) != mine) { return false; } } } catch (decaf::lang::exceptions::NullPointerException& ignored) { return false; } catch (decaf::lang::exceptions::ClassCastException& ignored) { return false; } return true; } virtual void copy(const Map& source) { int capacity = calculateCapacity(source.size()); this->clear(); if (capacity > elementData.length()) { elementData = decaf::lang::ArrayPointer(capacity); } computeThreshold(); putAll(source); } virtual std::string toString() const { return "HashMap"; } protected: virtual HashMapEntry* getEntry(const K& key) const { HashMapEntry* result = NULL; int hash = hashFunc(key); int index = hash & (elementData.length() - 1); result = findKeyEntry(key, index, hash); return result; } virtual bool putImpl(const K& key, const V& value) { V oldValue; return putImpl(key, value, oldValue); } virtual bool putImpl(const K& key, const V& value, V& oldValue) { bool replaced = true; HashMapEntry* entry = NULL; int hash = hashFunc(key); int index = hash & (elementData.length() - 1); entry = findKeyEntry(key, index, hash); if (entry == NULL) { modCount++; entry = createHashedEntry(key, index, hash); if (++elementCount > threshold) { rehash(); } replaced = false; } else { oldValue = entry->getValue(); } entry->setValue(value); return replaced; } virtual HashMapEntry* createEntry(const K& key, int index, const V& value) { HashMapEntry* entry = new HashMapEntry(key, value); entry->next = elementData[index]; elementData[index] = entry; return entry; } virtual HashMapEntry* createHashedEntry(const K& key, int index, int hash) { HashMapEntry* entry = new HashMapEntry(key, V(), hash); entry->next = elementData[index]; elementData[index] = entry; return entry; } protected: void putAllImpl(const Map& map) { int capacity = elementCount + map.size(); if (capacity > threshold) { rehash(capacity); } decaf::lang::Pointer > > iterator(map.entrySet().iterator()); while (iterator->hasNext()) { MapEntry entry = iterator->next(); this->putImpl(entry.getKey(), entry.getValue()); } } HashMapEntry* findKeyEntry(const K& key, int index, int keyHash) const { HashMapEntry* entry = elementData[index]; while (entry != NULL && (entry->origKeyHash != keyHash || !(key == entry->getKey()))) { entry = entry->next; } return entry; } void rehash(int capacity) { int length = calculateCapacity((capacity == 0 ? 1 : capacity << 1)); decaf::lang::ArrayPointer newData(length); for (int i = 0; i < elementData.length(); i++) { HashMapEntry* entry = elementData[i]; elementData[i] = NULL; while (entry != NULL) { int index = entry->origKeyHash & (length - 1); HashMapEntry* next = entry->next; entry->next = newData[index]; newData[index] = entry; entry = next; } } elementData = newData; computeThreshold(); } void rehash() { rehash(elementData.length()); } // Removes the given entry from the map and deletes it void removeEntry(HashMapEntry* entry) { int index = entry->origKeyHash & (elementData.length() - 1); HashMapEntry* current = elementData[index]; if (current == entry) { elementData[index] = entry->next; } else { while (current->next != entry) { current = current->next; } current->next = entry->next; } delete entry; modCount++; elementCount--; } // Removes but doesn't delete the entry in the map with the given key. HashMapEntry* removeEntry(const K& key) { int index = 0; HashMapEntry* current = NULL; HashMapEntry* last = NULL; int hash = hashFunc(key); index = hash & (elementData.length() - 1); current = elementData[index]; while (current != NULL && !(current->origKeyHash == hash && key == current->getKey())) { last = current; current = current->next; } if (current == NULL) { return NULL; } if (last == NULL) { elementData[index] = current->next; } else { last->next = current->next; } modCount++; elementCount--; return current; } }; }} #endif /* _DECAF_UTIL_HASHMAP_H_ */