/* Hashtable - a general purpose hash table
**
** Copyright 2001 pinc Software. All Rights Reserved.
** Released under the terms of the MIT license.
*/
 
 
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
 
#include "Hashtable.h"
 
 
/************************** standard string hash functions **************************/
 
 
unsigned int stringHash(const char *c)
{
	int len = strlen(c);
 
	return(*(int *)(c + len - 4));  // erstmal zum Testen
}
 
 
bool stringCompare(const char *a, const char *b)
{
	return(!strcmp(a, b));
}
 
 
// #pragma mark - Hashtable
 
 
Hashtable::Hashtable(int capacity, float loadFactor)
	:
	fIteratorIndex(-1)
{
	if (capacity < 0 || loadFactor <= 0)
		return;
 
	if (!capacity)
		capacity = 1;
 
	if (!(fTable = (struct Entry **)malloc(capacity * sizeof(void *))))
		return;
	memset(fTable,0,capacity * sizeof(void *));
 
	fThreshold = (int)(capacity * loadFactor);
	fModCount = 0;
	fLoadFactor = loadFactor;
	fCapacity = capacity;
 
	fHashFunc = (uint32 (*)(const void *))stringHash;
	fCompareFunc = (bool (*)(const void *, const void *))stringCompare;
}
 
 
Hashtable::~Hashtable()
{
	struct Entry **table = fTable;
 
	for(int32 index = fCapacity;--index >= 0;)
	{
		struct Entry *entry,*next;
 
		for(entry = table[index];entry;entry = next)
		{
			next = entry->next;
			delete entry;
		}
	}
	free(table);
}
 
 
void Hashtable::SetHashFunction(uint32 (*func)(const void *))
{
	fHashFunc = func;
}
 
 
void Hashtable::SetCompareFunction(bool (*func)(const void *, const void *))
{
	fCompareFunc = func;
}
 
 
bool Hashtable::IsEmpty() const
{
	return fCount == 0;
}
 
 
bool Hashtable::ContainsKey(const void *key)
{
	return GetHashEntry(key) ? true : false;
}
 
 
void *Hashtable::GetValue(const void *key)
{
	Entry *entry = GetHashEntry(key);
 
	return entry ? entry->value : NULL;
}
 
 
bool Hashtable::Put(const void *key, void *value)
{
	Entry *entry = GetHashEntry(key);
	int hash = fHashFunc(key);
	int index;
 
	if (entry)
		return true;
 
	fModCount++;
	if (fCount >= fThreshold)
		Rehash();
 
	index = hash % fCapacity;
 
	fTable[index] = new Entry(fTable[index], key, value);
	fCount++;
 
	return true;
}
 
 
void *Hashtable::Remove(const void *key)
{
	Entry **table,*entry,*prev;
	uint32 hash,(*func)(const void *);
	int32 index;
 
	table = fTable;
	hash = (func = fHashFunc)(key);
	index = hash % fCapacity;
 
	for(entry = table[index],prev = NULL;entry;entry = entry->next)
	{
		if ((func(entry->key) == hash) && fCompareFunc(entry->key,key))
		{
			void *value;
 
			fModCount++;
			if (prev)
				prev->next = entry->next;
			else
				table[index] = entry->next;
 
			fCount--;
			value = entry->value;
			delete entry;
 
			return value;
		}
		prev = entry;
	}
	return NULL;
}
 
 
status_t Hashtable::GetNextEntry(void **value)
{
	if (fIteratorIndex == -1)
	{
		fIteratorIndex = 0;
		fIteratorEntry = fTable[0];
	}
	else if (fIteratorEntry)
		fIteratorEntry = fIteratorEntry->next;
 
	// get next filled slot
	while (!fIteratorEntry && fIteratorIndex + 1 < fCapacity)
		fIteratorEntry = fTable[++fIteratorIndex];
 
	if (fIteratorEntry)
	{
		*value = fIteratorEntry->value;
		return B_OK;
	}
 
	return B_ENTRY_NOT_FOUND;
}
 
 
void Hashtable::Rewind()
{
	fIteratorIndex = -1;
}
 
 
void
Hashtable::MakeEmpty(int8 keyMode,int8 valueMode)
{
	fModCount++;
 
	for (int32 index = fCapacity; --index >= 0;) {
		Entry *entry, *next;
 
		for (entry = fTable[index]; entry; entry = next) {
			switch (keyMode) {
				case HASH_EMPTY_DELETE:
					// TODO: destructors are not called!
					delete (void*)entry->key;
					break;
				case HASH_EMPTY_FREE:
					free((void*)entry->key);
					break;
			}
			switch (valueMode) {
				case HASH_EMPTY_DELETE:
					// TODO: destructors are not called!
					delete entry->value;
					break;
				case HASH_EMPTY_FREE:
					free(entry->value);
					break;
			}
			next = entry->next;
			delete entry;
		}
		fTable[index] = NULL;
	}
	fCount = 0;
}
 
 
size_t
Hashtable::Size() const
{
	return fCount;
}
 
 
/** The hash table will be doubled in size, and rebuild.
 *  @return true on success
 */
 
bool Hashtable::Rehash()
{
	uint32 (*hashCode)(const void *) = fHashFunc;
	struct Entry **oldTable = fTable,**newtable;
	int oldCapacity = fCapacity;
	int newCapacity,i;
 
	newCapacity = oldCapacity * 2 + 1;
	if (!(newtable = (struct Entry **)malloc(newCapacity * sizeof(struct Entry *))))
		return false;
	memset(newtable,0,newCapacity*sizeof(struct Entry *));
 
	fModCount++;
	fThreshold = (int)(newCapacity * fLoadFactor);
	fTable = newtable;
	fCapacity = newCapacity;
 
	for (i = oldCapacity;i-- > 0;) {
		Entry *oldEntry,*entry = NULL;
		int index;
 
		for (oldEntry = oldTable[i];oldEntry;) {
			entry = oldEntry;  oldEntry = oldEntry->next;
 
			index = hashCode(entry->key) % newCapacity;
			entry->next = newtable[index];
			newtable[index] = entry;
		}
	}
	free(oldTable);
 
	return true;
}
 
 
Hashtable::Entry *Hashtable::GetHashEntry(const void *key)
{
	Entry **table,*entry;
	uint32 hash,(*func)(const void *);
 
	table = fTable;
	hash = (func = fHashFunc)(key);
 
	for(entry = table[hash % fCapacity];entry;entry = entry->next)
	{
		if ((func(entry->key) == hash) && fCompareFunc(entry->key,key))
			return entry;
	}
	return NULL;
}
 

V730 Not all members of a class are initialized inside the constructor. Consider inspecting: fCount, fIteratorEntry.

V772 Calling a 'delete' operator for a void pointer will cause undefined behavior.

V772 Calling a 'delete' operator for a void pointer will cause undefined behavior.