/* * Copyright 2004-2009, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2019, Haiku, Inc. All rights reserved. * Distributed under the terms of the MIT License. */ #ifndef HASH_MAP_H #define HASH_MAP_H #include #include #include "AutoLocker.h" namespace BPrivate { // HashMapElement template class HashMapElement { private: typedef HashMapElement Element; public: HashMapElement() : fKey(), fValue(), fNext(NULL) { } HashMapElement(const Key& key, const Value& value) : fKey(key), fValue(value), fNext(NULL) { } Key fKey; Value fValue; HashMapElement* fNext; }; // HashMapTableDefinition template struct HashMapTableDefinition { typedef Key KeyType; typedef HashMapElement 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 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 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); } Iterator& operator=(const Iterator& other) { fMap = other.fMap; fIterator = other.fIterator; fElement = other.fElement; return *this; } private: Iterator(const HashMap* map) : fMap(map), fIterator(map->fTable.GetIterator()), fElement(NULL) { } private: friend class HashMap; typedef BOpenHashTable > ElementTable; const HashMap* 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); Value Remove(Iterator& it); void Clear(); Value Get(const Key& key) const; bool Get(const Key& key, Value*& _value) const; bool ContainsKey(const Key& key) const; int32 Size() const; Iterator GetIterator() const; protected: typedef BOpenHashTable > ElementTable; typedef HashMapElement Element; friend class Iterator; protected: ElementTable fTable; }; // SynchronizedHashMap template class SynchronizedHashMap : public Locker { public: typedef typename HashMap::Entry Entry; typedef typename HashMap::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); fMap.Clear(); } Value Get(const Key& key) const { const Locker* lock = this; MapLocker locker(const_cast(lock)); if (!locker.IsLocked()) return Value(); return fMap.Get(key); } bool ContainsKey(const Key& key) const { const Locker* lock = this; MapLocker locker(const_cast(lock)); if (!locker.IsLocked()) return false; return fMap.ContainsKey(key); } int32 Size() const { const Locker* lock = this; MapLocker locker(const_cast(lock)); return fMap.Size(); } Iterator GetIterator() { return fMap.GetIterator(); } // for debugging only const HashMap& GetUnsynchronizedMap() const { return fMap; } HashMap& GetUnsynchronizedMap() { return fMap; } protected: typedef AutoLocker MapLocker; HashMap fMap; }; // HashKey32 template struct HashKey32 { HashKey32() {} HashKey32(const Value& value) : value(value) {} uint32 GetHashCode() const { return (uint32)value; } HashKey32 operator=(const HashKey32& other) { value = other.value; return *this; } bool operator==(const HashKey32& other) const { return (value == other.value); } bool operator!=(const HashKey32& other) const { return (value != other.value); } Value value; }; // HashKey64 template struct HashKey64 { HashKey64() {} HashKey64(const Value& value) : value(value) {} uint32 GetHashCode() const { uint64 v = (uint64)value; return (uint32)(v >> 32) ^ (uint32)v; } HashKey64 operator=(const HashKey64& other) { value = other.value; return *this; } bool operator==(const HashKey64& other) const { return (value == other.value); } bool operator!=(const HashKey64& other) const { return (value != other.value); } Value value; }; // HashKeyPointer template struct HashKeyPointer { HashKeyPointer() {} HashKeyPointer(const Value& value) : value(value) {} uint32 GetHashCode() const { #if __HAIKU_ARCH_BITS == 32 return (uint32)(addr_t)value; #elif __HAIKU_ARCH_BITS == 64 uint64 v = (uint64)(addr_t)value; return (uint32)(v >> 32) ^ (uint32)v; #else #error unknown bitness #endif } HashKeyPointer operator=(const HashKeyPointer& other) { value = other.value; return *this; } bool operator==(const HashKeyPointer& other) const { return (value == other.value); } bool operator!=(const HashKeyPointer& other) const { return (value != other.value); } Value value; }; // HashMap // constructor template HashMap::HashMap() : fTable() { fTable.Init(); } // destructor template HashMap::~HashMap() { Clear(); } // InitCheck template status_t HashMap::InitCheck() const { return (fTable.TableSize() > 0 ? B_OK : B_NO_MEMORY); } // Put template status_t HashMap::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 Value HashMap::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; } // Remove template Value HashMap::Remove(Iterator& it) { Element* element = it.fElement; if (element == NULL) return Value(); Value value = element->fValue; fTable.RemoveUnchecked(element); delete element; it.fElement = NULL; return value; } // Clear template void HashMap::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 Value HashMap::Get(const Key& key) const { if (Element* element = fTable.Lookup(key)) return element->fValue; return Value(); } // Get template bool HashMap::Get(const Key& key, Value*& _value) const { if (Element* element = fTable.Lookup(key)) { _value = &element->fValue; return true; } return false; } // ContainsKey template bool HashMap::ContainsKey(const Key& key) const { return fTable.Lookup(key) != NULL; } // Size template int32 HashMap::Size() const { return fTable.CountElements(); } // GetIterator template typename HashMap::Iterator HashMap::GetIterator() const { return Iterator(this); } } // namespace BPrivate using BPrivate::HashMap; using BPrivate::HashKey32; using BPrivate::HashKey64; using BPrivate::HashKeyPointer; using BPrivate::SynchronizedHashMap; #endif // HASH_MAP_H