| /* |
| * 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 <decaf/util/Config.h> |
| |
| #include <decaf/util/AbstractMap.h> |
| #include <decaf/util/AbstractSet.h> |
| #include <decaf/util/HashCode.h> |
| #include <decaf/util/ConcurrentModificationException.h> |
| #include <decaf/lang/exceptions/UnsupportedOperationException.h> |
| #include <decaf/lang/Pointer.h> |
| #include <decaf/lang/ArrayPointer.h> |
| |
| 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<K, V>* map = Collections::synchronizedMap(new HashMap<K, V>()); |
| * |
| * 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<typename K, typename V, typename HASHCODE = HashCode<K> > |
| class HashMap : public AbstractMap<K, V> { |
| protected: |
| |
| class HashMapEntry : public MapEntry<K, V> { |
| private: |
| |
| HashMapEntry(const HashMapEntry&); |
| HashMapEntry& operator= (const HashMapEntry&); |
| |
| public: |
| |
| int origKeyHash; |
| |
| HashMapEntry* next; |
| |
| HashMapEntry(const K& key, const V& value, int hash) : MapEntry<K, V>(), origKeyHash(hash), next(NULL) { |
| this->setKey(key); |
| this->setValue(value); |
| this->origKeyHash = hash; |
| } |
| |
| HashMapEntry(const K& key, const V& value) : MapEntry<K, V>(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<K,V> >, 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<K, V> next() { |
| this->makeNext(); |
| return *(this->currentEntry); |
| } |
| |
| virtual void remove() { |
| this->doRemove(); |
| } |
| }; |
| |
| class KeyIterator : public Iterator<K>, 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<V>, 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<K,V> >, 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<K, V> 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<K>, 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<V>, 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<K, V> > { |
| private: |
| |
| HashMap* associatedMap; |
| |
| private: |
| |
| HashMapEntrySet(const HashMapEntrySet&); |
| HashMapEntrySet& operator= (const HashMapEntrySet&); |
| |
| public: |
| |
| HashMapEntrySet(HashMap* parent) : AbstractSet< MapEntry<K,V> >(), associatedMap(parent) { |
| } |
| |
| virtual ~HashMapEntrySet() {} |
| |
| virtual int size() const { |
| return associatedMap->elementCount; |
| } |
| |
| virtual void clear() { |
| associatedMap->clear(); |
| } |
| |
| virtual bool remove(const MapEntry<K,V>& 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<K,V>& entry) const { |
| HashMapEntry* result = associatedMap->getEntry(entry.getKey()); |
| if (result != NULL && entry.getValue() == result->getValue()) { |
| return true; |
| } |
| return false; |
| } |
| |
| virtual Iterator< MapEntry<K, V> >* iterator() { |
| return new EntryIterator(associatedMap); |
| } |
| |
| virtual Iterator< MapEntry<K, V> >* iterator() const { |
| return new ConstEntryIterator(associatedMap); |
| } |
| }; |
| |
| // Special Set implementation that is backed by this HashMap |
| class ConstHashMapEntrySet : public AbstractSet< MapEntry<K, V> > { |
| private: |
| |
| const HashMap* associatedMap; |
| |
| private: |
| |
| ConstHashMapEntrySet(const ConstHashMapEntrySet&); |
| ConstHashMapEntrySet& operator= (const ConstHashMapEntrySet&); |
| |
| public: |
| |
| ConstHashMapEntrySet(const HashMap* parent) : AbstractSet< MapEntry<K,V> >(), 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<K,V>& entry DECAF_UNUSED) { |
| throw decaf::lang::exceptions::UnsupportedOperationException( |
| __FILE__, __LINE__, "Can't remove from const collection"); |
| } |
| |
| virtual bool contains(const MapEntry<K,V>& entry) const { |
| HashMapEntry* result = associatedMap->getEntry(entry.getKey()); |
| if (result != NULL && entry.getValue() == result->getValue()) { |
| return true; |
| } |
| return false; |
| } |
| |
| virtual Iterator< MapEntry<K, V> >* iterator() { |
| throw decaf::lang::exceptions::UnsupportedOperationException( |
| __FILE__, __LINE__, "Can't return a non-const iterator for a const collection"); |
| } |
| |
| virtual Iterator< MapEntry<K, V> >* iterator() const { |
| return new ConstEntryIterator(associatedMap); |
| } |
| }; |
| |
| protected: |
| |
| class HashMapKeySet : public AbstractSet<K> { |
| private: |
| |
| HashMap* associatedMap; |
| |
| private: |
| |
| HashMapKeySet(const HashMapKeySet&); |
| HashMapKeySet& operator= (const HashMapKeySet&); |
| |
| public: |
| |
| HashMapKeySet(HashMap* parent) : AbstractSet<K>(), 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<K>* iterator() { |
| return new KeyIterator(this->associatedMap); |
| } |
| |
| virtual Iterator<K>* iterator() const { |
| return new ConstKeyIterator(this->associatedMap); |
| } |
| }; |
| |
| class ConstHashMapKeySet : public AbstractSet<K> { |
| private: |
| |
| const HashMap* associatedMap; |
| |
| private: |
| |
| ConstHashMapKeySet(const ConstHashMapKeySet&); |
| ConstHashMapKeySet& operator= (const ConstHashMapKeySet&); |
| |
| public: |
| |
| ConstHashMapKeySet(const HashMap* parent) : AbstractSet<K>(), 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<K>* iterator() { |
| throw decaf::lang::exceptions::UnsupportedOperationException( |
| __FILE__, __LINE__, "Can't return a non-const iterator for a const collection"); |
| } |
| |
| virtual Iterator<K>* iterator() const { |
| return new ConstKeyIterator(this->associatedMap); |
| } |
| }; |
| |
| protected: |
| |
| class HashMapValueCollection : public AbstractCollection<V> { |
| private: |
| |
| HashMap* associatedMap; |
| |
| private: |
| |
| HashMapValueCollection(const HashMapValueCollection&); |
| HashMapValueCollection& operator= (const HashMapValueCollection&); |
| |
| public: |
| |
| HashMapValueCollection(HashMap* parent) : AbstractCollection<V>(), 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<V>* iterator() { |
| return new ValueIterator(this->associatedMap); |
| } |
| |
| virtual Iterator<V>* iterator() const { |
| return new ConstValueIterator(this->associatedMap); |
| } |
| }; |
| |
| class ConstHashMapValueCollection : public AbstractCollection<V> { |
| private: |
| |
| const HashMap* associatedMap; |
| |
| private: |
| |
| ConstHashMapValueCollection(const ConstHashMapValueCollection&); |
| ConstHashMapValueCollection& operator= (const ConstHashMapValueCollection&); |
| |
| public: |
| |
| ConstHashMapValueCollection(const HashMap* parent) : AbstractCollection<V>(), 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<V>* iterator() { |
| throw decaf::lang::exceptions::UnsupportedOperationException( |
| __FILE__, __LINE__, "Can't return a non-const iterator for a const collection"); |
| } |
| |
| virtual Iterator<V>* 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<HashMapEntry*> 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<HashMapEntrySet> cachedEntrySet; |
| decaf::lang::Pointer<HashMapKeySet> cachedKeySet; |
| decaf::lang::Pointer<HashMapValueCollection> cachedValueCollection; |
| |
| // Cached values that are only initialized once a request for them is made. |
| mutable decaf::lang::Pointer<ConstHashMapEntrySet> cachedConstEntrySet; |
| mutable decaf::lang::Pointer<ConstHashMapKeySet> cachedConstKeySet; |
| mutable decaf::lang::Pointer<ConstHashMapValueCollection> 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<K,V>(), 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<HashMapEntry*>(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<K,V>(), 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<HashMapEntry*>(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<K,V>(), 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<HashMapEntry*>(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<K,V>& map) : AbstractMap<K,V>(), 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<HashMapEntry*>(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<K,V>& map) : AbstractMap<K,V>(), 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<HashMapEntry*>(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: |
| |
| HashMap<K, V>& operator= (const Map<K, V>& other) { |
| this->copy(other); |
| return *this; |
| } |
| |
| HashMap<K, V>& operator= (const HashMap<K, V>& other) { |
| this->copy(other); |
| return *this; |
| } |
| |
| bool operator==(const Map<K, V>& other) const { |
| return this->equals(other); |
| } |
| |
| bool operator!=(const Map<K, V>& 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<K, V>& 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<K,V> >& entrySet() { |
| if (this->cachedEntrySet == NULL) { |
| this->cachedEntrySet.reset(new HashMapEntrySet(this)); |
| } |
| return *(this->cachedEntrySet); |
| } |
| |
| virtual const Set< MapEntry<K,V> >& entrySet() const { |
| if (this->cachedConstEntrySet == NULL) { |
| this->cachedConstEntrySet.reset(new ConstHashMapEntrySet(this)); |
| } |
| return *(this->cachedConstEntrySet); |
| } |
| |
| virtual Set<K>& keySet() { |
| if (this->cachedKeySet == NULL) { |
| this->cachedKeySet.reset(new HashMapKeySet(this)); |
| } |
| return *(this->cachedKeySet); |
| } |
| |
| virtual const Set<K>& keySet() const { |
| if (this->cachedConstKeySet == NULL) { |
| this->cachedConstKeySet.reset(new ConstHashMapKeySet(this)); |
| } |
| return *(this->cachedConstKeySet); |
| } |
| |
| virtual Collection<V>& values() { |
| if (this->cachedValueCollection == NULL) { |
| this->cachedValueCollection.reset(new HashMapValueCollection(this)); |
| } |
| return *(this->cachedValueCollection); |
| } |
| |
| virtual const Collection<V>& values() const { |
| if (this->cachedConstValueCollection == NULL) { |
| this->cachedConstValueCollection.reset(new ConstHashMapValueCollection(this)); |
| } |
| return *(this->cachedConstValueCollection); |
| } |
| |
| virtual bool equals(const Map<K, V>& source) const { |
| |
| if (this == &source) { |
| return true; |
| } |
| |
| if (size() != source.size()) { |
| return false; |
| } |
| |
| try { |
| decaf::lang::Pointer<Iterator<MapEntry<K, V> > > iter(entrySet().iterator()); |
| while (iter->hasNext() ) { |
| MapEntry<K, V> 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<K, V>& source) { |
| int capacity = calculateCapacity(source.size()); |
| this->clear(); |
| if (capacity > elementData.length()) { |
| elementData = decaf::lang::ArrayPointer<HashMapEntry*>(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<K, V>& map) { |
| int capacity = elementCount + map.size(); |
| if (capacity > threshold) { |
| rehash(capacity); |
| } |
| |
| decaf::lang::Pointer<Iterator< MapEntry<K,V> > > iterator(map.entrySet().iterator()); |
| while (iterator->hasNext()) { |
| MapEntry<K, V> 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<HashMapEntry*> 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_ */ |