introduced MultiHashTable, similiar to multimap, but with hash table semantics.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20864 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Hugo Santos 2007-04-27 15:06:30 +00:00
parent e2200e347d
commit 505e98538a
2 changed files with 152 additions and 4 deletions

View File

@ -0,0 +1,138 @@
/*
* Copyright 2007, Hugo Santos. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Hugo Santos, hugosantos@gmail.com
*/
#ifndef _MULTI_HASH_TABLE_H_
#define _MULTI_HASH_TABLE_H_
#include <KernelExport.h>
#include <util/kernel_cpp.h>
#include <util/OpenHashTable.h>
// MultiHashTable is a container which acts a bit like multimap<>
// but with hash table semantics.
// refer to OpenHashTable.h for how to use this container.
template<typename Definition, bool AutoExpand = true,
bool CheckDuplicates = false>
class MultiHashTable : private OpenHashTable<Definition,
AutoExpand, CheckDuplicates> {
public:
typedef OpenHashTable<Definition, AutoExpand, CheckDuplicates> HashTable;
typedef MultiHashTable<Definition, AutoExpand, CheckDuplicates> MultiTable;
typedef typename HashTable::Iterator Iterator;
typedef typename Definition::KeyType KeyType;
typedef typename Definition::ValueType ValueType;
MultiHashTable(size_t initialSize = HashTable::kMinimumSize)
: HashTable(initialSize) {}
MultiHashTable(typename Definition::ParentType *parent,
size_t initialSize = HashTable::kMinimumSize)
: HashTable(parent, initialSize) {}
status_t InitCheck() const { return HashTable::InitCheck(); }
Iterator Lookup(const KeyType &key) const
{
size_t index = HashTable::fDefinition.HashKey(key)
& (HashTable::fTableSize - 1);
ValueType *slot = HashTable::fTable[index];
while (slot) {
if (HashTable::fDefinition.Compare(key, slot))
break;
slot = HashTable::_Link(slot)->fNext;
}
if (slot == NULL)
return Iterator(this, HashTable::fTableSize, NULL);
return Iterator(this, index, slot);
}
void Insert(ValueType *value)
{
if (AutoExpand
&& HashTable::fItemCount >= (HashTable::fTableSize * 200 / 256))
_Resize(HashTable::fTableSize * 2);
InsertUnchecked(value);
}
void InsertUnchecked(ValueType *value)
{
_Insert(HashTable::fTable, HashTable::fTableSize, value);
HashTable::fItemCount++;
}
bool Remove(ValueType *value)
{
if (!HashTable::RemoveUnchecked(value))
return false;
if (AutoExpand && HashTable::fTableSize > HashTable::kMinimumSize
&& HashTable::fItemCount < (HashTable::fTableSize * 50 / 256))
_Resize(HashTable::fTableSize / 2);
return true;
}
private:
void _Insert(ValueType **table, size_t tableSize, ValueType *value)
{
size_t index = HashTable::fDefinition.Hash(value) & (tableSize - 1);
ValueType *previous;
// group values with the same key
for (previous = table[index]; previous
&& !HashTable::fDefinition.CompareValues(previous, value);
previous = HashTable::_Link(previous)->fNext);
if (previous) {
_Link(value)->fNext = _Link(previous)->fNext;
_Link(previous)->fNext = value;
} else {
_Link(value)->fNext = table[index];
table[index] = value;
}
}
// TODO use OpenHashTable's _Resize
bool _Resize(size_t newSize)
{
ValueType **newTable = new ValueType *[newSize];
if (newTable == NULL)
return false;
for (size_t i = 0; i < newSize; i++)
newTable[i] = NULL;
if (HashTable::fTable) {
for (size_t i = 0; i < HashTable::fTableSize; i++) {
ValueType *bucket = HashTable::fTable[i];
while (bucket) {
ValueType *next = _Link(bucket)->fNext;
_Insert(newTable, newSize, bucket);
bucket = next;
}
}
delete [] HashTable::fTable;
}
HashTable::fTableSize = newSize;
HashTable::fTable = newTable;
return true;
}
};
#endif

View File

@ -123,16 +123,19 @@ public:
fItemCount++;
}
void Remove(ValueType *value)
bool Remove(ValueType *value)
{
RemoveUnchecked(value);
if (!RemoveUnchecked(value))
return false;
if (AutoExpand && fTableSize > kMinimumSize
&& fItemCount < (fTableSize * 50 / 256))
_Resize(fTableSize / 2);
return true;
}
void RemoveUnchecked(ValueType *value)
bool RemoveUnchecked(ValueType *value)
{
size_t index = fDefinition.Hash(value) & (fTableSize - 1);
ValueType *previous = NULL, *slot = fTable[index];
@ -152,6 +155,9 @@ public:
slot = next;
}
if (slot == NULL)
return false;
if (CheckDuplicates) {
for (size_t i = 0; i < fTableSize; i++) {
ValueType *bucket = fTable[i];
@ -164,6 +170,7 @@ public:
}
fItemCount--;
return true;
}
class Iterator {
@ -174,6 +181,9 @@ public:
Rewind();
}
Iterator(const HashTable *table, size_t index, ValueType *value)
: fTable(table), fIndex(index), fNext(value) {}
bool HasNext() const { return fNext != NULL; }
ValueType *Next()
@ -208,7 +218,7 @@ public:
Iterator GetIterator() const { return Iterator(this); }
private:
protected:
// for g++ 2.95
friend class Iterator;