Removed the OpenHashTable implementation the UserlandFS used. Adjusted the

HashMap and HashSet classes to use the kernel utils OpenHashTable instead.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@29429 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Ingo Weinhold
2009-03-07 21:21:10 +00:00
parent 2d4fb82c0f
commit 484708d5d6
4 changed files with 243 additions and 752 deletions
+113 -129
View File
@@ -1,72 +1,61 @@
// HashMap.h
//
// Copyright (c) 2004, Ingo Weinhold ([email protected])
//
// 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, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef HASH_MAP_H
#define HASH_MAP_H
//#include <Debug.h>
#include <util/OpenHashTable.h>
#include "AutoLocker.h"
#include "Locker.h"
#include "OpenHashTable.h"
// HashMapElement
template<typename Key, typename Value>
class HashMapElement : public OpenHashElement {
class HashMapElement : public HashTableLink<HashMapElement<Key, Value> > {
private:
typedef HashMapElement<Key, Value> Element;
public:
HashMapElement() : OpenHashElement(), fKey(), fValue()
HashMapElement()
:
fKey(),
fValue()
{
fNext = -1;
}
inline uint32 Hash() const
HashMapElement(const Key& key, const Value& value)
:
fKey(key),
fValue(value)
{
return fKey.GetHashCode();
}
inline bool operator==(const OpenHashElement &_element) const
{
const Element &element = static_cast<const Element&>(_element);
return (fKey == element.fKey);
}
inline void Adopt(Element &element)
{
fKey = element.fKey;
fValue = element.fValue;
}
Key fKey;
Value fValue;
};
// HashMapTableDefinition
template<typename Key, typename Value>
struct HashMapTableDefinition {
typedef Key KeyType;
typedef HashMapElement<Key, Value> 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<ValueType>* GetLink(ValueType* value) const
{ return value; }
};
// HashMap
template<typename Key, typename Value>
class HashMap {
@@ -85,77 +74,65 @@ public:
typedef HashMapElement<Key, Value> Element;
public:
Iterator(const Iterator& other)
: fMap(other.fMap),
fIndex(other.fIndex),
fElement(other.fElement),
fLastElement(other.fElement)
:
fMap(other.fMap),
fIterator(other.fIterator),
fElement(other.fElement)
{
}
bool HasNext() const
{
return fElement;
return fIterator.HasNext();
}
Entry Next()
{
if (!fElement)
fElement = fIterator.Next();
if (fElement == NULL)
return Entry();
Entry result(fElement->fKey, fElement->fValue);
_FindNext();
return result;
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(HashMap<Key, Value>* map)
: fMap(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<Key, Value>;
typedef OpenHashTable<HashMapTableDefinition<Key, Value> > ElementTable;
HashMap<Key, Value>* fMap;
int32 fIndex;
ElementTable::Iterator fIterator;
Element* fElement;
Element* fLastElement;
};
HashMap();
@@ -163,7 +140,7 @@ 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;
@@ -175,17 +152,15 @@ public:
Iterator GetIterator();
protected:
typedef OpenHashTable<HashMapTableDefinition<Key, Value> > ElementTable;
typedef HashMapElement<Key, Value> Element;
friend class Iterator;
private:
Element *_FindElement(const Key& key) const;
protected:
OpenHashElementArray<Element> fElementArray;
OpenHashTable<Element, OpenHashElementArray<Element> > fTable;
ElementTable fTable;
};
// SynchronizedHashMap
template<typename Key, typename Value>
class SynchronizedHashMap : public Locker {
@@ -201,7 +176,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())
@@ -331,85 +306,107 @@ struct HashKey64 {
// constructor
template<typename Key, typename Value>
HashMap<Key, Value>::HashMap()
: fElementArray(1000),
fTable(1000, &fElementArray)
:
fTable()
{
fTable.Init();
}
// destructor
template<typename Key, typename Value>
HashMap<Key, Value>::~HashMap()
{
Clear();
}
// InitCheck
template<typename Key, typename Value>
status_t
HashMap<Key, Value>::InitCheck() const
{
return (fTable.InitCheck() && fElementArray.InitCheck()
? B_OK : B_NO_MEMORY);
return (fTable.TableSize() > 0 ? B_OK : B_NO_MEMORY);
}
// Put
template<typename Key, typename Value>
status_t
HashMap<Key, Value>::Put(const Key& key, Value value)
HashMap<Key, Value>::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<typename Key, typename Value>
Value
HashMap<Key, Value>::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<typename Key, typename Value>
void
HashMap<Key, Value>::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<typename Key, typename Value>
Value
HashMap<Key, Value>::Get(const Key& key) const
{
if (Element* element = _FindElement(key))
if (Element* element = fTable.Lookup(key))
return element->fValue;
return Value();
}
// ContainsKey
template<typename Key, typename Value>
bool
HashMap<Key, Value>::ContainsKey(const Key& key) const
{
return _FindElement(key);
return fTable.Lookup(key) != NULL;
}
// Size
template<typename Key, typename Value>
int32
@@ -418,6 +415,7 @@ HashMap<Key, Value>::Size() const
return fTable.CountElements();
}
// GetIterator
template<typename Key, typename Value>
typename HashMap<Key, Value>::Iterator
@@ -426,19 +424,5 @@ HashMap<Key, Value>::GetIterator()
return Iterator(this);
}
// _FindElement
template<typename Key, typename Value>
typename HashMap<Key, Value>::Element *
HashMap<Key, Value>::_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_MAP_H
+129 -110
View File
@@ -1,68 +1,56 @@
// HashSet.h
//
// Copyright (c) 2004, Ingo Weinhold ([email protected])
//
// 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, [email protected].
* Distributed under the terms of the MIT License.
*/
#ifndef HASH_SET_H
#define HASH_SET_H
#include <util/OpenHashTable.h>
#include "AutoLocker.h"
#include "Locker.h"
#include "OpenHashTable.h"
// HashSetElement
template<typename Key>
class HashSetElement : public OpenHashElement {
class HashSetElement : public HashTableLink<HashSetElement<Key> > {
private:
typedef HashSetElement<Key> 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<const Element&>(_element);
return (fKey == element.fKey);
}
inline void Adopt(Element &element)
{
fKey = element.fKey;
}
Key fKey;
};
// HashSetTableDefinition
template<typename Key>
struct HashSetTableDefinition {
typedef Key KeyType;
typedef HashSetElement<Key> 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<ValueType>* GetLink(ValueType* value) const
{ return value; }
};
// HashSet
template<typename Key>
class HashSet {
@@ -72,76 +60,66 @@ public:
typedef HashSetElement<Key> 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<Key>* map)
: fSet(map),
fIndex(0),
fElement(NULL),
fLastElement(NULL)
Iterator(HashSet<Key>* 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 HashMap<Key, Value>;
typedef OpenHashTable<HashSetTableDefinition<Key> > ElementTable;
HashSet<Key>* fSet;
ElementTable::Iterator fIterator;
Element* fElement;
private:
friend class HashSet<Key>;
HashSet<Key>* fSet;
int32 fIndex;
Element* fElement;
Element* fLastElement;
};
HashSet();
@@ -151,6 +129,7 @@ public:
status_t Add(const Key& key);
bool Remove(const Key& key);
void Clear();
bool Contains(const Key& key) const;
int32 Size() const;
@@ -158,24 +137,22 @@ public:
Iterator GetIterator();
protected:
typedef OpenHashTable<HashSetTableDefinition<Key> > ElementTable;
typedef HashSetElement<Key> Element;
friend class Iterator;
private:
Element *_FindElement(const Key& key) const;
protected:
OpenHashElementArray<Element> fElementArray;
OpenHashTable<Element, OpenHashElementArray<Element> > fTable;
ElementTable fTable;
};
// SynchronizedHashSet
template<typename Key>
class SynchronizedHashSet : public Locker {
public:
typedef HashSet<Key>::Iterator Iterator;
SynchronizedHashSet() : Locker("synchronized hash map") {}
SynchronizedHashSet() : Locker("synchronized hash set") {}
~SynchronizedHashSet() { Lock(); }
status_t InitCheck() const
@@ -199,6 +176,12 @@ public:
return fSet.Remove(key);
}
void Clear()
{
MapLocker locker(this);
fSet.Clear();
}
bool Contains(const Key& key) const
{
const Locker* lock = this;
@@ -230,65 +213,100 @@ protected:
HashSet<Key> fSet;
};
// HashSet
// constructor
template<typename Key>
HashSet<Key>::HashSet()
: fElementArray(1000),
fTable(1000, &fElementArray)
:
fTable()
{
fTable.Init();
}
// destructor
template<typename Key>
HashSet<Key>::~HashSet()
{
Clear();
}
// InitCheck
template<typename Key>
status_t
HashSet<Key>::InitCheck() const
{
return (fTable.InitCheck() && fElementArray.InitCheck()
? B_OK : B_NO_MEMORY);
return (fTable.TableSize() > 0 ? B_OK : B_NO_MEMORY);
}
// Add
template<typename Key>
status_t
HashSet<Key>::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<typename Key>
bool
HashSet<Key>::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<typename Key, typename Value>
void
HashSet<Key>::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<typename Key>
bool
HashSet<Key>::Contains(const Key& key) const
{
return _FindElement(key);
return fTable.Lookup(key) != NULL;
}
// Size
template<typename Key>
int32
@@ -320,4 +338,5 @@ HashSet<Key>::_FindElement(const Key& key) const
return element;
}
#endif // HASH_SET_H
@@ -1,512 +0,0 @@
/*
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 <malloc.h>
#include <new.h>
// don't include <Debug.h>
#ifndef ASSERT
# define ASSERT(E) (void)0
#endif
#define TRESPASS() (void)0
//namespace BPrivate {
template <class Element>
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 Element, class ElementVec = ElementVector<Element> >
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 Element>
class OpenHashElementArray : public ElementVector<Element> {
// 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<class Element, class ElementVec>
OpenHashTable<Element, ElementVec>::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<class Element, class ElementVec>
OpenHashTable<Element, ElementVec>::~OpenHashTable()
{
RemoveAll();
free(fHashArray);
}
template<class Element, class ElementVec>
bool
OpenHashTable<Element, ElementVec>::InitCheck() const
{
return (fHashArray && fElementVector);
}
template<class Element, class ElementVec>
int32
OpenHashTable<Element, ElementVec>::OptimalSize(int32 minSize)
{
for (int32 index = 0; ; index++)
if (!kPrimes[index] || kPrimes[index] >= (uint32)minSize)
return (int32)kPrimes[index];
return 0;
}
template<class Element, class ElementVec>
Element *
OpenHashTable<Element, ElementVec>::FindFirst(uint32 hash) const
{
ASSERT(fElementVector);
hash %= fArraySize;
if (fHashArray[hash] < 0)
return 0;
return &fElementVector->At(fHashArray[hash]);
}
template<class Element, class ElementVec>
int32
OpenHashTable<Element, ElementVec>::ElementIndex(const Element *element) const
{
return fElementVector->IndexOf(*element);
}
template<class Element, class ElementVec>
Element *
OpenHashTable<Element, ElementVec>::ElementAt(int32 index) const
{
return &fElementVector->At(index);
}
template<class Element, class ElementVec>
int32
OpenHashTable<Element, ElementVec>::ArraySize() const
{
return fArraySize;
}
template<class Element, class ElementVec>
int32
OpenHashTable<Element, ElementVec>::VectorSize() const
{
return fElementVector->Size();
}
template<class Element, class ElementVec>
int32
OpenHashTable<Element, ElementVec>::CountElements() const
{
return fElementCount;
}
template<class Element, class ElementVec>
Element *
OpenHashTable<Element, ElementVec>::Add(uint32 hash)
{
ASSERT(fElementVector);
_RehashIfNeeded();
hash %= fArraySize;
Element *result = fElementVector->Add();
if (result) {
result->fNext = fHashArray[hash];
fHashArray[hash] = fElementVector->IndexOf(*result);
fElementCount++;
}
return result;
}
template<class Element, class ElementVec>
void
OpenHashTable<Element, ElementVec>::Remove(Element *element, bool dontRehash)
{
if (!dontRehash)
_RehashIfNeeded();
uint32 hash = element->Hash() % fArraySize;
int32 next = fHashArray[hash];
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) {
TRESPASS();
return;
}
if (&fElementVector->At(next) == element) {
fElementVector->At(index).fNext = element->fNext;
fElementVector->Remove(next);
fElementCount--;
return;
}
index = next;
}
}
template<class Element, class ElementVec>
void
OpenHashTable<Element, ElementVec>::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<class Element, class ElementVec>
void
OpenHashTable<Element, ElementVec>::SetElementVector(ElementVec *elementVector)
{
fElementVector = elementVector;
}
// _RehashIfNeeded
template<class Element, class ElementVec>
bool
OpenHashTable<Element, ElementVec>::_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<class Element, class ElementVec>
bool
OpenHashTable<Element, ElementVec>::_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<class Element>
OpenHashElementArray<Element>::OpenHashElementArray(int32 initialSize)
: fSize(initialSize),
fNextFree(0),
fNextDeleted(-1)
{
fData = (Element*)calloc((size_t)initialSize, sizeof(Element));
}
template<class Element>
OpenHashElementArray<Element>::~OpenHashElementArray()
{
free(fData);
}
template<class Element>
bool
OpenHashElementArray<Element>::InitCheck() const
{
return fData;
}
template<class Element>
Element &
OpenHashElementArray<Element>::At(int32 index)
{
ASSERT(index < fSize);
return fData[index];
}
template<class Element>
const Element &
OpenHashElementArray<Element>::At(int32 index) const
{
ASSERT(index < fSize);
return fData[index];
}
template<class Element>
int32
OpenHashElementArray<Element>::IndexOf(const Element &element) const
{
int32 result = &element - fData;
if (result < 0 || result > fSize)
return -1;
return result;
}
template<class Element>
int32
OpenHashElementArray<Element>::Size() const
{
return fSize;
}
template<class Element>
Element *
OpenHashElementArray<Element>::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<class Element>
Element *
OpenHashElementArray<Element>::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
ASSERT(At(index).fNext == -1);
return &At(index);
}
template<class Element>
void
OpenHashElementArray<Element>::Remove(int32 index)
{
// delete by chaining empty elements in a single linked
// list, reusing the next field
ASSERT(index < fSize);
At(index).~Element();
// call the destructor explicitly to destroy the element
// properly
At(index).fNext = fNextDeleted;
fNextDeleted = index;
}
//} // namespace BPrivate
//using namespace BPrivate;
#endif
@@ -9,7 +9,7 @@ SubDirHdrs [ FDirName $(userlandFSIncludes) private ] ;
SubDirHdrs [ FDirName $(userlandFSIncludes) shared ] ;
UsePrivateSystemHeaders ;
UsePrivateHeaders libroot shared ;
UsePrivateHeaders kernel libroot shared ;
SEARCH_SOURCE += [ FDirName $(userlandFSTop) private ] ;
SEARCH_SOURCE += [ FDirName $(userlandFSTop) shared ] ;