diff --git a/headers/private/kernel/util/MultiHashTable.h b/headers/private/kernel/util/MultiHashTable.h new file mode 100644 index 0000000000..4b05aca556 --- /dev/null +++ b/headers/private/kernel/util/MultiHashTable.h @@ -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 +#include +#include + +// 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 +class MultiHashTable : private OpenHashTable { +public: + typedef OpenHashTable HashTable; + typedef MultiHashTable 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 diff --git a/headers/private/kernel/util/OpenHashTable.h b/headers/private/kernel/util/OpenHashTable.h index 47e7d7ee84..c393150da9 100644 --- a/headers/private/kernel/util/OpenHashTable.h +++ b/headers/private/kernel/util/OpenHashTable.h @@ -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;