diff --git a/headers/private/shared/HashMap.h b/headers/private/shared/HashMap.h index ffd86436a6..453c56b506 100644 --- a/headers/private/shared/HashMap.h +++ b/headers/private/shared/HashMap.h @@ -1,75 +1,64 @@ -// HashMap.h -// -// Copyright (c) 2004-2007, 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. - +/* + * 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 -#include +#include #include "AutoLocker.h" -#include "OpenHashTable.h" +#include "Locker.h" -namespace BPrivate { - // HashMapElement template -class HashMapElement : public OpenHashElement { +class HashMapElement { private: typedef HashMapElement Element; + public: - - HashMapElement() : OpenHashElement(), fKey(), fValue() + HashMapElement() + : + fKey(), + fValue(), + fNext(NULL) { - fNext = -1; } - inline uint32 Hash() const + HashMapElement(const Key& key, const Value& value) + : + fKey(key), + fValue(value), + fNext(NULL) { - 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; - fValue = element.fValue; - } - - Key fKey; - Value fValue; + 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 { @@ -90,87 +79,64 @@ public: Iterator(const Iterator& other) : fMap(other.fMap), - fIndex(other.fIndex), - fElement(other.fElement), - fLastElement(other.fElement) + fIterator(other.fIterator), + fElement(other.fElement) { } bool HasNext() const { - return fElement; + return fIterator.HasNext(); } Entry Next() { - if (!fElement) - return Entry(); - Entry result(fElement->fKey, fElement->fValue); - _FindNext(); - return result; - } - - Value* NextValue() - { + fElement = fIterator.Next(); if (fElement == NULL) - return NULL; + return Entry(); - Value* value = &fElement->fValue; - _FindNext(); - return value; + return Entry(fElement->fKey, fElement->fValue); } Entry Remove() { - if (!fLastElement) + if (fElement == NULL) return Entry(); - Entry result(fLastElement->fKey, fLastElement->fValue); - fMap->fTable.Remove(fLastElement, true); - fLastElement = NULL; + + Entry result(fElement->fKey, fElement->fValue); + + fMap->fTable.RemoveUnchecked(fElement); + delete fElement; + fElement = NULL; + return result; } Iterator& operator=(const Iterator& other) { fMap = other.fMap; - fIndex = other.fIndex; + fIterator = other.fIterator; fElement = other.fElement; - fLastElement = other.fLastElement; return *this; } private: - Iterator(const HashMap* map) + Iterator(HashMap* map) : - fMap(const_cast*>(map)), - fIndex(0), - fElement(NULL), - fLastElement(NULL) + fMap(map), + fIterator(map->fTable.GetIterator()), + fElement(NULL) { - // find first - _FindNext(); - } - - void _FindNext() - { - fLastElement = fElement; - if (fElement && fElement->fNext >= 0) { - fElement = fMap->fTable.ElementAt(fElement->fNext); - return; - } - fElement = NULL; - int32 arraySize = fMap->fTable.ArraySize(); - for (; !fElement && fIndex < arraySize; fIndex++) - fElement = fMap->fTable.FindFirst(fIndex); } private: friend class HashMap; + typedef BOpenHashTable > + ElementTable; - HashMap* fMap; - int32 fIndex; - Element* fElement; - Element* fLastElement; + HashMap* fMap; + typename ElementTable::Iterator fIterator; + Element* fElement; }; HashMap(); @@ -178,38 +144,35 @@ public: status_t InitCheck() const; - status_t Put(const Key& key, Value value); + status_t Put(const Key& key, const Value& value); Value Remove(const Key& key); 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; + Iterator GetIterator(); protected: + typedef BOpenHashTable > ElementTable; typedef HashMapElement Element; friend class Iterator; -private: - Element *_FindElement(const Key& key) const; - protected: - OpenHashElementArray fElementArray; - OpenHashTable > fTable; + ElementTable fTable; }; + // SynchronizedHashMap template -class SynchronizedHashMap : public BLocker { +class SynchronizedHashMap : public Locker { public: - typedef struct HashMap::Entry Entry; - typedef struct HashMap::Iterator Iterator; + typedef typename HashMap::Entry Entry; + typedef typename HashMap::Iterator Iterator; - SynchronizedHashMap() : BLocker("synchronized hash map") {} + SynchronizedHashMap() : Locker("synchronized hash map") {} ~SynchronizedHashMap() { Lock(); } status_t InitCheck() const @@ -217,7 +180,7 @@ public: return fMap.InitCheck(); } - status_t Put(const Key& key, Value value) + status_t Put(const Key& key, const Value& value) { MapLocker locker(this); if (!locker.IsLocked()) @@ -241,8 +204,8 @@ public: Value Get(const Key& key) const { - const BLocker* lock = this; - MapLocker locker(const_cast(lock)); + const Locker* lock = this; + MapLocker locker(const_cast(lock)); if (!locker.IsLocked()) return Value(); return fMap.Get(key); @@ -250,8 +213,8 @@ public: bool ContainsKey(const Key& key) const { - const BLocker* lock = this; - MapLocker locker(const_cast(lock)); + const Locker* lock = this; + MapLocker locker(const_cast(lock)); if (!locker.IsLocked()) return false; return fMap.ContainsKey(key); @@ -259,8 +222,8 @@ public: int32 Size() const { - const BLocker* lock = this; - MapLocker locker(const_cast(lock)); + const Locker* lock = this; + MapLocker locker(const_cast(lock)); return fMap.Size(); } @@ -274,7 +237,7 @@ public: HashMap& GetUnsynchronizedMap() { return fMap; } protected: - typedef AutoLocker MapLocker; + typedef AutoLocker MapLocker; HashMap fMap; }; @@ -342,104 +305,150 @@ struct HashKey64 { }; +// 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() : - fElementArray(1000), - fTable(1000, &fElementArray) + fTable() { + fTable.Init(); } + // destructor template HashMap::~HashMap() { + Clear(); } + // InitCheck template status_t HashMap::InitCheck() const { - return (fTable.InitCheck() && fElementArray.InitCheck() - ? B_OK : B_NO_MEMORY); + return (fTable.TableSize() > 0 ? B_OK : B_NO_MEMORY); } + // Put template status_t -HashMap::Put(const Key& key, Value value) +HashMap::Put(const Key& key, const Value& value) { - Element* element = _FindElement(key); + 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: add an element - element = fTable.Add(key.GetHashCode()); + + // 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; - element->fKey = key; - element->fValue = value; - return B_OK; + + status_t error = fTable.Insert(element); + if (error != B_OK) + delete element; + + return error; } + // Remove template Value HashMap::Remove(const Key& key) { - Value value = Value(); - if (Element* element = _FindElement(key)) { - value = element->fValue; - fTable.Remove(element); - } + Element* element = fTable.Lookup(key); + if (element == NULL) + return Value(); + + fTable.Remove(element); + Value value = element->fValue; + delete element; + return value; } + // Clear template void HashMap::Clear() { - fTable.RemoveAll(); + // 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 = _FindElement(key)) + 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 = _FindElement(key)) { - _value = &element->fValue; - return true; - } - - return false; -} // ContainsKey template bool HashMap::ContainsKey(const Key& key) const { - return _FindElement(key); + return fTable.Lookup(key) != NULL; } + // Size template int32 @@ -448,34 +457,14 @@ HashMap::Size() const return fTable.CountElements(); } + // GetIterator template -class HashMap::Iterator -HashMap::GetIterator() const +typename HashMap::Iterator +HashMap::GetIterator() { return Iterator(this); } -// _FindElement -template -typename HashMap::Element * -HashMap::_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::HashMap; -using BPrivate::HashKey32; -using BPrivate::HashKey64; -using BPrivate::SynchronizedHashMap; #endif // HASH_MAP_H diff --git a/headers/private/shared/HashSet.h b/headers/private/shared/HashSet.h index 9a102d1f02..373f127ae8 100644 --- a/headers/private/shared/HashSet.h +++ b/headers/private/shared/HashSet.h @@ -1,72 +1,56 @@ -// 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. - +/* + * Copyright 2004-2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ #ifndef HASH_SET_H #define HASH_SET_H -#include +#include #include "AutoLocker.h" -#include "OpenHashTable.h" +#include "Locker.h" -namespace BPrivate { - // HashSetElement template -class HashSetElement : public OpenHashElement { +class HashSetElement : public HashTableLink > { private: typedef HashSetElement Element; + public: - - HashSetElement() : OpenHashElement(), fKey() + HashSetElement() + : + fKey() { - fNext = -1; } - inline uint32 Hash() const + HashSetElement(const Key& key) + : + fKey(key) { - 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; }; + +// 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; } + HashTableLink* GetLink(ValueType* value) const + { return value; } +}; + + // HashSet template class HashSet { @@ -76,76 +60,66 @@ public: typedef HashSetElement Element; public: Iterator(const Iterator& other) - : fSet(other.fSet), - fIndex(other.fIndex), - fElement(other.fElement), - fLastElement(other.fElement) + : + fSet(other.fSet), + fIterator(other.fIterator), + fElement(other.fElement) { } bool HasNext() const { - return fElement; + return fIterator.HasNext(); } Key Next() { - if (!fElement) + fElement = fIterator.Next(); + if (fElement == NULL) return Key(); - Key result(fElement->fKey); - _FindNext(); - return result; + + return fElement->fKey; } bool Remove() { - if (!fLastElement) + if (fElement == NULL) return false; - fSet->fTable.Remove(fLastElement); - fLastElement = NULL; + + fSet->fTable.RemoveUnchecked(fElement); + delete fElement; + fElement = NULL; + return true; } Iterator& operator=(const Iterator& other) { fSet = other.fSet; - fIndex = other.fIndex; + fIterator = other.fIterator; fElement = other.fElement; - fLastElement = other.fLastElement; return *this; } private: - Iterator(HashSet* map) - : fSet(map), - fIndex(0), - fElement(NULL), - fLastElement(NULL) + Iterator(HashSet* set) + : + fSet(set), + fIterator(set->fTable.GetIterator()), + fElement(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; + friend class HashMap; + typedef OpenHashTable > ElementTable; - HashSet* fSet; - int32 fIndex; - Element* fElement; - Element* fLastElement; + HashSet* fSet; + ElementTable::Iterator fIterator; + Element* fElement; + + private: + friend class HashSet; }; HashSet(); @@ -159,29 +133,26 @@ public: bool Contains(const Key& key) const; int32 Size() const; - bool IsEmpty() const { return Size() == 0; } Iterator GetIterator(); protected: + typedef OpenHashTable > ElementTable; typedef HashSetElement Element; friend class Iterator; -private: - Element *_FindElement(const Key& key) const; - protected: - OpenHashElementArray fElementArray; - OpenHashTable > fTable; + ElementTable fTable; }; + // SynchronizedHashSet template -class SynchronizedHashSet : public BLocker { +class SynchronizedHashSet : public Locker { public: - typedef typename HashSet::Iterator Iterator; + typedef HashSet::Iterator Iterator; - SynchronizedHashSet() : BLocker("synchronized hash set") {} + SynchronizedHashSet() : Locker("synchronized hash set") {} ~SynchronizedHashSet() { Lock(); } status_t InitCheck() const @@ -205,10 +176,16 @@ public: return fSet.Remove(key); } + void Clear() + { + MapLocker locker(this); + fSet.Clear(); + } + bool Contains(const Key& key) const { - const BLocker* lock = this; - MapLocker locker(const_cast(lock)); + const Locker* lock = this; + MapLocker locker(const_cast(lock)); if (!locker.IsLocked()) return false; return fSet.Contains(key); @@ -216,8 +193,8 @@ public: int32 Size() const { - const BLocker* lock = this; - MapLocker locker(const_cast(lock)); + const Locker* lock = this; + MapLocker locker(const_cast(lock)); return fSet.Size(); } @@ -231,78 +208,105 @@ public: HashSet& GetUnsynchronizedSet() { return fSet; } protected: - typedef AutoLocker MapLocker; + typedef AutoLocker MapLocker; HashSet fSet; }; + // HashSet // constructor template HashSet::HashSet() - : fElementArray(1000), - fTable(1000, &fElementArray) + : + fTable() { + fTable.Init(); } + // destructor template HashSet::~HashSet() { + Clear(); } + // InitCheck template status_t HashSet::InitCheck() const { - return (fTable.InitCheck() && fElementArray.InitCheck() - ? B_OK : B_NO_MEMORY); + return (fTable.TableSize() > 0 ? B_OK : B_NO_MEMORY); } + // Add template status_t HashSet::Add(const Key& key) { - if (Contains(key)) + Element* element = fTable.Lookup(key); + if (element) { + // already contains the value return B_OK; - Element* element = fTable.Add(key.GetHashCode()); + } + + // does not contain the key yet: create an element and add it + element = new(std::nothrow) Element(key); if (!element) return B_NO_MEMORY; - element->fKey = key; - return B_OK; + + status_t error = fTable.Insert(element); + if (error != B_OK) + delete element; + + return error; } + // Remove template bool HashSet::Remove(const Key& key) { - if (Element* element = _FindElement(key)) { - fTable.Remove(element); - return true; - } - return false; + Element* element = fTable.Lookup(key); + if (element == NULL) + return false; + + fTable.Remove(element); + delete element; + + return true; } + // Clear -template +template void HashSet::Clear() { - fTable.RemoveAll(); + // 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 _FindElement(key); + return fTable.Lookup(key) != NULL; } + // Size template int32 @@ -313,7 +317,7 @@ HashSet::Size() const // GetIterator template -typename HashSet::Iterator +HashSet::Iterator HashSet::GetIterator() { return Iterator(this); @@ -321,7 +325,7 @@ HashSet::GetIterator() // _FindElement template -HashSetElement * +HashSet::Element * HashSet::_FindElement(const Key& key) const { Element* element = fTable.FindFirst(key.GetHashCode()); @@ -334,9 +338,5 @@ HashSet::_FindElement(const Key& key) const return element; } -} // namespace BPrivate - -using BPrivate::HashSet; -using BPrivate::SynchronizedHashSet; #endif // HASH_SET_H diff --git a/headers/private/shared/OpenHashTable.h b/headers/private/shared/OpenHashTable.h index eb000595c6..1c11602ed0 100644 --- a/headers/private/shared/OpenHashTable.h +++ b/headers/private/shared/OpenHashTable.h @@ -1,514 +1 @@ -/* -Open Tracker License - -Terms and Conditions - -Copyright (c) 1991-2000, Be Incorporated. All rights reserved. - -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 applies to all licensees -and 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 TITLE, MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -BE INCORPORATED 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 Be Incorporated shall not be -used in advertising or otherwise to promote the sale, use or other dealings in -this Software without prior written authorization from Be Incorporated. - -Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks -of Be Incorporated in the United States and other countries. Other brand product -names are registered trademarks or trademarks of their respective holders. -All rights reserved. -*/ - -// bonefish: -// * removed need for exceptions -// * fixed warnings -// * implemented rehashing -// * added RemoveAll() -// TODO: -// * shrinking of element vectors - -// Hash table with open addresssing - -#ifndef __OPEN_HASH_TABLE__ -#define __OPEN_HASH_TABLE__ - -#include -#include - -// don't include -#ifndef _OPEN_HASH_TABLE_ASSERT -# define _OPEN_HASH_TABLE_ASSERT(E) (void)0 -#endif -#ifndef _OPEN_HASH_TABLE_TRESPASS -# define _OPEN_HASH_TABLE_TRESPASS() (void)0 -#endif - -namespace BPrivate { - -template -class ElementVector { - // element vector for OpenHashTable needs to implement this - // interface -public: - Element &At(int32 index); - Element *Add(); - int32 IndexOf(const Element &) const; - void Remove(int32 index); -}; - -class OpenHashElement { -public: - uint32 Hash() const; - bool operator==(const OpenHashElement &) const; - void Adopt(OpenHashElement &); - // low overhead copy, original element is in undefined state - // after call (calls Adopt on BString members, etc.) - int32 fNext; -}; - -const uint32 kPrimes [] = { - 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139, - 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859, - 134217689, 268435399, 536870909, 1073741789, 2147483647, 0 -}; - -template > -class OpenHashTable { -public: - OpenHashTable(int32 minSize, ElementVec *elementVector = 0, - float maxLoadFactor = 0.8); - // it is up to the subclass of OpenHashTable to supply - // elementVector - ~OpenHashTable(); - - bool InitCheck() const; - - void SetElementVector(ElementVec *elementVector); - - Element *FindFirst(uint32 elementHash) const; - Element *Add(uint32 elementHash); - - void Remove(Element *element, bool dontRehash = false); - void RemoveAll(); - - // when calling Add, any outstanding element pointer may become - // invalid; to deal with this, get the element index and restore - // it after the add - int32 ElementIndex(const Element *) const; - Element *ElementAt(int32 index) const; - - int32 ArraySize() const; - int32 VectorSize() const; - int32 CountElements() const; - -protected: - static int32 OptimalSize(int32 minSize); - -private: - bool _RehashIfNeeded(); - bool _Rehash(); - - int32 fArraySize; - int32 fInitialSize; - int32 fElementCount; - int32 *fHashArray; - ElementVec *fElementVector; - float fMaxLoadFactor; -}; - -template -class OpenHashElementArray : public ElementVector { - // this is a straightforward implementation of an element vector - // deleting is handled by linking deleted elements into a free list - // the vector never shrinks -public: - OpenHashElementArray(int32 initialSize); - ~OpenHashElementArray(); - - bool InitCheck() const; - - Element &At(int32 index); - const Element &At(int32 index) const; - Element *Add(const Element &); - Element *Add(); - void Remove(int32 index); - int32 IndexOf(const Element &) const; - int32 Size() const; - -private: - Element *fData; - int32 fSize; - int32 fNextFree; - int32 fNextDeleted; -}; - - -//----------------------------------- - -template -OpenHashTable::OpenHashTable(int32 minSize, - ElementVec *elementVector, float maxLoadFactor) - : fArraySize(OptimalSize(minSize)), - fInitialSize(fArraySize), - fElementCount(0), - fElementVector(elementVector), - fMaxLoadFactor(maxLoadFactor) -{ - // sanity check the maximal load factor - if (fMaxLoadFactor < 0.5) - fMaxLoadFactor = 0.5; - // allocate and init the array - fHashArray = (int32*)calloc(fArraySize, sizeof(int32)); - if (fHashArray) { - for (int32 index = 0; index < fArraySize; index++) - fHashArray[index] = -1; - } -} - -template -OpenHashTable::~OpenHashTable() -{ - RemoveAll(); - free(fHashArray); -} - -template -bool -OpenHashTable::InitCheck() const -{ - return (fHashArray && fElementVector); -} - -template -int32 -OpenHashTable::OptimalSize(int32 minSize) -{ - for (int32 index = 0; ; index++) - if (!kPrimes[index] || kPrimes[index] >= (uint32)minSize) - return (int32)kPrimes[index]; - - return 0; -} - -template -Element * -OpenHashTable::FindFirst(uint32 hash) const -{ - _OPEN_HASH_TABLE_ASSERT(fElementVector); - hash %= fArraySize; - if (fHashArray[hash] < 0) - return 0; - - return &fElementVector->At(fHashArray[hash]); -} - -template -int32 -OpenHashTable::ElementIndex(const Element *element) const -{ - return fElementVector->IndexOf(*element); -} - -template -Element * -OpenHashTable::ElementAt(int32 index) const -{ - return &fElementVector->At(index); -} - -template -int32 -OpenHashTable::ArraySize() const -{ - return fArraySize; -} - -template -int32 -OpenHashTable::VectorSize() const -{ - return fElementVector->Size(); -} - -template -int32 -OpenHashTable::CountElements() const -{ - return fElementCount; -} - - -template -Element * -OpenHashTable::Add(uint32 hash) -{ - _OPEN_HASH_TABLE_ASSERT(fElementVector); - _RehashIfNeeded(); - hash %= fArraySize; - Element *result = fElementVector->Add(); - if (result) { - result->fNext = fHashArray[hash]; - fHashArray[hash] = fElementVector->IndexOf(*result); - fElementCount++; - } - return result; -} - -template -void -OpenHashTable::Remove(Element *element, bool dontRehash) -{ - if (!dontRehash) - _RehashIfNeeded(); - uint32 hash = element->Hash() % fArraySize; - int32 next = fHashArray[hash]; - _OPEN_HASH_TABLE_ASSERT(next >= 0); - - if (&fElementVector->At(next) == element) { - fHashArray[hash] = element->fNext; - fElementVector->Remove(next); - fElementCount--; - return; - } - - for (int32 index = next; index >= 0; ) { - // look for an existing match in table - next = fElementVector->At(index).fNext; - if (next < 0) { - _OPEN_HASH_TABLE_TRESPASS(); - return; - } - - if (&fElementVector->At(next) == element) { - fElementVector->At(index).fNext = element->fNext; - fElementVector->Remove(next); - fElementCount--; - return; - } - index = next; - } -} - -template -void -OpenHashTable::RemoveAll() -{ - for (int32 i = 0; fElementCount > 0 && i < fArraySize; i++) { - int32 index = fHashArray[i]; - while (index >= 0) { - Element* element = &fElementVector->At(index); - int32 next = element->fNext; - fElementVector->Remove(index); - fElementCount--; - index = next; - } - fHashArray[i] = -1; - } - _RehashIfNeeded(); -} - -template -void -OpenHashTable::SetElementVector(ElementVec *elementVector) -{ - fElementVector = elementVector; -} - -// _RehashIfNeeded -template -bool -OpenHashTable::_RehashIfNeeded() -{ - // The load factor range [fMaxLoadFactor / 3, fMaxLoadFactor] is fine, - // I think. After rehashing the load factor will be about - // fMaxLoadFactor * 2 / 3, respectively fMaxLoadFactor / 2. - float loadFactor = (float)fElementCount / (float)fArraySize; - if (loadFactor > fMaxLoadFactor - || (fArraySize > fInitialSize && loadFactor < fMaxLoadFactor / 3)) { - return _Rehash(); - } - return true; -} - -// _Rehash -template -bool -OpenHashTable::_Rehash() -{ - bool result = true; - int32 newSize = int32(fElementCount * 1.73 * fMaxLoadFactor); - newSize = (fInitialSize > newSize ? fInitialSize : newSize); - if (newSize != fArraySize) { - // allocate a new array - int32 *newHashArray = (int32*)calloc(newSize, sizeof(int32)); - if (newHashArray) { - // init the new hash array - for (int32 index = 0; index < newSize; index++) - newHashArray[index] = -1; - // iterate through all elements and put them into the new - // hash array - for (int i = 0; i < fArraySize; i++) { - int32 index = fHashArray[i]; - while (index >= 0) { - // insert the element in the new array - Element &element = fElementVector->At(index); - int32 next = element.fNext; - uint32 hash = (element.Hash() % newSize); - element.fNext = newHashArray[hash]; - newHashArray[hash] = index; - // next element in old list - index = next; - } - } - // delete the old array and set the new one - free(fHashArray); - fHashArray = newHashArray; - fArraySize = newSize; - } else - result = false; - } - return result; -} - - -template -OpenHashElementArray::OpenHashElementArray(int32 initialSize) - : fSize(initialSize), - fNextFree(0), - fNextDeleted(-1) -{ - fData = (Element*)calloc((size_t)initialSize, sizeof(Element)); -} - -template -OpenHashElementArray::~OpenHashElementArray() -{ - free(fData); -} - -template -bool -OpenHashElementArray::InitCheck() const -{ - return fData; -} - -template -Element & -OpenHashElementArray::At(int32 index) -{ - _OPEN_HASH_TABLE_ASSERT(index < fSize); - return fData[index]; -} - -template -const Element & -OpenHashElementArray::At(int32 index) const -{ - _OPEN_HASH_TABLE_ASSERT(index < fSize); - return fData[index]; -} - -template -int32 -OpenHashElementArray::IndexOf(const Element &element) const -{ - int32 result = &element - fData; - if (result < 0 || result > fSize) - return -1; - - return result; -} - -template -int32 -OpenHashElementArray::Size() const -{ - return fSize; -} - - -template -Element * -OpenHashElementArray::Add(const Element &newElement) -{ - Element *element = Add(); - if (element) - element->Adopt(newElement); - return element; -} - -#if DEBUG -const int32 kGrowChunk = 10; -#else -const int32 kGrowChunk = 1024; -#endif - -template -Element * -OpenHashElementArray::Add() -{ - int32 index = fNextFree; - if (fNextDeleted >= 0) { - index = fNextDeleted; - fNextDeleted = At(index).fNext; - } else if (fNextFree >= fSize - 1) { - int32 newSize = fSize + kGrowChunk; -/* - Element *newData = (Element *)calloc((size_t)newSize , sizeof(Element)); - if (!newData) - return NULL; - memcpy(newData, fData, fSize * sizeof(Element)); - free(fData); -*/ - Element *newData = (Element*)realloc(fData, - (size_t)newSize * sizeof(Element)); - if (!newData) - return NULL; - - fData = newData; - fSize = newSize; - index = fNextFree; - fNextFree++; - } else - fNextFree++; - - new (&At(index)) Element; - // call placement new to initialize the element properly - _OPEN_HASH_TABLE_ASSERT(At(index).fNext == -1); - - return &At(index); -} - -template -void -OpenHashElementArray::Remove(int32 index) -{ - // delete by chaining empty elements in a single linked - // list, reusing the next field - _OPEN_HASH_TABLE_ASSERT(index < fSize); - At(index).~Element(); - // call the destructor explicitly to destroy the element - // properly - At(index).fNext = fNextDeleted; - fNextDeleted = index; -} - -} // namespace BPrivate - -using BPrivate::OpenHashTable; - -#endif // __OPEN_HASH_TABLE__ +#include <../kernel/util/OpenHashTable.h> diff --git a/headers/private/userlandfs/shared/HashMap.h b/headers/private/userlandfs/shared/HashMap.h deleted file mode 100644 index 70e93d9da9..0000000000 --- a/headers/private/userlandfs/shared/HashMap.h +++ /dev/null @@ -1,470 +0,0 @@ -/* - * 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 - -#include - -#include "AutoLocker.h" -#include "Locker.h" - - -// 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); - } - - 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* map) - : - fMap(map), - fIterator(map->fTable.GetIterator()), - fElement(NULL) - { - } - - private: - friend class HashMap; - typedef BOpenHashTable > - ElementTable; - - 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); - void Clear(); - Value Get(const Key& key) const; - - bool ContainsKey(const Key& key) const; - - int32 Size() const; - - Iterator GetIterator(); - -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); - return 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; -} - - -// 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(); -} - - -// 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() -{ - return Iterator(this); -} - - -#endif // HASH_MAP_H diff --git a/headers/private/userlandfs/shared/HashSet.h b/headers/private/userlandfs/shared/HashSet.h deleted file mode 100644 index 373f127ae8..0000000000 --- a/headers/private/userlandfs/shared/HashSet.h +++ /dev/null @@ -1,342 +0,0 @@ -/* - * Copyright 2004-2009, Ingo Weinhold, ingo_weinhold@gmx.de. - * Distributed under the terms of the MIT License. - */ -#ifndef HASH_SET_H -#define HASH_SET_H - -#include - -#include "AutoLocker.h" -#include "Locker.h" - - -// HashSetElement -template -class HashSetElement : public HashTableLink > { -private: - typedef HashSetElement Element; - -public: - HashSetElement() - : - fKey() - { - } - - HashSetElement(const Key& key) - : - fKey(key) - { - } - - Key fKey; -}; - - -// 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; } - HashTableLink* GetLink(ValueType* value) const - { return value; } -}; - - -// 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; - } - - bool Remove() - { - if (fElement == NULL) - return false; - - fSet->fTable.RemoveUnchecked(fElement); - delete fElement; - fElement = NULL; - - return true; - } - - Iterator& operator=(const Iterator& other) - { - fSet = other.fSet; - fIterator = other.fIterator; - fElement = other.fElement; - return *this; - } - - private: - Iterator(HashSet* set) - : - fSet(set), - fIterator(set->fTable.GetIterator()), - fElement(NULL) - { - } - - private: - friend class HashMap; - typedef OpenHashTable > ElementTable; - - HashSet* fSet; - 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); - void Clear(); - bool Contains(const Key& key) const; - - int32 Size() const; - - Iterator GetIterator(); - -protected: - typedef OpenHashTable > ElementTable; - typedef HashSetElement Element; - friend class Iterator; - -protected: - ElementTable fTable; -}; - - -// SynchronizedHashSet -template -class SynchronizedHashSet : public Locker { -public: - typedef HashSet::Iterator Iterator; - - SynchronizedHashSet() : Locker("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); - } - - 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() - { - 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; -} - - -// 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 -HashSet::Iterator -HashSet::GetIterator() -{ - return Iterator(this); -} - -// _FindElement -template -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; -} - - -#endif // HASH_SET_H diff --git a/src/kits/tracker/OpenHashTable.h b/src/kits/tracker/OpenHashTable.h new file mode 100644 index 0000000000..eb000595c6 --- /dev/null +++ b/src/kits/tracker/OpenHashTable.h @@ -0,0 +1,514 @@ +/* +Open Tracker License + +Terms and Conditions + +Copyright (c) 1991-2000, Be Incorporated. All rights reserved. + +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 applies to all licensees +and 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 TITLE, MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +BE INCORPORATED 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 Be Incorporated shall not be +used in advertising or otherwise to promote the sale, use or other dealings in +this Software without prior written authorization from Be Incorporated. + +Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks +of Be Incorporated in the United States and other countries. Other brand product +names are registered trademarks or trademarks of their respective holders. +All rights reserved. +*/ + +// bonefish: +// * removed need for exceptions +// * fixed warnings +// * implemented rehashing +// * added RemoveAll() +// TODO: +// * shrinking of element vectors + +// Hash table with open addresssing + +#ifndef __OPEN_HASH_TABLE__ +#define __OPEN_HASH_TABLE__ + +#include +#include + +// don't include +#ifndef _OPEN_HASH_TABLE_ASSERT +# define _OPEN_HASH_TABLE_ASSERT(E) (void)0 +#endif +#ifndef _OPEN_HASH_TABLE_TRESPASS +# define _OPEN_HASH_TABLE_TRESPASS() (void)0 +#endif + +namespace BPrivate { + +template +class ElementVector { + // element vector for OpenHashTable needs to implement this + // interface +public: + Element &At(int32 index); + Element *Add(); + int32 IndexOf(const Element &) const; + void Remove(int32 index); +}; + +class OpenHashElement { +public: + uint32 Hash() const; + bool operator==(const OpenHashElement &) const; + void Adopt(OpenHashElement &); + // low overhead copy, original element is in undefined state + // after call (calls Adopt on BString members, etc.) + int32 fNext; +}; + +const uint32 kPrimes [] = { + 509, 1021, 2039, 4093, 8191, 16381, 32749, 65521, 131071, 262139, + 524287, 1048573, 2097143, 4194301, 8388593, 16777213, 33554393, 67108859, + 134217689, 268435399, 536870909, 1073741789, 2147483647, 0 +}; + +template > +class OpenHashTable { +public: + OpenHashTable(int32 minSize, ElementVec *elementVector = 0, + float maxLoadFactor = 0.8); + // it is up to the subclass of OpenHashTable to supply + // elementVector + ~OpenHashTable(); + + bool InitCheck() const; + + void SetElementVector(ElementVec *elementVector); + + Element *FindFirst(uint32 elementHash) const; + Element *Add(uint32 elementHash); + + void Remove(Element *element, bool dontRehash = false); + void RemoveAll(); + + // when calling Add, any outstanding element pointer may become + // invalid; to deal with this, get the element index and restore + // it after the add + int32 ElementIndex(const Element *) const; + Element *ElementAt(int32 index) const; + + int32 ArraySize() const; + int32 VectorSize() const; + int32 CountElements() const; + +protected: + static int32 OptimalSize(int32 minSize); + +private: + bool _RehashIfNeeded(); + bool _Rehash(); + + int32 fArraySize; + int32 fInitialSize; + int32 fElementCount; + int32 *fHashArray; + ElementVec *fElementVector; + float fMaxLoadFactor; +}; + +template +class OpenHashElementArray : public ElementVector { + // this is a straightforward implementation of an element vector + // deleting is handled by linking deleted elements into a free list + // the vector never shrinks +public: + OpenHashElementArray(int32 initialSize); + ~OpenHashElementArray(); + + bool InitCheck() const; + + Element &At(int32 index); + const Element &At(int32 index) const; + Element *Add(const Element &); + Element *Add(); + void Remove(int32 index); + int32 IndexOf(const Element &) const; + int32 Size() const; + +private: + Element *fData; + int32 fSize; + int32 fNextFree; + int32 fNextDeleted; +}; + + +//----------------------------------- + +template +OpenHashTable::OpenHashTable(int32 minSize, + ElementVec *elementVector, float maxLoadFactor) + : fArraySize(OptimalSize(minSize)), + fInitialSize(fArraySize), + fElementCount(0), + fElementVector(elementVector), + fMaxLoadFactor(maxLoadFactor) +{ + // sanity check the maximal load factor + if (fMaxLoadFactor < 0.5) + fMaxLoadFactor = 0.5; + // allocate and init the array + fHashArray = (int32*)calloc(fArraySize, sizeof(int32)); + if (fHashArray) { + for (int32 index = 0; index < fArraySize; index++) + fHashArray[index] = -1; + } +} + +template +OpenHashTable::~OpenHashTable() +{ + RemoveAll(); + free(fHashArray); +} + +template +bool +OpenHashTable::InitCheck() const +{ + return (fHashArray && fElementVector); +} + +template +int32 +OpenHashTable::OptimalSize(int32 minSize) +{ + for (int32 index = 0; ; index++) + if (!kPrimes[index] || kPrimes[index] >= (uint32)minSize) + return (int32)kPrimes[index]; + + return 0; +} + +template +Element * +OpenHashTable::FindFirst(uint32 hash) const +{ + _OPEN_HASH_TABLE_ASSERT(fElementVector); + hash %= fArraySize; + if (fHashArray[hash] < 0) + return 0; + + return &fElementVector->At(fHashArray[hash]); +} + +template +int32 +OpenHashTable::ElementIndex(const Element *element) const +{ + return fElementVector->IndexOf(*element); +} + +template +Element * +OpenHashTable::ElementAt(int32 index) const +{ + return &fElementVector->At(index); +} + +template +int32 +OpenHashTable::ArraySize() const +{ + return fArraySize; +} + +template +int32 +OpenHashTable::VectorSize() const +{ + return fElementVector->Size(); +} + +template +int32 +OpenHashTable::CountElements() const +{ + return fElementCount; +} + + +template +Element * +OpenHashTable::Add(uint32 hash) +{ + _OPEN_HASH_TABLE_ASSERT(fElementVector); + _RehashIfNeeded(); + hash %= fArraySize; + Element *result = fElementVector->Add(); + if (result) { + result->fNext = fHashArray[hash]; + fHashArray[hash] = fElementVector->IndexOf(*result); + fElementCount++; + } + return result; +} + +template +void +OpenHashTable::Remove(Element *element, bool dontRehash) +{ + if (!dontRehash) + _RehashIfNeeded(); + uint32 hash = element->Hash() % fArraySize; + int32 next = fHashArray[hash]; + _OPEN_HASH_TABLE_ASSERT(next >= 0); + + if (&fElementVector->At(next) == element) { + fHashArray[hash] = element->fNext; + fElementVector->Remove(next); + fElementCount--; + return; + } + + for (int32 index = next; index >= 0; ) { + // look for an existing match in table + next = fElementVector->At(index).fNext; + if (next < 0) { + _OPEN_HASH_TABLE_TRESPASS(); + return; + } + + if (&fElementVector->At(next) == element) { + fElementVector->At(index).fNext = element->fNext; + fElementVector->Remove(next); + fElementCount--; + return; + } + index = next; + } +} + +template +void +OpenHashTable::RemoveAll() +{ + for (int32 i = 0; fElementCount > 0 && i < fArraySize; i++) { + int32 index = fHashArray[i]; + while (index >= 0) { + Element* element = &fElementVector->At(index); + int32 next = element->fNext; + fElementVector->Remove(index); + fElementCount--; + index = next; + } + fHashArray[i] = -1; + } + _RehashIfNeeded(); +} + +template +void +OpenHashTable::SetElementVector(ElementVec *elementVector) +{ + fElementVector = elementVector; +} + +// _RehashIfNeeded +template +bool +OpenHashTable::_RehashIfNeeded() +{ + // The load factor range [fMaxLoadFactor / 3, fMaxLoadFactor] is fine, + // I think. After rehashing the load factor will be about + // fMaxLoadFactor * 2 / 3, respectively fMaxLoadFactor / 2. + float loadFactor = (float)fElementCount / (float)fArraySize; + if (loadFactor > fMaxLoadFactor + || (fArraySize > fInitialSize && loadFactor < fMaxLoadFactor / 3)) { + return _Rehash(); + } + return true; +} + +// _Rehash +template +bool +OpenHashTable::_Rehash() +{ + bool result = true; + int32 newSize = int32(fElementCount * 1.73 * fMaxLoadFactor); + newSize = (fInitialSize > newSize ? fInitialSize : newSize); + if (newSize != fArraySize) { + // allocate a new array + int32 *newHashArray = (int32*)calloc(newSize, sizeof(int32)); + if (newHashArray) { + // init the new hash array + for (int32 index = 0; index < newSize; index++) + newHashArray[index] = -1; + // iterate through all elements and put them into the new + // hash array + for (int i = 0; i < fArraySize; i++) { + int32 index = fHashArray[i]; + while (index >= 0) { + // insert the element in the new array + Element &element = fElementVector->At(index); + int32 next = element.fNext; + uint32 hash = (element.Hash() % newSize); + element.fNext = newHashArray[hash]; + newHashArray[hash] = index; + // next element in old list + index = next; + } + } + // delete the old array and set the new one + free(fHashArray); + fHashArray = newHashArray; + fArraySize = newSize; + } else + result = false; + } + return result; +} + + +template +OpenHashElementArray::OpenHashElementArray(int32 initialSize) + : fSize(initialSize), + fNextFree(0), + fNextDeleted(-1) +{ + fData = (Element*)calloc((size_t)initialSize, sizeof(Element)); +} + +template +OpenHashElementArray::~OpenHashElementArray() +{ + free(fData); +} + +template +bool +OpenHashElementArray::InitCheck() const +{ + return fData; +} + +template +Element & +OpenHashElementArray::At(int32 index) +{ + _OPEN_HASH_TABLE_ASSERT(index < fSize); + return fData[index]; +} + +template +const Element & +OpenHashElementArray::At(int32 index) const +{ + _OPEN_HASH_TABLE_ASSERT(index < fSize); + return fData[index]; +} + +template +int32 +OpenHashElementArray::IndexOf(const Element &element) const +{ + int32 result = &element - fData; + if (result < 0 || result > fSize) + return -1; + + return result; +} + +template +int32 +OpenHashElementArray::Size() const +{ + return fSize; +} + + +template +Element * +OpenHashElementArray::Add(const Element &newElement) +{ + Element *element = Add(); + if (element) + element->Adopt(newElement); + return element; +} + +#if DEBUG +const int32 kGrowChunk = 10; +#else +const int32 kGrowChunk = 1024; +#endif + +template +Element * +OpenHashElementArray::Add() +{ + int32 index = fNextFree; + if (fNextDeleted >= 0) { + index = fNextDeleted; + fNextDeleted = At(index).fNext; + } else if (fNextFree >= fSize - 1) { + int32 newSize = fSize + kGrowChunk; +/* + Element *newData = (Element *)calloc((size_t)newSize , sizeof(Element)); + if (!newData) + return NULL; + memcpy(newData, fData, fSize * sizeof(Element)); + free(fData); +*/ + Element *newData = (Element*)realloc(fData, + (size_t)newSize * sizeof(Element)); + if (!newData) + return NULL; + + fData = newData; + fSize = newSize; + index = fNextFree; + fNextFree++; + } else + fNextFree++; + + new (&At(index)) Element; + // call placement new to initialize the element properly + _OPEN_HASH_TABLE_ASSERT(At(index).fNext == -1); + + return &At(index); +} + +template +void +OpenHashElementArray::Remove(int32 index) +{ + // delete by chaining empty elements in a single linked + // list, reusing the next field + _OPEN_HASH_TABLE_ASSERT(index < fSize); + At(index).~Element(); + // call the destructor explicitly to destroy the element + // properly + At(index).fNext = fNextDeleted; + fNextDeleted = index; +} + +} // namespace BPrivate + +using BPrivate::OpenHashTable; + +#endif // __OPEN_HASH_TABLE__ diff --git a/src/system/kernel/fs/rootfs.cpp b/src/system/kernel/fs/rootfs.cpp index 61678a6b2f..b60ef39927 100644 --- a/src/system/kernel/fs/rootfs.cpp +++ b/src/system/kernel/fs/rootfs.cpp @@ -10,7 +10,7 @@ #if FS_SHELL # include "fssh_api_wrapper.h" -# include "KOpenHashTable.h" +# include "OpenHashTable.h" # include "list.h" #else # include diff --git a/src/tools/fs_shell/KOpenHashTable.h b/src/tools/fs_shell/OpenHashTable.h similarity index 100% rename from src/tools/fs_shell/KOpenHashTable.h rename to src/tools/fs_shell/OpenHashTable.h