haiku/headers/private/kernel/util/MultiHashTable.h
Stephan Aßmus 5147963dcd headers/private/kernel/util/OpenHashTable.h, Hugo's version, is a bit nicer than
Tracker's OpenHashTable.h which it should eventually replace. We've renamed the
class to BOpenHashTable and changed the interface slightly so that HashTableLink
became superfluous.
Adapted all the code that used it. Since the OpenHashTables no longer clash,
this should fix the GCC4 build.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@31791 a95241bf-73f2-0310-859d-f6bbb57e9c96
2009-07-27 00:39:12 +00:00

184 lines
4.3 KiB
C++

/*
* Copyright 2007, Hugo Santos. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Hugo Santos, hugosantos@gmail.com
*/
#ifndef _KERNEL_UTIL_MULTI_HASH_TABLE_H
#define _KERNEL_UTIL_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 BOpenHashTable<Definition,
AutoExpand, CheckDuplicates> {
public:
typedef BOpenHashTable<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()
: HashTable() {}
MultiHashTable(const Definition& definition)
: HashTable(definition) {}
status_t Init(size_t initialSize = HashTable::kMinimumSize)
{
return HashTable::Init(initialSize);
}
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;
}
Iterator GetIterator() const { return HashTable::GetIterator(); }
class ValueIterator : protected Iterator {
public:
ValueIterator(const HashTable *table, size_t index, ValueType *value)
: fOriginalIndex(index), fOriginalValue(value)
{
Iterator::fTable = table;
Rewind();
}
bool HasNext() const
{
if (Iterator::fNext == NULL)
return false;
if (Iterator::fNext == fOriginalValue)
return true;
return ((const MultiTable *)Iterator::fTable)->_Definition().CompareValues(
fOriginalValue, Iterator::fNext);
}
void Rewind()
{
Iterator::fIndex = fOriginalIndex + 1;
Iterator::fNext = fOriginalValue;
}
ValueType *Next() { return Iterator::Next(); }
private:
size_t fOriginalIndex;
ValueType *fOriginalValue;
};
ValueIterator Lookup(const KeyType &key) const
{
size_t index = 0;
ValueType *slot = NULL;
if (HashTable::fTableSize > 0) {
index = HashTable::fDefinition.HashKey(key)
& (HashTable::fTableSize - 1);
slot = HashTable::fTable[index];
}
while (slot) {
if (HashTable::fDefinition.Compare(key, slot))
break;
slot = HashTable::_Link(slot);
}
if (slot == NULL)
return ValueIterator(this, HashTable::fTableSize, NULL);
return ValueIterator(this, index, slot);
}
private:
// for g++ 2.95
friend class ValueIterator;
const Definition &_Definition() const { return HashTable::fDefinition; }
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));
if (previous) {
_Link(value) = _Link(previous);
_Link(previous) = value;
} else {
_Link(value) = table[index];
table[index] = value;
}
}
// TODO use BOpenHashTable'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);
_Insert(newTable, newSize, bucket);
bucket = next;
}
}
delete [] HashTable::fTable;
}
HashTable::fTableSize = newSize;
HashTable::fTable = newTable;
return true;
}
};
#endif // _KERNEL_UTIL_MULTI_HASH_TABLE_H