3 * Copyright (C) 1998-2002 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * PROJECT: ReactOS kernel
22 * PURPOSE: Hash table support
23 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
24 * NOTES: The hash function is from:
25 * Bob Jenkins <bob_jenkins@burtleburtle.net>
26 * http://burtleburtle.net/bob/hash/doobs.html
28 * 15-03-2002 CSH Created
34 #include <internal/debug.h>
37 /* FUNCTIONS ****************************************************************/
39 #define ExpHashTableSize(n) ((ULONG)1 << (n))
40 #define ExpHashTableMask(n) (ExpHashTableSize(n) - 1)
42 #define ExpHashMix(a, b, c) \
44 a -= b; a -= c; a ^= (c >> 13); \
45 b -= c; b -= a; b ^= (a << 8); \
46 c -= a; c -= b; c ^= (b >> 13); \
47 a -= b; a -= c; a ^= (c >> 12); \
48 b -= c; b -= a; b ^= (a << 16); \
49 c -= a; c -= b; c ^= (b >> 5); \
50 a -= b; a -= c; a ^= (c >> 3); \
51 b -= c; b -= a; b ^= (a << 10); \
52 c -= a; c -= b; c ^= (b >> 15); \
60 register ULONG a
, b
, c
, len
;
62 /* Set up the internal state */
64 a
= b
= 0x9e3779b9; /* The golden ratio; an arbitrary value */
67 /* Handle most of the key */
70 a
+= (Key
[0] + ((ULONG
)Key
[1]<<8) + ((ULONG
)Key
[2]<<16) + ((ULONG
)Key
[3]<<24));
71 b
+= (Key
[4] + ((ULONG
)Key
[5]<<8) + ((ULONG
)Key
[6]<<16) + ((ULONG
)Key
[7]<<24));
72 c
+= (Key
[8] + ((ULONG
)Key
[9]<<8) + ((ULONG
)Key
[10]<<16)+ ((ULONG
)Key
[11]<<24));
77 /* Handle the last 11 bytes */
79 switch(len
) /* All the case statements fall through */
81 case 11: c
+= ((ULONG
)Key
[10] << 24);
82 case 10: c
+= ((ULONG
)Key
[9] << 16);
83 case 9 : c
+= ((ULONG
)Key
[8] << 8);
84 /* The first byte of c is reserved for the length */
85 case 8 : b
+= ((ULONG
)Key
[7] << 24);
86 case 7 : b
+= ((ULONG
)Key
[6] << 16);
87 case 6 : b
+= ((ULONG
)Key
[5] << 8);
89 case 4 : a
+= ((ULONG
)Key
[3] << 24);
90 case 3 : a
+= ((ULONG
)Key
[2] << 16);
91 case 2 : a
+= ((ULONG
)Key
[1] << 8);
93 /* case 0: nothing left to add */
103 * Lock the hash table
106 ExpLockHashTable(PHASH_TABLE HashTable
,
109 if (HashTable
->UseNonPagedPool
)
111 KeAcquireSpinLock(&HashTable
->Lock
.NonPaged
, OldIrql
);
115 ExAcquireFastMutex(&HashTable
->Lock
.Paged
);
121 * Unlock the hash table
124 ExpUnlockHashTable(PHASH_TABLE HashTable
,
127 if (HashTable
->UseNonPagedPool
)
129 KeReleaseSpinLock(&HashTable
->Lock
.NonPaged
, *OldIrql
);
133 ExReleaseFastMutex(&HashTable
->Lock
.Paged
);
139 * Insert a value in a hash table.
142 ExpInsertHashTable(IN PHASH_TABLE HashTable
,
149 Index
= (ExpHash(Key
, KeyLength
) & ExpHashTableMask(HashTable
->HashTableSize
));
151 ExInsertSplayTree(&HashTable
->HashTrees
[Index
], Key
, Value
);
156 * Search for a value associated with a given key in a hash table.
158 inline BOOLEAN STDCALL
159 ExpSearchHashTable(IN PHASH_TABLE HashTable
,
166 Index
= (ExpHash(Key
, KeyLength
) & ExpHashTableMask(HashTable
->HashTableSize
));
168 return ExSearchSplayTree(&HashTable
->HashTrees
[Index
], Key
, Value
);
173 * Remove a value associated with a given key from a hash table.
176 ExpRemoveHashTable(IN PHASH_TABLE HashTable
,
183 Index
= (ExpHash(Key
, KeyLength
) & ExpHashTableMask(HashTable
->HashTableSize
));
185 return ExRemoveSplayTree(&HashTable
->HashTrees
[Index
], Key
, Value
);
190 * Initializes a hash table.
193 ExInitializeHashTable(IN PHASH_TABLE HashTable
,
194 IN ULONG HashTableSize
,
195 IN PKEY_COMPARATOR Compare OPTIONAL
,
196 IN BOOLEAN UseNonPagedPool
)
201 RtlZeroMemory(HashTable
, sizeof(HASH_TABLE
));
203 HashTable
->HashTableSize
= HashTableSize
;
205 HashTable
->UseNonPagedPool
= UseNonPagedPool
;
209 KeInitializeSpinLock(&HashTable
->Lock
.NonPaged
);
210 HashTable
->HashTrees
= ExAllocatePool(NonPagedPool
, ExpHashTableSize(HashTableSize
) * sizeof(SPLAY_TREE
));
214 ExInitializeFastMutex(&HashTable
->Lock
.Paged
);
215 HashTable
->HashTrees
= ExAllocatePool(PagedPool
, ExpHashTableSize(HashTableSize
) * sizeof(SPLAY_TREE
));
218 if (HashTable
->HashTrees
== NULL
)
223 for (Index
= 0; Index
< ExpHashTableSize(HashTableSize
); Index
++)
225 Status
= ExInitializeSplayTree(&HashTable
->HashTrees
[Index
], Compare
, FALSE
, UseNonPagedPool
);
231 for (i
= Index
- 1; i
>= 0; i
--)
233 ExDeleteSplayTree(&HashTable
->HashTrees
[i
]);
236 ExFreePool(HashTable
->HashTrees
);
247 * Release resources used by a hash table.
250 ExDeleteHashTable(IN PHASH_TABLE HashTable
)
254 for (Index
= 0; Index
< ExpHashTableSize(HashTable
->HashTableSize
); Index
++)
256 ExDeleteSplayTree(&HashTable
->HashTrees
[Index
]);
259 ExFreePool(HashTable
->HashTrees
);
264 * Insert a value in a hash table.
267 ExInsertHashTable(IN PHASH_TABLE HashTable
,
274 /* FIXME: Use SEH for error reporting */
276 ExpLockHashTable(HashTable
, &OldIrql
);
277 ExpInsertHashTable(HashTable
, Key
, KeyLength
, Value
);
278 ExpUnlockHashTable(HashTable
, &OldIrql
);
283 * Search for a value associated with a given key in a hash table.
286 ExSearchHashTable(IN PHASH_TABLE HashTable
,
294 ExpLockHashTable(HashTable
, &OldIrql
);
295 Status
= ExpSearchHashTable(HashTable
, Key
, KeyLength
, Value
);
296 ExpUnlockHashTable(HashTable
, &OldIrql
);
303 * Remove a value associated with a given key from a hash table.
306 ExRemoveHashTable(IN PHASH_TABLE HashTable
,
314 ExpLockHashTable(HashTable
, &OldIrql
);
315 Status
= ExpRemoveHashTable(HashTable
, Key
, KeyLength
, Value
);
316 ExpUnlockHashTable(HashTable
, &OldIrql
);