// HashSet.h // // Copyright (c) 2004, Ingo Weinhold (bonefish@cs.tu-berlin.de) // // Permission is hereby granted, free of charge, to any person obtaining a // copy of this software and associated documentation files (the "Software"), // to deal in the Software without restriction, including without limitation // the rights to use, copy, modify, merge, publish, distribute, sublicense, // and/or sell copies of the Software, and to permit persons to whom the // Software is furnished to do so, subject to the following conditions: // // The above copyright notice and this permission notice shall be included in // all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL // THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // // Except as contained in this notice, the name of a copyright holder shall // not be used in advertising or otherwise to promote the sale, use or other // dealings in this Software without prior written authorization of the // copyright holder. #ifndef HASH_SET_H #define HASH_SET_H #include #include "AutoLocker.h" #include "OpenHashTable.h" namespace BPrivate { // HashSetElement template class HashSetElement : public OpenHashElement { private: typedef HashSetElement Element; public: HashSetElement() : OpenHashElement(), fKey() { fNext = -1; } inline uint32 Hash() const { return fKey.GetHashCode(); } inline bool operator==(const OpenHashElement &_element) const { const Element &element = static_cast(_element); return (fKey == element.fKey); } inline void Adopt(Element &element) { fKey = element.fKey; } Key fKey; }; // HashSet template class HashSet { public: class Iterator { private: typedef HashSetElement Element; public: Iterator(const Iterator& other) : fSet(other.fSet), fIndex(other.fIndex), fElement(other.fElement), fLastElement(other.fElement) { } bool HasNext() const { return fElement; } Key Next() { if (!fElement) return Key(); Key result(fElement->fKey); _FindNext(); return result; } bool Remove() { if (!fLastElement) return false; fSet->fTable.Remove(fLastElement); fLastElement = NULL; return true; } Iterator& operator=(const Iterator& other) { fSet = other.fSet; fIndex = other.fIndex; fElement = other.fElement; fLastElement = other.fLastElement; return *this; } private: Iterator(HashSet* map) : fSet(map), fIndex(0), fElement(NULL), fLastElement(NULL) { // find first _FindNext(); } void _FindNext() { fLastElement = fElement; if (fElement && fElement->fNext >= 0) { fElement = fSet->fTable.ElementAt(fElement->fNext); return; } fElement = NULL; int32 arraySize = fSet->fTable.ArraySize(); for (; !fElement && fIndex < arraySize; fIndex++) fElement = fSet->fTable.FindFirst(fIndex); } private: friend class HashSet; HashSet* fSet; int32 fIndex; Element* fElement; Element* fLastElement; }; HashSet(); ~HashSet(); status_t InitCheck() const; status_t Add(const Key& key); bool Remove(const Key& key); void Clear(); bool Contains(const Key& key) const; int32 Size() const; bool IsEmpty() const { return Size() == 0; } Iterator GetIterator(); protected: typedef HashSetElement Element; friend class Iterator; private: Element *_FindElement(const Key& key) const; protected: OpenHashElementArray fElementArray; OpenHashTable > fTable; }; // SynchronizedHashSet template class SynchronizedHashSet : public BLocker { public: typedef typename HashSet::Iterator Iterator; SynchronizedHashSet() : BLocker("synchronized hash set") {} ~SynchronizedHashSet() { 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); } bool Contains(const Key& key) const { const BLocker* lock = this; MapLocker locker(const_cast(lock)); if (!locker.IsLocked()) return false; return fSet.Contains(key); } int32 Size() const { const BLocker* lock = this; MapLocker locker(const_cast(lock)); return fSet.Size(); } Iterator GetIterator() { 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() : fElementArray(1000), fTable(1000, &fElementArray) { } // destructor template HashSet::~HashSet() { } // InitCheck template status_t HashSet::InitCheck() const { return (fTable.InitCheck() && fElementArray.InitCheck() ? B_OK : B_NO_MEMORY); } // Add template status_t HashSet::Add(const Key& key) { if (Contains(key)) return B_OK; Element* element = fTable.Add(key.GetHashCode()); if (!element) return B_NO_MEMORY; element->fKey = key; return B_OK; } // Remove template bool HashSet::Remove(const Key& key) { if (Element* element = _FindElement(key)) { fTable.Remove(element); return true; } return false; } // Clear template void HashSet::Clear() { fTable.RemoveAll(); } // Contains template bool HashSet::Contains(const Key& key) const { return _FindElement(key); } // Size template int32 HashSet::Size() const { return fTable.CountElements(); } // GetIterator template typename HashSet::Iterator HashSet::GetIterator() { return Iterator(this); } // _FindElement template HashSetElement * HashSet::_FindElement(const Key& key) const { Element* element = fTable.FindFirst(key.GetHashCode()); while (element && element->fKey != key) { if (element->fNext >= 0) element = fTable.ElementAt(element->fNext); else element = NULL; } return element; } } // namespace BPrivate using BPrivate::HashSet; using BPrivate::SynchronizedHashSet; #endif // HASH_SET_H