From edb41bfb71e6092763688fdcf9d896a8d55f7975 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Thu, 14 Jan 2010 21:49:16 +0000 Subject: [PATCH] Added HashSet class based on the (OpenTracker) OpenHashTable code. This is currently similar to HashMap, which is also based on that version. The kernel has OpenHashTable by Hugo Santos, which is a bit nicer, but I didn't want to change too much code, although HashMap and HashSet exist for this as well. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@35077 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/shared/HashSet.h | 342 +++++++++++++++++++++++++++++++ 1 file changed, 342 insertions(+) create mode 100644 headers/private/shared/HashSet.h diff --git a/headers/private/shared/HashSet.h b/headers/private/shared/HashSet.h new file mode 100644 index 0000000000..ee7be71288 --- /dev/null +++ b/headers/private/shared/HashSet.h @@ -0,0 +1,342 @@ +// 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 struct 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 +struct HashSet::Iterator +HashSet::GetIterator() +{ + return Iterator(this); +} + +// _FindElement +template +struct HashSet::Element * +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