/* * Copyright 2004-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef HASH_MAP_H #define HASH_MAP_H //#include <Debug.h> #include <util/OpenHashTable.h> #include "AutoLocker.h" #include "Locker.h" // HashMapElement template<typename Key, typename Value> class HashMapElement { private: typedef HashMapElement<Key, Value> Element; public: HashMapElement() : fKey(), fValue() { } HashMapElement(const Key& key, const Value& value) : fKey(key), fValue(value) { } Key fKey; Value fValue; HashMapElement* fNext; }; // HashMapTableDefinition template<typename Key, typename Value> struct HashMapTableDefinition { typedef Key KeyType; typedef HashMapElement<Key, Value> ValueType; size_t HashKey(const KeyType& key) const { return key.GetHashCode(); } size_t Hash(const ValueType* value) const { return HashKey(value->fKey); } bool Compare(const KeyType& key, const ValueType* value) const { return value->fKey == key; } ValueType*& GetLink(ValueType* value) const { return value->fNext; } }; // HashMap template<typename Key, typename Value> class HashMap { public: class Entry { public: Entry() {} Entry(const Key& key, Value value) : key(key), value(value) {} Key key; Value value; }; class Iterator { private: typedef HashMapElement<Key, Value> Element; public: Iterator(const Iterator& other) : fMap(other.fMap), fIterator(other.fIterator), fElement(other.fElement) { } bool HasNext() const { return fIterator.HasNext(); } Entry Next() { fElement = fIterator.Next(); if (fElement == NULL) return Entry(); return Entry(fElement->fKey, fElement->fValue); } Entry Remove() { if (fElement == NULL) return Entry(); Entry result(fElement->fKey, fElement->fValue); fMap->fTable.RemoveUnchecked(fElement); delete fElement; fElement = NULL; return result; } Iterator& operator=(const Iterator& other) { fMap = other.fMap; fIterator = other.fIterator; fElement = other.fElement; return *this; } private: Iterator(HashMap<Key, Value>* map) : fMap(map), fIterator(map->fTable.GetIterator()), fElement(NULL) { } private: friend class HashMap<Key, Value>; typedef BOpenHashTable<HashMapTableDefinition<Key, Value> > ElementTable; HashMap<Key, Value>* fMap; typename ElementTable::Iterator fIterator; Element* fElement; }; HashMap(); ~HashMap(); status_t InitCheck() const; status_t Put(const Key& key, const Value& value); Value Remove(const Key& key); void Clear(); Value Get(const Key& key) const; bool ContainsKey(const Key& key) const; int32 Size() const; Iterator GetIterator(); protected: typedef BOpenHashTable<HashMapTableDefinition<Key, Value> > ElementTable; typedef HashMapElement<Key, Value> Element; friend class Iterator; protected: ElementTable fTable; }; // SynchronizedHashMap template<typename Key, typename Value> class SynchronizedHashMap : public Locker { public: typedef typename HashMap<Key, Value>::Entry Entry; typedef typename HashMap<Key, Value>::Iterator Iterator; SynchronizedHashMap() : Locker("synchronized hash map") {} ~SynchronizedHashMap() { Lock(); } status_t InitCheck() const { return fMap.InitCheck(); } status_t Put(const Key& key, const Value& value) { MapLocker locker(this); if (!locker.IsLocked()) return B_ERROR; return fMap.Put(key, value); } Value Remove(const Key& key) { MapLocker locker(this); if (!locker.IsLocked()) return Value(); return fMap.Remove(key); } void Clear() { MapLocker locker(this); return fMap.Clear(); } Value Get(const Key& key) const { const Locker* lock = this; MapLocker locker(const_cast<Locker*>(lock)); if (!locker.IsLocked()) return Value(); return fMap.Get(key); } bool ContainsKey(const Key& key) const { const Locker* lock = this; MapLocker locker(const_cast<Locker*>(lock)); if (!locker.IsLocked()) return false; return fMap.ContainsKey(key); } int32 Size() const { const Locker* lock = this; MapLocker locker(const_cast<Locker*>(lock)); return fMap.Size(); } Iterator GetIterator() { return fMap.GetIterator(); } // for debugging only const HashMap<Key, Value>& GetUnsynchronizedMap() const { return fMap; } HashMap<Key, Value>& GetUnsynchronizedMap() { return fMap; } protected: typedef AutoLocker<Locker> MapLocker; HashMap<Key, Value> fMap; }; // HashKey32 template<typename Value> struct HashKey32 { HashKey32() {} HashKey32(const Value& value) : value(value) {} uint32 GetHashCode() const { return (uint32)value; } HashKey32<Value> operator=(const HashKey32<Value>& other) { value = other.value; return *this; } bool operator==(const HashKey32<Value>& other) const { return (value == other.value); } bool operator!=(const HashKey32<Value>& other) const { return (value != other.value); } Value value; }; // HashKey64 template<typename Value> struct HashKey64 { HashKey64() {} HashKey64(const Value& value) : value(value) {} uint32 GetHashCode() const { uint64 v = (uint64)value; return (uint32)(v >> 32) ^ (uint32)v; } HashKey64<Value> operator=(const HashKey64<Value>& other) { value = other.value; return *this; } bool operator==(const HashKey64<Value>& other) const { return (value == other.value); } bool operator!=(const HashKey64<Value>& other) const { return (value != other.value); } Value value; }; // HashMap // constructor template<typename Key, typename Value> HashMap<Key, Value>::HashMap() : fTable() { fTable.Init(); } // destructor template<typename Key, typename Value> HashMap<Key, Value>::~HashMap() { Clear(); } // InitCheck template<typename Key, typename Value> status_t HashMap<Key, Value>::InitCheck() const { return (fTable.TableSize() > 0 ? B_OK : B_NO_MEMORY); } // Put template<typename Key, typename Value> status_t HashMap<Key, Value>::Put(const Key& key, const Value& value) { Element* element = fTable.Lookup(key); if (element) { // already contains the key: just set the new value element->fValue = value; return B_OK; } // does not contain the key yet: create an element and add it element = new(std::nothrow) Element(key, value); if (!element) return B_NO_MEMORY; status_t error = fTable.Insert(element); if (error != B_OK) delete element; return error; } // Remove template<typename Key, typename Value> Value HashMap<Key, Value>::Remove(const Key& key) { Element* element = fTable.Lookup(key); if (element == NULL) return Value(); fTable.Remove(element); Value value = element->fValue; delete element; return value; } // Clear template<typename Key, typename Value> void HashMap<Key, Value>::Clear() { // clear the table and delete the elements Element* element = fTable.Clear(true); while (element != NULL) { Element* next = element->fNext; delete element; element = next; } } // Get template<typename Key, typename Value> Value HashMap<Key, Value>::Get(const Key& key) const { if (Element* element = fTable.Lookup(key)) return element->fValue; return Value(); } // ContainsKey template<typename Key, typename Value> bool HashMap<Key, Value>::ContainsKey(const Key& key) const { return fTable.Lookup(key) != NULL; } // Size template<typename Key, typename Value> int32 HashMap<Key, Value>::Size() const { return fTable.CountElements(); } // GetIterator template<typename Key, typename Value> typename HashMap<Key, Value>::Iterator HashMap<Key, Value>::GetIterator() { return Iterator(this); } #endif // HASH_MAP_H