200 lines
3.2 KiB
C++
200 lines
3.2 KiB
C++
|
/*
|
||
|
* Copyright 2005, Haiku.
|
||
|
* Distributed under the terms of the MIT License.
|
||
|
*
|
||
|
* Authors:
|
||
|
* Axel Dörfler, axeld@pinc-software.de
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include "HashTable.h"
|
||
|
|
||
|
#include <new>
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
//#include <stdarg.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
|
||
|
struct HashTable::entry {
|
||
|
entry* next;
|
||
|
Hashable* value;
|
||
|
};
|
||
|
|
||
|
|
||
|
HashTable::HashTable(int32 capacity, float loadFactor)
|
||
|
:
|
||
|
fTable(NULL),
|
||
|
fCount(0),
|
||
|
fThreshold(0)
|
||
|
{
|
||
|
if (capacity < 10)
|
||
|
capacity = 10;
|
||
|
if (loadFactor <= 0.3)
|
||
|
loadFactor = 0.3;
|
||
|
|
||
|
fLoadFactor = loadFactor;
|
||
|
fCapacity = capacity;
|
||
|
}
|
||
|
|
||
|
|
||
|
HashTable::~HashTable()
|
||
|
{
|
||
|
MakeEmpty();
|
||
|
}
|
||
|
|
||
|
|
||
|
void
|
||
|
HashTable::MakeEmpty()
|
||
|
{
|
||
|
for (int32 index = fCapacity; --index >= 0;) {
|
||
|
struct entry *entry, *next;
|
||
|
|
||
|
for (entry = fTable[index]; entry != NULL; entry = next) {
|
||
|
next = entry->next;
|
||
|
|
||
|
delete entry->value;
|
||
|
delete entry;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
free(fTable);
|
||
|
fTable = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
Hashable *
|
||
|
HashTable::GetValue(Hashable& key) const
|
||
|
{
|
||
|
struct entry* entry = _GetHashEntry(key);
|
||
|
|
||
|
return entry != NULL ? entry->value : NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool
|
||
|
HashTable::AddItem(Hashable *value)
|
||
|
{
|
||
|
struct entry *entry = _GetHashEntry(*value);
|
||
|
int32 hash = value->Hash();
|
||
|
int32 index;
|
||
|
|
||
|
// already in hash?
|
||
|
if (entry != NULL)
|
||
|
return true;
|
||
|
|
||
|
if (fCount >= fThreshold)
|
||
|
_Rehash();
|
||
|
|
||
|
index = hash % fCapacity;
|
||
|
|
||
|
entry = new (nothrow) HashTable::entry;
|
||
|
if (entry == NULL)
|
||
|
return false;
|
||
|
|
||
|
entry->value = value;
|
||
|
entry->next = fTable[index];
|
||
|
fTable[index] = entry;
|
||
|
fCount++;
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
Hashable *
|
||
|
HashTable::RemoveItem(Hashable& key)
|
||
|
{
|
||
|
struct entry* previous = NULL;
|
||
|
struct entry* entry;
|
||
|
uint32 hash;
|
||
|
int32 index;
|
||
|
|
||
|
if (fTable == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
hash = key.Hash();
|
||
|
index = hash % fCapacity;
|
||
|
|
||
|
for (entry = fTable[index]; entry != NULL; entry = entry->next) {
|
||
|
if (entry->value->Hash() == hash && entry->value->CompareTo(key)) {
|
||
|
// found value in array
|
||
|
Hashable* value;
|
||
|
|
||
|
if (previous)
|
||
|
previous->next = entry->next;
|
||
|
else
|
||
|
fTable[index] = entry->next;
|
||
|
|
||
|
fCount--;
|
||
|
value = entry->value;
|
||
|
delete entry;
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
previous = entry;
|
||
|
}
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
bool
|
||
|
HashTable::_Rehash()
|
||
|
{
|
||
|
struct entry** newTable;
|
||
|
int32 oldCapacity = fCapacity;
|
||
|
int32 newCapacity, i;
|
||
|
|
||
|
if (fCount != 0)
|
||
|
newCapacity = oldCapacity * 2 + 1;
|
||
|
else
|
||
|
newCapacity = fCapacity;
|
||
|
|
||
|
newTable = (struct entry **)malloc(newCapacity * sizeof(struct entry *));
|
||
|
if (newTable == NULL)
|
||
|
return false;
|
||
|
|
||
|
memset(newTable, 0, newCapacity * sizeof(struct entry *));
|
||
|
|
||
|
if (fTable != NULL) {
|
||
|
// repopulate the entries into the new array
|
||
|
for (i = fCapacity; i-- > 0;) {
|
||
|
struct entry* entry;
|
||
|
struct entry* next;
|
||
|
|
||
|
for (entry = fTable[i]; entry != NULL; entry = next) {
|
||
|
next = entry->next;
|
||
|
|
||
|
int32 index = entry->value->Hash() % newCapacity;
|
||
|
entry->next = newTable[index];
|
||
|
newTable[index] = entry;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
free(fTable);
|
||
|
}
|
||
|
|
||
|
fTable = newTable;
|
||
|
fCapacity = newCapacity;
|
||
|
fThreshold = int32(newCapacity * fLoadFactor);
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
struct HashTable::entry *
|
||
|
HashTable::_GetHashEntry(Hashable& key) const
|
||
|
{
|
||
|
struct entry* entry;
|
||
|
uint32 hash = key.Hash();
|
||
|
|
||
|
if (fTable == NULL)
|
||
|
return NULL;
|
||
|
|
||
|
for (entry = fTable[hash % fCapacity]; entry != NULL; entry = entry->next) {
|
||
|
if (entry->value->Hash() == hash && entry->value->CompareTo(key))
|
||
|
return entry;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|