3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ex/hashtab.c
6 * PURPOSE: Hash table support
8 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
12 * NOTES: The hash function is from:
13 * Bob Jenkins <bob_jenkins@burtleburtle.net>
14 * http://burtleburtle.net/bob/hash/doobs.html
20 #include <internal/debug.h>
22 /* FUNCTIONS ****************************************************************/
24 #define ExpHashTableSize(n) ((ULONG)1 << (n))
25 #define ExpHashTableMask(n) (ExpHashTableSize(n) - 1)
27 #define ExpHashMix(a, b, c) \
29 a -= b; a -= c; a ^= (c >> 13); \
30 b -= c; b -= a; b ^= (a << 8); \
31 c -= a; c -= b; c ^= (b >> 13); \
32 a -= b; a -= c; a ^= (c >> 12); \
33 b -= c; b -= a; b ^= (a << 16); \
34 c -= a; c -= b; c ^= (b >> 5); \
35 a -= b; a -= c; a ^= (c >> 3); \
36 b -= c; b -= a; b ^= (a << 10); \
37 c -= a; c -= b; c ^= (b >> 15); \
45 register ULONG a
, b
, c
, len
;
47 /* Set up the internal state */
49 a
= b
= 0x9e3779b9; /* The golden ratio; an arbitrary value */
52 /* Handle most of the key */
55 a
+= (Key
[0] + ((ULONG
)Key
[1]<<8) + ((ULONG
)Key
[2]<<16) + ((ULONG
)Key
[3]<<24));
56 b
+= (Key
[4] + ((ULONG
)Key
[5]<<8) + ((ULONG
)Key
[6]<<16) + ((ULONG
)Key
[7]<<24));
57 c
+= (Key
[8] + ((ULONG
)Key
[9]<<8) + ((ULONG
)Key
[10]<<16)+ ((ULONG
)Key
[11]<<24));
62 /* Handle the last 11 bytes */
64 switch(len
) /* All the case statements fall through */
66 case 11: c
+= ((ULONG
)Key
[10] << 24);
67 case 10: c
+= ((ULONG
)Key
[9] << 16);
68 case 9 : c
+= ((ULONG
)Key
[8] << 8);
69 /* The first byte of c is reserved for the length */
70 case 8 : b
+= ((ULONG
)Key
[7] << 24);
71 case 7 : b
+= ((ULONG
)Key
[6] << 16);
72 case 6 : b
+= ((ULONG
)Key
[5] << 8);
74 case 4 : a
+= ((ULONG
)Key
[3] << 24);
75 case 3 : a
+= ((ULONG
)Key
[2] << 16);
76 case 2 : a
+= ((ULONG
)Key
[1] << 8);
78 /* case 0: nothing left to add */
91 ExpLockHashTable(PHASH_TABLE HashTable
,
94 if (HashTable
->UseNonPagedPool
)
96 KeAcquireSpinLock(&HashTable
->Lock
.NonPaged
, OldIrql
);
100 ExAcquireFastMutex(&HashTable
->Lock
.Paged
);
106 * Unlock the hash table
109 ExpUnlockHashTable(PHASH_TABLE HashTable
,
112 if (HashTable
->UseNonPagedPool
)
114 KeReleaseSpinLock(&HashTable
->Lock
.NonPaged
, *OldIrql
);
118 ExReleaseFastMutex(&HashTable
->Lock
.Paged
);
124 * Insert a value in a hash table.
127 ExpInsertHashTable(IN PHASH_TABLE HashTable
,
134 Index
= (ExpHash(Key
, KeyLength
) & ExpHashTableMask(HashTable
->HashTableSize
));
136 ExInsertSplayTree(&HashTable
->HashTrees
[Index
], Key
, Value
);
141 * Search for a value associated with a given key in a hash table.
143 inline BOOLEAN STDCALL
144 ExpSearchHashTable(IN PHASH_TABLE HashTable
,
151 Index
= (ExpHash(Key
, KeyLength
) & ExpHashTableMask(HashTable
->HashTableSize
));
153 return ExSearchSplayTree(&HashTable
->HashTrees
[Index
], Key
, Value
);
158 * Remove a value associated with a given key from a hash table.
161 ExpRemoveHashTable(IN PHASH_TABLE HashTable
,
168 Index
= (ExpHash(Key
, KeyLength
) & ExpHashTableMask(HashTable
->HashTableSize
));
170 return ExRemoveSplayTree(&HashTable
->HashTrees
[Index
], Key
, Value
);
175 * Initializes a hash table.
178 ExInitializeHashTable(IN PHASH_TABLE HashTable
,
179 IN ULONG HashTableSize
,
180 IN PKEY_COMPARATOR Compare OPTIONAL
,
181 IN BOOLEAN UseNonPagedPool
)
186 RtlZeroMemory(HashTable
, sizeof(HASH_TABLE
));
188 HashTable
->HashTableSize
= HashTableSize
;
190 HashTable
->UseNonPagedPool
= UseNonPagedPool
;
194 KeInitializeSpinLock(&HashTable
->Lock
.NonPaged
);
195 HashTable
->HashTrees
= ExAllocatePool(NonPagedPool
, ExpHashTableSize(HashTableSize
) * sizeof(SPLAY_TREE
));
199 ExInitializeFastMutex(&HashTable
->Lock
.Paged
);
200 HashTable
->HashTrees
= ExAllocatePool(PagedPool
, ExpHashTableSize(HashTableSize
) * sizeof(SPLAY_TREE
));
203 if (HashTable
->HashTrees
== NULL
)
208 for (Index
= 0; Index
< ExpHashTableSize(HashTableSize
); Index
++)
210 Status
= ExInitializeSplayTree(&HashTable
->HashTrees
[Index
], Compare
, FALSE
, UseNonPagedPool
);
216 for (i
= Index
- 1; i
>= 0; i
--)
218 ExDeleteSplayTree(&HashTable
->HashTrees
[i
]);
221 ExFreePool(HashTable
->HashTrees
);
232 * Release resources used by a hash table.
235 ExDeleteHashTable(IN PHASH_TABLE HashTable
)
239 for (Index
= 0; Index
< ExpHashTableSize(HashTable
->HashTableSize
); Index
++)
241 ExDeleteSplayTree(&HashTable
->HashTrees
[Index
]);
244 ExFreePool(HashTable
->HashTrees
);
249 * Insert a value in a hash table.
252 ExInsertHashTable(IN PHASH_TABLE HashTable
,
259 /* FIXME: Use SEH for error reporting */
261 ExpLockHashTable(HashTable
, &OldIrql
);
262 ExpInsertHashTable(HashTable
, Key
, KeyLength
, Value
);
263 ExpUnlockHashTable(HashTable
, &OldIrql
);
268 * Search for a value associated with a given key in a hash table.
271 ExSearchHashTable(IN PHASH_TABLE HashTable
,
279 ExpLockHashTable(HashTable
, &OldIrql
);
280 Status
= ExpSearchHashTable(HashTable
, Key
, KeyLength
, Value
);
281 ExpUnlockHashTable(HashTable
, &OldIrql
);
288 * Remove a value associated with a given key from a hash table.
291 ExRemoveHashTable(IN PHASH_TABLE HashTable
,
299 ExpLockHashTable(HashTable
, &OldIrql
);
300 Status
= ExpRemoveHashTable(HashTable
, Key
, KeyLength
, Value
);
301 ExpUnlockHashTable(HashTable
, &OldIrql
);