Blame winpr/libwinpr/utils/collections/HashTable.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * WinPR: Windows Portable Runtime
Packit 1fb8d4
 * System.Collections.Hashtable
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/collections.h>
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * This implementation is based on the public domain
Packit 1fb8d4
 * hash table implementation made by Keith Pomakis:
Packit 1fb8d4
 *
Packit 1fb8d4
 * http://www.pomakis.com/hashtable/hashtable.c
Packit 1fb8d4
 * http://www.pomakis.com/hashtable/hashtable.h
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL HashTable_PointerCompare(void* pointer1, void* pointer2)
Packit 1fb8d4
{
Packit 1fb8d4
	return (pointer1 == pointer2);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
UINT32 HashTable_PointerHash(void* pointer)
Packit 1fb8d4
{
Packit Service 5a9772
	return ((UINT32)(UINT_PTR)pointer) >> 4;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL HashTable_StringCompare(void* string1, void* string2)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!string1 || !string2)
Packit 1fb8d4
		return (string1 == string2);
Packit 1fb8d4
Packit Service 5a9772
	return (strcmp((char*)string1, (char*)string2) == 0);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
UINT32 HashTable_StringHash(void* key)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 c;
Packit 1fb8d4
	UINT32 hash = 5381;
Packit Service 5a9772
	BYTE* str = (BYTE*)key;
Packit 1fb8d4
Packit 1fb8d4
	/* djb2 algorithm */
Packit 1fb8d4
	while ((c = *str++) != '\0')
Packit 1fb8d4
		hash = (hash * 33) + c;
Packit 1fb8d4
Packit 1fb8d4
	return hash;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void* HashTable_StringClone(void* str)
Packit 1fb8d4
{
Packit Service 5a9772
	return _strdup((char*)str);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void HashTable_StringFree(void* str)
Packit 1fb8d4
{
Packit 1fb8d4
	free(str);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int HashTable_IsProbablePrime(int oddNumber)
Packit 1fb8d4
{
Packit 1fb8d4
	int i;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 3; i < 51; i += 2)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (oddNumber == i)
Packit 1fb8d4
			return 1;
Packit 1fb8d4
		else if (oddNumber % i == 0)
Packit 1fb8d4
			return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1; /* maybe */
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static long HashTable_CalculateIdealNumOfBuckets(wHashTable* table)
Packit 1fb8d4
{
Packit Service 5a9772
	int idealNumOfBuckets = table->numOfElements / ((int)table->idealRatio);
Packit 1fb8d4
Packit 1fb8d4
	if (idealNumOfBuckets < 5)
Packit 1fb8d4
		idealNumOfBuckets = 5;
Packit 1fb8d4
	else
Packit 1fb8d4
		idealNumOfBuckets |= 0x01;
Packit 1fb8d4
Packit 1fb8d4
	while (!HashTable_IsProbablePrime(idealNumOfBuckets))
Packit 1fb8d4
		idealNumOfBuckets += 2;
Packit 1fb8d4
Packit 1fb8d4
	return idealNumOfBuckets;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
static void HashTable_Rehash(wHashTable* table, int numOfBuckets)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	UINT32 hashValue;
Packit 1fb8d4
	wKeyValuePair* pair;
Packit 1fb8d4
	wKeyValuePair* nextPair;
Packit 1fb8d4
	wKeyValuePair** newBucketArray;
Packit 1fb8d4
Packit 1fb8d4
	if (numOfBuckets == 0)
Packit 1fb8d4
		numOfBuckets = HashTable_CalculateIdealNumOfBuckets(table);
Packit 1fb8d4
Packit 1fb8d4
	if (numOfBuckets == table->numOfBuckets)
Packit 1fb8d4
		return; /* already the right size! */
Packit 1fb8d4
Packit Service 5a9772
	newBucketArray = (wKeyValuePair**)calloc(numOfBuckets, sizeof(wKeyValuePair*));
Packit 1fb8d4
Packit 1fb8d4
	if (!newBucketArray)
Packit 1fb8d4
	{
Packit 1fb8d4
		/*
Packit 1fb8d4
		 * Couldn't allocate memory for the new array.
Packit 1fb8d4
		 * This isn't a fatal error; we just can't perform the rehash.
Packit 1fb8d4
		 */
Packit 1fb8d4
		return;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < table->numOfBuckets; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		pair = table->bucketArray[index];
Packit 1fb8d4
Packit 1fb8d4
		while (pair)
Packit 1fb8d4
		{
Packit 1fb8d4
			nextPair = pair->next;
Packit 1fb8d4
			hashValue = table->hash(pair->key) % numOfBuckets;
Packit 1fb8d4
			pair->next = newBucketArray[hashValue];
Packit 1fb8d4
			newBucketArray[hashValue] = pair;
Packit 1fb8d4
			pair = nextPair;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	free(table->bucketArray);
Packit 1fb8d4
	table->bucketArray = newBucketArray;
Packit 1fb8d4
	table->numOfBuckets = numOfBuckets;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
wKeyValuePair* HashTable_Get(wHashTable* table, void* key)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 hashValue;
Packit 1fb8d4
	wKeyValuePair* pair;
Packit 1fb8d4
	hashValue = table->hash(key) % table->numOfBuckets;
Packit 1fb8d4
	pair = table->bucketArray[hashValue];
Packit 1fb8d4
Packit 1fb8d4
	while (pair && !table->keyCompare(key, pair->key))
Packit 1fb8d4
		pair = pair->next;
Packit 1fb8d4
Packit 1fb8d4
	return pair;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * C equivalent of the C# Hashtable Class:
Packit 1fb8d4
 * http://msdn.microsoft.com/en-us/library/system.collections.hashtable.aspx
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Properties
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Gets the number of key/value pairs contained in the HashTable.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
int HashTable_Count(wHashTable* table)
Packit 1fb8d4
{
Packit 1fb8d4
	return table->numOfElements;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Methods
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Adds an element with the specified key and value into the HashTable.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
int HashTable_Add(wHashTable* table, void* key, void* value)
Packit 1fb8d4
{
Packit 1fb8d4
	int status = 0;
Packit 1fb8d4
	UINT32 hashValue;
Packit 1fb8d4
	wKeyValuePair* pair;
Packit 1fb8d4
	wKeyValuePair* newPair;
Packit 1fb8d4
Packit 1fb8d4
	if (!key || !value)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (table->keyClone)
Packit 1fb8d4
	{
Packit 1fb8d4
		key = table->keyClone(key);
Packit 1fb8d4
Packit 1fb8d4
		if (!key)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (table->valueClone)
Packit 1fb8d4
	{
Packit 1fb8d4
		value = table->valueClone(value);
Packit 1fb8d4
Packit 1fb8d4
		if (!value)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		EnterCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	hashValue = table->hash(key) % table->numOfBuckets;
Packit 1fb8d4
	pair = table->bucketArray[hashValue];
Packit 1fb8d4
Packit 1fb8d4
	while (pair && !table->keyCompare(key, pair->key))
Packit 1fb8d4
		pair = pair->next;
Packit 1fb8d4
Packit 1fb8d4
	if (pair)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (pair->key != key)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (table->keyFree)
Packit 1fb8d4
				table->keyFree(pair->key);
Packit 1fb8d4
Packit 1fb8d4
			pair->key = key;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (pair->value != value)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (table->valueFree)
Packit 1fb8d4
				table->valueFree(pair->value);
Packit 1fb8d4
Packit 1fb8d4
			pair->value = value;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit Service 5a9772
		newPair = (wKeyValuePair*)malloc(sizeof(wKeyValuePair));
Packit 1fb8d4
Packit 1fb8d4
		if (!newPair)
Packit 1fb8d4
		{
Packit 1fb8d4
			status = -1;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			newPair->key = key;
Packit 1fb8d4
			newPair->value = value;
Packit 1fb8d4
			newPair->next = table->bucketArray[hashValue];
Packit 1fb8d4
			table->bucketArray[hashValue] = newPair;
Packit 1fb8d4
			table->numOfElements++;
Packit 1fb8d4
Packit 1fb8d4
			if (table->upperRehashThreshold > table->idealRatio)
Packit 1fb8d4
			{
Packit Service 5a9772
				float elementToBucketRatio =
Packit Service 5a9772
				    (float)table->numOfElements / (float)table->numOfBuckets;
Packit 1fb8d4
Packit 1fb8d4
				if (elementToBucketRatio > table->upperRehashThreshold)
Packit 1fb8d4
					HashTable_Rehash(table, 0);
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		LeaveCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Removes the element with the specified key from the HashTable.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL HashTable_Remove(wHashTable* table, void* key)
Packit 1fb8d4
{
Packit 1fb8d4
	UINT32 hashValue;
Packit 1fb8d4
	BOOL status = TRUE;
Packit 1fb8d4
	wKeyValuePair* pair = NULL;
Packit 1fb8d4
	wKeyValuePair* previousPair = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		EnterCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	hashValue = table->hash(key) % table->numOfBuckets;
Packit 1fb8d4
	pair = table->bucketArray[hashValue];
Packit 1fb8d4
Packit 1fb8d4
	while (pair && !table->keyCompare(key, pair->key))
Packit 1fb8d4
	{
Packit 1fb8d4
		previousPair = pair;
Packit 1fb8d4
		pair = pair->next;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!pair)
Packit 1fb8d4
	{
Packit 1fb8d4
		status = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (table->keyFree)
Packit 1fb8d4
			table->keyFree(pair->key);
Packit 1fb8d4
Packit 1fb8d4
		if (table->valueFree)
Packit 1fb8d4
			table->valueFree(pair->value);
Packit 1fb8d4
Packit 1fb8d4
		if (previousPair)
Packit 1fb8d4
			previousPair->next = pair->next;
Packit 1fb8d4
		else
Packit 1fb8d4
			table->bucketArray[hashValue] = pair->next;
Packit 1fb8d4
Packit 1fb8d4
		free(pair);
Packit 1fb8d4
		table->numOfElements--;
Packit 1fb8d4
Packit 1fb8d4
		if (table->lowerRehashThreshold > 0.0)
Packit 1fb8d4
		{
Packit Service 5a9772
			float elementToBucketRatio = (float)table->numOfElements / (float)table->numOfBuckets;
Packit 1fb8d4
Packit 1fb8d4
			if (elementToBucketRatio < table->lowerRehashThreshold)
Packit 1fb8d4
				HashTable_Rehash(table, 0);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		LeaveCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Get an item value using key
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void* HashTable_GetItemValue(wHashTable* table, void* key)
Packit 1fb8d4
{
Packit 1fb8d4
	void* value = NULL;
Packit 1fb8d4
	wKeyValuePair* pair;
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		EnterCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	pair = HashTable_Get(table, key);
Packit 1fb8d4
Packit 1fb8d4
	if (pair)
Packit 1fb8d4
		value = pair->value;
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		LeaveCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	return value;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Set an item value using key
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL HashTable_SetItemValue(wHashTable* table, void* key, void* value)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status = TRUE;
Packit 1fb8d4
	wKeyValuePair* pair;
Packit 1fb8d4
Packit 1fb8d4
	if (table->valueClone && value)
Packit 1fb8d4
	{
Packit 1fb8d4
		value = table->valueClone(value);
Packit 1fb8d4
Packit 1fb8d4
		if (!value)
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		EnterCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	pair = HashTable_Get(table, key);
Packit 1fb8d4
Packit 1fb8d4
	if (!pair)
Packit 1fb8d4
		status = FALSE;
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		if (table->valueClone && table->valueFree)
Packit 1fb8d4
			table->valueFree(pair->value);
Packit 1fb8d4
Packit 1fb8d4
		pair->value = value;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		LeaveCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Removes all elements from the HashTable.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
void HashTable_Clear(wHashTable* table)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	wKeyValuePair* pair;
Packit 1fb8d4
	wKeyValuePair* nextPair;
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		EnterCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < table->numOfBuckets; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		pair = table->bucketArray[index];
Packit 1fb8d4
Packit 1fb8d4
		while (pair)
Packit 1fb8d4
		{
Packit 1fb8d4
			nextPair = pair->next;
Packit 1fb8d4
Packit 1fb8d4
			if (table->keyFree)
Packit 1fb8d4
				table->keyFree(pair->key);
Packit 1fb8d4
Packit 1fb8d4
			if (table->valueFree)
Packit 1fb8d4
				table->valueFree(pair->value);
Packit 1fb8d4
Packit 1fb8d4
			free(pair);
Packit 1fb8d4
			pair = nextPair;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		table->bucketArray[index] = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	table->numOfElements = 0;
Packit 1fb8d4
	HashTable_Rehash(table, 5);
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		LeaveCriticalSection(&table->lock);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Gets the list of keys as an array
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
int HashTable_GetKeys(wHashTable* table, ULONG_PTR** ppKeys)
Packit 1fb8d4
{
Packit 1fb8d4
	int iKey;
Packit 1fb8d4
	int count;
Packit 1fb8d4
	int index;
Packit 1fb8d4
	ULONG_PTR* pKeys;
Packit 1fb8d4
	wKeyValuePair* pair;
Packit 1fb8d4
	wKeyValuePair* nextPair;
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		EnterCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	iKey = 0;
Packit 1fb8d4
	count = table->numOfElements;
Packit Service 5a9772
	*ppKeys = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (count < 1)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (table->synchronized)
Packit 1fb8d4
			LeaveCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
		return 0;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	pKeys = (ULONG_PTR*)calloc(count, sizeof(ULONG_PTR));
Packit 1fb8d4
Packit 1fb8d4
	if (!pKeys)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (table->synchronized)
Packit 1fb8d4
			LeaveCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < table->numOfBuckets; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		pair = table->bucketArray[index];
Packit 1fb8d4
Packit 1fb8d4
		while (pair)
Packit 1fb8d4
		{
Packit 1fb8d4
			nextPair = pair->next;
Packit Service 5a9772
			pKeys[iKey++] = (ULONG_PTR)pair->key;
Packit 1fb8d4
			pair = nextPair;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		LeaveCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	*ppKeys = pKeys;
Packit 1fb8d4
	return count;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Determines whether the HashTable contains a specific key.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL HashTable_Contains(wHashTable* table, void* key)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		EnterCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	status = (HashTable_Get(table, key) != NULL) ? TRUE : FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		LeaveCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Determines whether the HashTable contains a specific key.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL HashTable_ContainsKey(wHashTable* table, void* key)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		EnterCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	status = (HashTable_Get(table, key) != NULL) ? TRUE : FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		LeaveCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Determines whether the HashTable contains a specific value.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
BOOL HashTable_ContainsValue(wHashTable* table, void* value)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	BOOL status = FALSE;
Packit 1fb8d4
	wKeyValuePair* pair;
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		EnterCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < table->numOfBuckets; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		pair = table->bucketArray[index];
Packit 1fb8d4
Packit 1fb8d4
		while (pair)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (table->valueCompare(value, pair->value))
Packit 1fb8d4
			{
Packit 1fb8d4
				status = TRUE;
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			pair = pair->next;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (status)
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (table->synchronized)
Packit 1fb8d4
		LeaveCriticalSection(&table->lock);
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
/**
Packit 1fb8d4
 * Construction, Destruction
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
wHashTable* HashTable_New(BOOL synchronized)
Packit 1fb8d4
{
Packit 1fb8d4
	wHashTable* table;
Packit Service 5a9772
	table = (wHashTable*)calloc(1, sizeof(wHashTable));
Packit 1fb8d4
Packit 1fb8d4
	if (table)
Packit 1fb8d4
	{
Packit 1fb8d4
		table->synchronized = synchronized;
Packit 1fb8d4
		InitializeCriticalSectionAndSpinCount(&(table->lock), 4000);
Packit 1fb8d4
		table->numOfBuckets = 64;
Packit 1fb8d4
		table->numOfElements = 0;
Packit Service 5a9772
		table->bucketArray = (wKeyValuePair**)calloc(table->numOfBuckets, sizeof(wKeyValuePair*));
Packit 1fb8d4
Packit 1fb8d4
		if (!table->bucketArray)
Packit 1fb8d4
		{
Packit 1fb8d4
			free(table);
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		table->idealRatio = 3.0;
Packit 1fb8d4
		table->lowerRehashThreshold = 0.0;
Packit 1fb8d4
		table->upperRehashThreshold = 15.0;
Packit 1fb8d4
		table->hash = HashTable_PointerHash;
Packit 1fb8d4
		table->keyCompare = HashTable_PointerCompare;
Packit 1fb8d4
		table->valueCompare = HashTable_PointerCompare;
Packit 1fb8d4
		table->keyClone = NULL;
Packit 1fb8d4
		table->valueClone = NULL;
Packit 1fb8d4
		table->keyFree = NULL;
Packit 1fb8d4
		table->valueFree = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return table;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void HashTable_Free(wHashTable* table)
Packit 1fb8d4
{
Packit 1fb8d4
	int index;
Packit 1fb8d4
	wKeyValuePair* pair;
Packit 1fb8d4
	wKeyValuePair* nextPair;
Packit 1fb8d4
Packit 1fb8d4
	if (table)
Packit 1fb8d4
	{
Packit 1fb8d4
		for (index = 0; index < table->numOfBuckets; index++)
Packit 1fb8d4
		{
Packit 1fb8d4
			pair = table->bucketArray[index];
Packit 1fb8d4
Packit 1fb8d4
			while (pair)
Packit 1fb8d4
			{
Packit 1fb8d4
				nextPair = pair->next;
Packit 1fb8d4
Packit 1fb8d4
				if (table->keyFree)
Packit 1fb8d4
					table->keyFree(pair->key);
Packit 1fb8d4
Packit 1fb8d4
				if (table->valueFree)
Packit 1fb8d4
					table->valueFree(pair->value);
Packit 1fb8d4
Packit 1fb8d4
				free(pair);
Packit 1fb8d4
				pair = nextPair;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		DeleteCriticalSection(&(table->lock));
Packit 1fb8d4
		free(table->bucketArray);
Packit 1fb8d4
		free(table);
Packit 1fb8d4
	}
Packit 1fb8d4
}