mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
286 lines
7.9 KiB
286 lines
7.9 KiB
/*++
|
|
|
|
Copyright (c) 1991 Microsoft Corporation
|
|
Copyright (c) 1991 Nokia Data Systems AB
|
|
|
|
Module Name:
|
|
|
|
hashobj.c
|
|
|
|
Abstract:
|
|
|
|
The module provides generic non-re-entrant hash object (the
|
|
same object cannot be used in several threads simultaneously).
|
|
The re-entrancy must be done in the specific implementations,
|
|
if it is necessary.
|
|
|
|
The file includes the definiton of hash objects and its the
|
|
operator functions. All data is private. The hash operators are:
|
|
- HashNew // creates a new hash object and returns its handle
|
|
- HashAdd // adds new data to hash object
|
|
- HashUnlink // Unlinks the given data object from hash table
|
|
- HashSearch // Search a key from the hash table
|
|
- HashRead // reads the hash objects to a buffer
|
|
- HashDelete // deletes the object
|
|
- HashLen // returns the number of saved data elemets
|
|
|
|
The client must provide these functions:
|
|
- Comp // compares objects, returns: -1, 0, 1
|
|
- Hash // Calculates the hash key for the object
|
|
- Alloc // Memory allocation subroutine
|
|
- Free // ... (guess what?)
|
|
|
|
Author:
|
|
|
|
Antti Saarenheimo [o-anttis] 06-MAY-1991
|
|
|
|
Revision History:
|
|
--*/
|
|
|
|
//**************** END CLASS HASH ******************
|
|
|
|
#ifdef NO_INCLUDES
|
|
#define FAR far
|
|
typedef unsigned int UINT;
|
|
typedef void FAR * PVOID;
|
|
enum _HashErrors {
|
|
NO_ERROR = 0,
|
|
ERROR_HASH_NO_MEMORY,
|
|
ERROR_HASH_KEY_EXIST,
|
|
ERROR_HASH_NOT_FOUND};
|
|
|
|
//**************** CLASS HASH ******************
|
|
//**** PUBLIC:
|
|
PVOID HashNew(
|
|
UINT cElements, // appr. # elements
|
|
INT (*Hash)( PVOID pKey ), // returns the hash key
|
|
INT (*Comp)( PVOID pKey1, PVOID pKey2 ), // Compares the keys
|
|
PVOID (*Alloc)( UINT cbSize ), // Allocates a memory block
|
|
VOID (*Free)( VOID *p) // Frees a memory block
|
|
);
|
|
INT HashAdd( PVOID hHash, PVOID pData);
|
|
INT HashUnlink( PVOID hHash, PVOID pData);
|
|
PVOID HashSearch( PVOID hHash, PVOID pKey );
|
|
UINT HashRead(
|
|
PVOID hHash, // hash handle
|
|
UINT cElemRead, // # elements to read
|
|
UINT iFirstElem, // index of the first element
|
|
PVOID pBuf[] // buffer for the elements
|
|
);
|
|
UINT HashDelete( PVOID hHash );
|
|
UINT HashLen( PVOID hHash );
|
|
|
|
#else
|
|
#include <fsm.h>
|
|
#endif
|
|
|
|
|
|
// Declare these routines in a .h file:
|
|
|
|
//
|
|
//
|
|
typedef struct _HASH_ELEMENT {
|
|
PVOID pData;
|
|
struct _HASH_ELEMENT FAR *pNext;
|
|
} HASH_ELEMENT, FAR *PHASH_ELEMENT;
|
|
|
|
typedef struct _HASH {
|
|
PHASH_ELEMENT FAR *apHashTable;
|
|
INT (*Hash)( PVOID pData );
|
|
INT (*Comp)( PVOID pData1, PVOID pData2 );
|
|
PVOID (*Alloc)( UINT cbSize );
|
|
VOID (*Free)( VOID *p );
|
|
UINT cElem;
|
|
UINT cHashTable;
|
|
} HASH, FAR *PHASH;
|
|
|
|
static PHASH_ELEMENT FAR *SearchAddr( PHASH pHash, PVOID pKey);
|
|
|
|
//
|
|
// Creates a new hash objetc and returns its handle.
|
|
//
|
|
PVOID HashNew(
|
|
UINT cElements, // appr. # elements
|
|
INT (*Hash)( PVOID pKey ), // returns the hash key
|
|
INT (*Comp)( PVOID pData1, PVOID pData2 ), // Compares the keys
|
|
PVOID (*Alloc)( UINT cbSize ), // Allocates a memory block
|
|
VOID (*Free)( VOID *p) // Frees a memory block
|
|
)
|
|
{
|
|
PHASH pHash = Alloc( sizeof( HASH ) );
|
|
UINT i;
|
|
|
|
if (pHash == 0) return 0;
|
|
|
|
if (!(pHash->apHashTable = Alloc( sizeof( PVOID ) * cElements )))
|
|
{
|
|
Free( pHash );
|
|
return 0;
|
|
}
|
|
// Good optimizer should compile this an efficient mem set
|
|
for (i = 0; i < cElements; i++)
|
|
pHash->apHashTable[i] = 0;
|
|
|
|
pHash->cElem = 0;
|
|
pHash->cHashTable = cElements;
|
|
pHash->Hash = Hash;
|
|
pHash->Alloc = Alloc;
|
|
pHash->Free = Free;
|
|
pHash->Comp = Comp;
|
|
return (PVOID)pHash;
|
|
}
|
|
|
|
//
|
|
// Adds new data to has object. Returns 0 if OK.
|
|
// Retunrs: NO_ERROR, ERROR_HASH_NO_MEMORY, ERROR_HASH_KEY_EXIST
|
|
//
|
|
INT HashAdd( PVOID hHash, PVOID pData)
|
|
{
|
|
PHASH_ELEMENT FAR *ppElem;
|
|
PHASH_ELEMENT pNext;
|
|
|
|
if (HashSearch( hHash, pData) != NULL)
|
|
return ERROR_HASH_KEY_EXIST;
|
|
else
|
|
{
|
|
ppElem = SearchAddr( (PHASH)hHash, pData);
|
|
pNext = *ppElem;
|
|
if (!(*ppElem = ((PHASH)hHash)->Alloc( sizeof( HASH_ELEMENT ))))
|
|
return ERROR_HASH_NO_MEMORY;
|
|
(*ppElem)->pData = pData;
|
|
(*ppElem)->pNext = pNext;
|
|
((PHASH)hHash)->cElem++;
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Unlinks the given data element from the array
|
|
//
|
|
INT HashUnlink( PVOID hHash, PVOID pData)
|
|
{
|
|
PHASH_ELEMENT FAR *ppElem;
|
|
PHASH_ELEMENT pElem;
|
|
|
|
if (HashSearch((PHASH)hHash, pData) == NULL)
|
|
return ERROR_HASH_NOT_FOUND;
|
|
|
|
ppElem = SearchAddr( (PHASH)hHash, pData);
|
|
pElem = *ppElem;
|
|
*ppElem = pElem->pNext;
|
|
((PHASH)hHash)->Free( pElem );
|
|
((PHASH)hHash)->cElem--;
|
|
return NO_ERROR;
|
|
}
|
|
|
|
//
|
|
// Reads the data elemets from hash table to a buffer.
|
|
// Returns the number of read elements.
|
|
//
|
|
UINT HashRead(
|
|
PVOID hHash, // hash handle
|
|
UINT cElemRead, // # elements to read
|
|
UINT iFirstElem, // index of the first element
|
|
PVOID pBuf[] // buffer for the elements
|
|
)
|
|
{
|
|
UINT iCurElem = 0;
|
|
UINT iCurSlot;
|
|
UINT cElemCopied = 0;
|
|
UINT cHashTable = ((PHASH)hHash)->cHashTable;
|
|
PHASH_ELEMENT FAR * apHashTable = ((PHASH)hHash)->apHashTable;
|
|
PHASH_ELEMENT pElem;
|
|
|
|
for (iCurSlot = 0; iCurSlot < cHashTable; iCurSlot++)
|
|
{
|
|
for (pElem = apHashTable[iCurSlot]; pElem; pElem = pElem->pNext)
|
|
{
|
|
if (cElemCopied == cElemRead)
|
|
return cElemCopied;
|
|
|
|
if (iCurElem >= iFirstElem)
|
|
{
|
|
pBuf[cElemCopied++] = pElem;
|
|
}
|
|
iCurElem++;
|
|
}
|
|
}
|
|
return cElemCopied;
|
|
}
|
|
|
|
//
|
|
// Deletes the hash object and releases all memory allocated by
|
|
// the object. It does not free any data allocated by the clients.
|
|
//
|
|
UINT HashDelete( PVOID hHash )
|
|
{
|
|
PHASH_ELEMENT aBuf[50];
|
|
UINT i, cRead;
|
|
|
|
// read and remove all hash elements, every read scans
|
|
// the whole hash table => read the data objects in blocks
|
|
while (cRead = HashRead( hHash, 50, 0, aBuf))
|
|
for (i = 0; i < cRead; i++)
|
|
HashUnlink( hHash, aBuf[i]->pData );
|
|
|
|
((PHASH)hHash)->Free( ((PHASH)hHash)->apHashTable );
|
|
((PHASH)hHash)->Free( hHash );
|
|
return 0;
|
|
}
|
|
|
|
//
|
|
// Returns the number of data elemets in a hash object
|
|
//
|
|
UINT HashLen( PVOID hHash )
|
|
{
|
|
return ((PHASH)hHash)->cElem;
|
|
}
|
|
//
|
|
// Search a key from the hash table
|
|
//
|
|
PVOID
|
|
HashSearch( PVOID pHash, PVOID pKey )
|
|
{
|
|
INT iRet;
|
|
PHASH_ELEMENT pElem;
|
|
|
|
pElem =
|
|
((PHASH)pHash)->apHashTable[
|
|
((PHASH)pHash)->Hash( pKey ) % ((PHASH)pHash)->cHashTable];
|
|
for (;;)
|
|
{
|
|
// return the address of the memory pointer reserved for this
|
|
// data object, it's address of a element in the hash table or
|
|
// address of pNext pointer in the list. The objects are increasing
|
|
// order in the list.
|
|
if (pElem == NULL ||
|
|
(iRet = ((PHASH)pHash)->Comp( pKey, pElem->pData)) > 0)
|
|
return NULL;
|
|
else if (iRet == 0)
|
|
return pElem->pData;
|
|
pElem = pElem->pNext;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Returns the address of the next free slot
|
|
//
|
|
static PHASH_ELEMENT FAR *
|
|
SearchAddr( PHASH pHash, PVOID pKey )
|
|
{
|
|
PHASH_ELEMENT FAR * ppElem;
|
|
|
|
ppElem = &(pHash->apHashTable[ pHash->Hash( pKey ) % pHash->cHashTable ]);
|
|
for (;;)
|
|
{
|
|
// return the address of the memory pointer reserved for this
|
|
// data object, it's address of a element in the hash table or
|
|
// address of pNext pointer in the list. The objects are increasing
|
|
// order in the list.
|
|
if (*ppElem == NULL ||
|
|
pHash->Comp( pKey, (*ppElem)->pData) >= 0)
|
|
return ppElem;
|
|
ppElem = &((*ppElem)->pNext);
|
|
}
|
|
}
|
|
|