271 lines
6.2 KiB
C
271 lines
6.2 KiB
C
|
/*
|
||
|
File HashTab.h
|
||
|
|
||
|
Definitions for creating/dealing with hash tables.
|
||
|
|
||
|
Paul Mayfield, 3/30/98
|
||
|
*/
|
||
|
|
||
|
#include "hashtab.h"
|
||
|
|
||
|
// Represents nodes in the binary tree
|
||
|
typedef struct _HTNODE {
|
||
|
HANDLE hData;
|
||
|
struct _HTNODE * pNext;
|
||
|
} HTNODE;
|
||
|
|
||
|
// Represents a binary tree
|
||
|
typedef struct _HASHTAB {
|
||
|
HTNODE ** ppNodes;
|
||
|
ULONG ulSize;
|
||
|
HashTabHashFuncPtr pHash;
|
||
|
HashTabKeyCompFuncPtr pCompKeyAndElem;
|
||
|
HashTabAllocFuncPtr pAlloc;
|
||
|
HashTabFreeFuncPtr pFree;
|
||
|
HashTabFreeElemFuncPtr pFreeElem;
|
||
|
ULONG dwCount;
|
||
|
|
||
|
} HASHTAB;
|
||
|
|
||
|
// Default allocator
|
||
|
PVOID HashTabAlloc (ULONG ulSize) {
|
||
|
return RtlAllocateHeap (RtlProcessHeap(), 0, ulSize);
|
||
|
}
|
||
|
|
||
|
// Default freer
|
||
|
VOID HashTabFree (PVOID pvData) {
|
||
|
RtlFreeHeap (RtlProcessHeap(), 0, pvData);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create a hash table
|
||
|
//
|
||
|
ULONG HashTabCreate (
|
||
|
IN ULONG ulSize,
|
||
|
IN HashTabHashFuncPtr pHash,
|
||
|
IN HashTabKeyCompFuncPtr pCompKeyAndElem,
|
||
|
IN OPTIONAL HashTabAllocFuncPtr pAlloc,
|
||
|
IN OPTIONAL HashTabFreeFuncPtr pFree,
|
||
|
IN OPTIONAL HashTabFreeElemFuncPtr pFreeElem,
|
||
|
OUT HANDLE * phHashTab )
|
||
|
{
|
||
|
HASHTAB * pTable;
|
||
|
|
||
|
// Validate and initailize variables
|
||
|
if (!pHash || !pCompKeyAndElem || !phHashTab)
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
|
||
|
if (!pAlloc)
|
||
|
pAlloc = HashTabAlloc;
|
||
|
|
||
|
// Allocate the table structure
|
||
|
pTable = (*pAlloc)(sizeof(HASHTAB));
|
||
|
if (!pTable)
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
|
||
|
// Initialize
|
||
|
pTable->pHash = pHash;
|
||
|
pTable->ulSize = ulSize;
|
||
|
pTable->pCompKeyAndElem = pCompKeyAndElem;
|
||
|
pTable->pAlloc = pAlloc;
|
||
|
pTable->pFree = (pFree) ? pFree : HashTabFree;
|
||
|
pTable->pFreeElem = pFreeElem;
|
||
|
|
||
|
// Allocate the table
|
||
|
pTable->ppNodes = (pAlloc)(sizeof(HTNODE*) * ulSize);
|
||
|
if (!pTable->ppNodes) {
|
||
|
(*(pTable->pFree))(pTable);
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
}
|
||
|
RtlZeroMemory (pTable->ppNodes, sizeof(HTNODE*) * ulSize);
|
||
|
|
||
|
*phHashTab = (HANDLE)pTable;
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Clean up the hash table.
|
||
|
//
|
||
|
ULONG
|
||
|
HashTabCleanup (
|
||
|
IN HANDLE hHashTab )
|
||
|
{
|
||
|
HASHTAB * pTable = (HASHTAB*)hHashTab;
|
||
|
HTNODE * pNode, * pNext;
|
||
|
ULONG i;
|
||
|
|
||
|
if (pTable == NULL)
|
||
|
{
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < pTable->ulSize; i++ )
|
||
|
{
|
||
|
if ((pNode = pTable->ppNodes[i]) != NULL)
|
||
|
{
|
||
|
while (pNode)
|
||
|
{
|
||
|
pNext = pNode->pNext;
|
||
|
if (pTable->pFreeElem)
|
||
|
{
|
||
|
(*(pTable->pFreeElem))(pNode->hData);
|
||
|
}
|
||
|
(*(pTable->pFree))(pNode);
|
||
|
pNode = pNext;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
(*(pTable->pFree))(pTable->ppNodes);
|
||
|
(*(pTable->pFree))(pTable);
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Insert an element in a hash table
|
||
|
//
|
||
|
ULONG HashTabInsert (
|
||
|
IN HANDLE hHashTab,
|
||
|
IN HANDLE hKey,
|
||
|
IN HANDLE hData )
|
||
|
{
|
||
|
HASHTAB * pTable = (HASHTAB*)hHashTab;
|
||
|
HTNODE * pNode;
|
||
|
ULONG ulIndex;
|
||
|
|
||
|
// Validate Params
|
||
|
if (!hHashTab || !hData)
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
|
||
|
// Find out where the element goes
|
||
|
ulIndex = (* (pTable->pHash))(hKey);
|
||
|
if (ulIndex >= pTable->ulSize)
|
||
|
return ERROR_INVALID_INDEX;
|
||
|
|
||
|
// Allocate a new hash table node
|
||
|
pNode = (* (pTable->pAlloc))(sizeof (HTNODE));
|
||
|
if (!pNode)
|
||
|
return ERROR_NOT_ENOUGH_MEMORY;
|
||
|
|
||
|
// Insert the node into the appropriate location in the
|
||
|
// hash table.
|
||
|
pNode->pNext = pTable->ppNodes[ulIndex];
|
||
|
pTable->ppNodes[ulIndex] = pNode;
|
||
|
pNode->hData = hData;
|
||
|
pTable->dwCount++;
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Removes the data associated with the given key
|
||
|
//
|
||
|
ULONG HashTabRemove (
|
||
|
IN HANDLE hHashTab,
|
||
|
IN HANDLE hKey)
|
||
|
{
|
||
|
HASHTAB * pTable = (HASHTAB*)hHashTab;
|
||
|
HTNODE * pCur, * pPrev;
|
||
|
ULONG ulIndex;
|
||
|
int iCmp;
|
||
|
|
||
|
// Validate Params
|
||
|
if (!hHashTab)
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
|
||
|
// Find out where the element should be
|
||
|
ulIndex = (* (pTable->pHash))(hKey);
|
||
|
if (ulIndex >= pTable->ulSize)
|
||
|
return ERROR_INVALID_INDEX;
|
||
|
if (pTable->ppNodes[ulIndex] == NULL)
|
||
|
return ERROR_NOT_FOUND;
|
||
|
|
||
|
// If the element is at the start of the
|
||
|
// list, remove it and we're done.
|
||
|
pCur = pTable->ppNodes[ulIndex];
|
||
|
if ( (*(pTable->pCompKeyAndElem))(hKey, pCur->hData) == 0 ) {
|
||
|
pTable->ppNodes[ulIndex] = pCur->pNext;
|
||
|
if (pTable->pFreeElem)
|
||
|
(*(pTable->pFreeElem))(pCur->hData);
|
||
|
(*(pTable->pFree))(pCur);
|
||
|
pTable->dwCount--;
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|
||
|
// Otherwise, loop through the list until we find a
|
||
|
// match.
|
||
|
pPrev = pCur;
|
||
|
pCur = pCur->pNext;
|
||
|
while (pCur) {
|
||
|
iCmp = (*(pTable->pCompKeyAndElem))(hKey, pCur->hData);
|
||
|
if ( iCmp == 0 ) {
|
||
|
pPrev->pNext = pCur->pNext;
|
||
|
if (pTable->pFreeElem)
|
||
|
(*(pTable->pFreeElem))(pCur->hData);
|
||
|
(*(pTable->pFree))(pCur);
|
||
|
pTable->dwCount--;
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
pPrev = pCur;
|
||
|
pCur = pCur->pNext;
|
||
|
}
|
||
|
|
||
|
return ERROR_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Search in the table for the data associated with the given key
|
||
|
//
|
||
|
ULONG HashTabFind (
|
||
|
IN HANDLE hHashTab,
|
||
|
IN HANDLE hKey,
|
||
|
OUT HANDLE * phData )
|
||
|
{
|
||
|
HASHTAB * pTable = (HASHTAB*)hHashTab;
|
||
|
HTNODE * pNode;
|
||
|
ULONG ulIndex;
|
||
|
|
||
|
// Validate Params
|
||
|
if (!hHashTab || !phData)
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
|
||
|
// Find out where the element goes
|
||
|
ulIndex = (* (pTable->pHash))(hKey);
|
||
|
if (ulIndex >= pTable->ulSize)
|
||
|
return ERROR_INVALID_INDEX;
|
||
|
|
||
|
// Search through the list at the given index
|
||
|
pNode = pTable->ppNodes[ulIndex];
|
||
|
while (pNode) {
|
||
|
if ( (*(pTable->pCompKeyAndElem))(hKey, pNode->hData) == 0 ) {
|
||
|
*phData = pNode->hData;
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
pNode = pNode->pNext;
|
||
|
}
|
||
|
|
||
|
return ERROR_NOT_FOUND;
|
||
|
}
|
||
|
|
||
|
ULONG
|
||
|
HashTabGetCount(
|
||
|
IN HANDLE hHashTab,
|
||
|
OUT ULONG* lpdwCount)
|
||
|
{
|
||
|
HASHTAB * pTable = (HASHTAB*)hHashTab;
|
||
|
|
||
|
if (!lpdwCount || !hHashTab)
|
||
|
{
|
||
|
return ERROR_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
*lpdwCount = pTable->dwCount;
|
||
|
|
||
|
return NO_ERROR;
|
||
|
}
|
||
|
|