mirror of
https://github.com/reactos/reactos.git
synced 2026-09-21 17:19:57 +08:00
Added a splay tree implementation Added a hash table implementation svn path=/trunk/; revision=2766
271 lines
6.4 KiB
C
271 lines
6.4 KiB
C
/*
|
|
* ReactOS kernel
|
|
* Copyright (C) 1998-2002 ReactOS Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
*/
|
|
/*
|
|
* PROJECT: ReactOS kernel
|
|
* FILE: hashtab.c
|
|
* PURPOSE: Hash table support
|
|
* PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
* NOTES: The hash function is from:
|
|
* Bob Jenkins <bob_jenkins@burtleburtle.net>
|
|
* http://burtleburtle.net/bob/hash/doobs.html
|
|
* UPDATE HISTORY:
|
|
* 15-03-2002 CSH Created
|
|
*/
|
|
#include <ddk/ntddk.h>
|
|
#include <internal/ex.h>
|
|
|
|
#define NDEBUG
|
|
#include <internal/debug.h>
|
|
|
|
/* FUNCTIONS ****************************************************************/
|
|
|
|
#define ExpHashTableSize(n) ((ULONG)1 << (n))
|
|
#define ExpHashTableMask(n) (ExpHashTableSize(n) - 1)
|
|
|
|
#define ExpHashMix(a, b, c) \
|
|
{ \
|
|
a -= b; a -= c; a ^= (c >> 13); \
|
|
b -= c; b -= a; b ^= (a << 8); \
|
|
c -= a; c -= b; c ^= (b >> 13); \
|
|
a -= b; a -= c; a ^= (c >> 12); \
|
|
b -= c; b -= a; b ^= (a << 16); \
|
|
c -= a; c -= b; c ^= (b >> 5); \
|
|
a -= b; a -= c; a ^= (c >> 3); \
|
|
b -= c; b -= a; b ^= (a << 10); \
|
|
c -= a; c -= b; c ^= (b >> 15); \
|
|
}
|
|
|
|
|
|
ULONG
|
|
ExpHash(PUCHAR Key,
|
|
ULONG KeyLength)
|
|
{
|
|
register ULONG a, b, c, len;
|
|
|
|
/* Set up the internal state */
|
|
len = KeyLength;
|
|
a = b = 0x9e3779b9; /* The golden ratio; an arbitrary value */
|
|
c = 0;
|
|
|
|
/* Handle most of the key */
|
|
while (len >= 12)
|
|
{
|
|
a += (Key[0] + ((ULONG)Key[1]<<8) + ((ULONG)Key[2]<<16) + ((ULONG)Key[3]<<24));
|
|
b += (Key[4] + ((ULONG)Key[5]<<8) + ((ULONG)Key[6]<<16) + ((ULONG)Key[7]<<24));
|
|
c += (Key[8] + ((ULONG)Key[9]<<8) + ((ULONG)Key[10]<<16)+ ((ULONG)Key[11]<<24));
|
|
ExpHashMix(a, b, c);
|
|
Key += 12; len -= 12;
|
|
}
|
|
|
|
/* Handle the last 11 bytes */
|
|
c += KeyLength;
|
|
switch(len) /* All the case statements fall through */
|
|
{
|
|
case 11: c += ((ULONG)Key[10] << 24);
|
|
case 10: c += ((ULONG)Key[9] << 16);
|
|
case 9 : c += ((ULONG)Key[8] << 8);
|
|
/* The first byte of c is reserved for the length */
|
|
case 8 : b += ((ULONG)Key[7] << 24);
|
|
case 7 : b += ((ULONG)Key[6] << 16);
|
|
case 6 : b += ((ULONG)Key[5] << 8);
|
|
case 5 : b += Key[4];
|
|
case 4 : a += ((ULONG)Key[3] << 24);
|
|
case 3 : a += ((ULONG)Key[2] << 16);
|
|
case 2 : a += ((ULONG)Key[1] << 8);
|
|
case 1 : a += Key[0];
|
|
/* case 0: nothing left to add */
|
|
}
|
|
|
|
ExpHashMix(a, b, c);
|
|
|
|
return c;
|
|
}
|
|
|
|
|
|
/*
|
|
* Insert a value in a hash table.
|
|
*/
|
|
inline VOID STDCALL
|
|
ExpInsertHashTable(IN PHASH_TABLE HashTable,
|
|
IN PVOID Key,
|
|
IN ULONG KeyLength,
|
|
IN PVOID Value)
|
|
{
|
|
ULONG Index;
|
|
|
|
Index = (ExpHash(Key, KeyLength) & ExpHashTableMask(HashTable->HashTableSize));
|
|
|
|
ExInsertSplayTree(&HashTable->HashTrees[Index], Key, Value);
|
|
}
|
|
|
|
|
|
/*
|
|
* Search for a value associated with a given key in a hash table.
|
|
*/
|
|
inline BOOLEAN STDCALL
|
|
ExpSearchHashTable(IN PHASH_TABLE HashTable,
|
|
IN PVOID Key,
|
|
IN ULONG KeyLength,
|
|
OUT PVOID * Value)
|
|
{
|
|
ULONG Index;
|
|
|
|
Index = (ExpHash(Key, KeyLength) & ExpHashTableMask(HashTable->HashTableSize));
|
|
|
|
return ExSearchSplayTree(&HashTable->HashTrees[Index], Key, Value);
|
|
}
|
|
|
|
|
|
/*
|
|
* Remove a value associated with a given key from a hash table.
|
|
*/
|
|
BOOLEAN STDCALL
|
|
ExpRemoveHashTable(IN PHASH_TABLE HashTable,
|
|
IN PVOID Key,
|
|
IN ULONG KeyLength,
|
|
IN PVOID * Value)
|
|
{
|
|
ULONG Index;
|
|
|
|
Index = (ExpHash(Key, KeyLength) & ExpHashTableMask(HashTable->HashTableSize));
|
|
|
|
return ExRemoveSplayTree(&HashTable->HashTrees[Index], Key, Value);
|
|
}
|
|
|
|
|
|
/*
|
|
* Initializes a hash table.
|
|
*/
|
|
BOOLEAN STDCALL
|
|
ExInitializeHashTable(IN PHASH_TABLE HashTable,
|
|
IN ULONG HashTableSize,
|
|
IN PKEY_COMPARATOR Compare OPTIONAL)
|
|
{
|
|
BOOLEAN Status;
|
|
LONG Index;
|
|
|
|
RtlZeroMemory(HashTable, sizeof(HASH_TABLE));
|
|
|
|
HashTable->HashTableSize = HashTableSize;
|
|
|
|
ExInitializeFastMutex(&HashTable->Lock);
|
|
|
|
HashTable->HashTrees = ExAllocatePool(PagedPool, ExpHashTableSize(HashTableSize) * sizeof(SPLAY_TREE));
|
|
|
|
if (HashTable->HashTrees == NULL)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
for (Index = 0; Index < ExpHashTableSize(HashTableSize); Index++)
|
|
{
|
|
Status = ExInitializeSplayTree(&HashTable->HashTrees[Index], Compare, FALSE);
|
|
|
|
if (!Status)
|
|
{
|
|
LONG i;
|
|
|
|
for (i = Index - 1; i >= 0; i--)
|
|
{
|
|
ExDeleteSplayTree(&HashTable->HashTrees[i]);
|
|
}
|
|
|
|
ExFreePool(HashTable->HashTrees);
|
|
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
/*
|
|
* Release resources used by a hash table.
|
|
*/
|
|
VOID STDCALL
|
|
ExDeleteHashTable(IN PHASH_TABLE HashTable)
|
|
{
|
|
ULONG Index;
|
|
|
|
for (Index = 0; Index < ExpHashTableSize(HashTable->HashTableSize); Index++)
|
|
{
|
|
ExDeleteSplayTree(&HashTable->HashTrees[Index]);
|
|
}
|
|
|
|
ExFreePool(HashTable->HashTrees);
|
|
}
|
|
|
|
|
|
/*
|
|
* Insert a value in a hash table.
|
|
*/
|
|
VOID STDCALL
|
|
ExInsertHashTable(IN PHASH_TABLE HashTable,
|
|
IN PVOID Key,
|
|
IN ULONG KeyLength,
|
|
IN PVOID Value)
|
|
{
|
|
/* FIXME: Use SEH for error reporting */
|
|
|
|
ExAcquireFastMutex(&HashTable->Lock);
|
|
ExpInsertHashTable(HashTable, Key, KeyLength, Value);
|
|
ExReleaseFastMutex(&HashTable->Lock);
|
|
}
|
|
|
|
|
|
/*
|
|
* Search for a value associated with a given key in a hash table.
|
|
*/
|
|
BOOLEAN STDCALL
|
|
ExSearchHashTable(IN PHASH_TABLE HashTable,
|
|
IN PVOID Key,
|
|
IN ULONG KeyLength,
|
|
OUT PVOID * Value)
|
|
{
|
|
BOOLEAN Status;
|
|
|
|
ExAcquireFastMutex(&HashTable->Lock);
|
|
Status = ExpSearchHashTable(HashTable, Key, KeyLength, Value);
|
|
ExReleaseFastMutex(&HashTable->Lock);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
/*
|
|
* Remove a value associated with a given key from a hash table.
|
|
*/
|
|
BOOLEAN STDCALL
|
|
ExRemoveHashTable(IN PHASH_TABLE HashTable,
|
|
IN PVOID Key,
|
|
IN ULONG KeyLength,
|
|
IN PVOID * Value)
|
|
{
|
|
BOOLEAN Status;
|
|
|
|
ExAcquireFastMutex(&HashTable->Lock);
|
|
Status = ExpRemoveHashTable(HashTable, Key, KeyLength, Value);
|
|
ExReleaseFastMutex(&HashTable->Lock);
|
|
|
|
return Status;
|
|
}
|
|
|
|
/* EOF */
|