|
|
/*
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; }
|