/* * 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_SET_H #define HASH_SET_H #include #include #include "AutoLocker.h" namespace BPrivate { // HashSetElement template class HashSetElement { private: typedef HashSetElement Element; public: HashSetElement() : fKey(), fNext(NULL) { } HashSetElement(const Key& key) : fKey(key), fNext(NULL) { } Key fKey; HashSetElement* fNext; }; // HashSetTableDefinition template struct HashSetTableDefinition { typedef Key KeyType; typedef HashSetElement 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; } }; // HashSet template class HashSet { public: class Iterator { private: typedef HashSetElement Element; public: Iterator(const Iterator& other) : fSet(other.fSet), fIterator(other.fIterator), fElement(other.fElement) { } bool HasNext() const { return fIterator.HasNext(); } Key Next() { fElement = fIterator.Next(); if (fElement == NULL) return Key(); return fElement->fKey; } Iterator& operator=(const Iterator& other) { fSet = other.fSet; fIterator = other.fIterator; fElement = other.fElement; return *this; } private: Iterator(const HashSet* set) : fSet(set), fIterator(set->fTable.GetIterator()), fElement(NULL) { } private: typedef BOpenHashTable > ElementTable; const HashSet* fSet; typename ElementTable::Iterator fIterator; Element* fElement; private: friend class HashSet; }; HashSet(); ~HashSet(); status_t InitCheck() const; status_t Add(const Key& key); bool Remove(const Key& key); bool Remove(Iterator& it); void Clear(); bool Contains(const Key& key) const; int32 Size() const; Iterator GetIterator() const; protected: typedef BOpenHashTable > ElementTable; typedef HashSetElement Element; friend class Iterator; protected: ElementTable fTable; }; // SynchronizedHashSet template class SynchronizedHashSet : public Locker { public: typedef typename HashSet::Iterator Iterator; SynchronizedHashSet() : Locker("synchronized hash set") {} ~SynchronizedHashSet() { Locker::Lock(); } status_t InitCheck() const { return fSet.InitCheck(); } status_t Add(const Key& key) { MapLocker locker(this); if (!locker.IsLocked()) return B_ERROR; return fSet.Add(key); } bool Remove(const Key& key) { MapLocker locker(this); if (!locker.IsLocked()) return false; return fSet.Remove(key); } void Clear() { MapLocker locker(this); fSet.Clear(); } bool Contains(const Key& key) const { const Locker* lock = this; MapLocker locker(const_cast(lock)); if (!locker.IsLocked()) return false; return fSet.Contains(key); } int32 Size() const { const Locker* lock = this; MapLocker locker(const_cast(lock)); return fSet.Size(); } Iterator GetIterator() const { return fSet.GetIterator(); } // for debugging only const HashSet& GetUnsynchronizedSet() const { return fSet; } HashSet& GetUnsynchronizedSet() { return fSet; } protected: typedef AutoLocker MapLocker; HashSet fSet; }; // HashSet // constructor template HashSet::HashSet() : fTable() { fTable.Init(); } // destructor template HashSet::~HashSet() { Clear(); } // InitCheck template status_t HashSet::InitCheck() const { return (fTable.TableSize() > 0 ? B_OK : B_NO_MEMORY); } // Add template status_t HashSet::Add(const Key& key) { Element* element = fTable.Lookup(key); if (element) { // already contains the value return B_OK; } // does not contain the key yet: create an element and add it element = new(std::nothrow) Element(key); if (!element) return B_NO_MEMORY; status_t error = fTable.Insert(element); if (error != B_OK) delete element; return error; } // Remove template bool HashSet::Remove(const Key& key) { Element* element = fTable.Lookup(key); if (element == NULL) return false; fTable.Remove(element); delete element; return true; } // Remove template bool HashSet::Remove(Iterator& it) { Element* element = it.fElement; if (element == NULL) return false; fTable.RemoveUnchecked(element); delete element; it.fElement = NULL; return true; } // Clear template void HashSet::Clear() { // clear the table and delete the elements Element* element = fTable.Clear(true); while (element != NULL) { Element* next = element->fNext; delete element; element = next; } } // Contains template bool HashSet::Contains(const Key& key) const { return fTable.Lookup(key) != NULL; } // Size template int32 HashSet::Size() const { return fTable.CountElements(); } // GetIterator template typename HashSet::Iterator HashSet::GetIterator() const { return Iterator(this); } } // namespace BPrivate using BPrivate::HashSet; #endif // HASH_SET_H