Import from 1.9a8 tarball
[mozilla-nss.git] / security / nss / lib / base / hash.c
blob9ea796e81eac11a36fba87e041093cb435978532
1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
12 * License.
14 * The Original Code is the Netscape security libraries.
16 * The Initial Developer of the Original Code is
17 * Netscape Communications Corporation.
18 * Portions created by the Initial Developer are Copyright (C) 1994-2000
19 * the Initial Developer. All Rights Reserved.
21 * Contributor(s):
23 * Alternatively, the contents of this file may be used under the terms of
24 * either the GNU General Public License Version 2 or later (the "GPL"), or
25 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
26 * in which case the provisions of the GPL or the LGPL are applicable instead
27 * of those above. If you wish to allow use of your version of this file only
28 * under the terms of either the GPL or the LGPL, and not to allow others to
29 * use your version of this file under the terms of the MPL, indicate your
30 * decision by deleting the provisions above and replace them with the notice
31 * and other provisions required by the GPL or the LGPL. If you do not delete
32 * the provisions above, a recipient may use your version of this file under
33 * the terms of any one of the MPL, the GPL or the LGPL.
35 * ***** END LICENSE BLOCK ***** */
37 #ifdef DEBUG
38 static const char CVS_ID[] = "@(#) $RCSfile: hash.c,v $ $Revision: 1.9 $ $Date: 2005/01/20 02:25:45 $";
39 #endif /* DEBUG */
42 * hash.c
44 * This is merely a couple wrappers around NSPR's PLHashTable, using
45 * the identity hash and arena-aware allocators.
46 * This is a copy of ckfw/hash.c, with modifications to use NSS types
47 * (not Cryptoki types). Would like for this to be a single implementation,
48 * but doesn't seem like it will work.
51 #ifndef BASE_H
52 #include "base.h"
53 #endif /* BASE_H */
56 * nssHash
58 * nssHash_Create
59 * nssHash_Destroy
60 * nssHash_Add
61 * nssHash_Remove
62 * nssHash_Count
63 * nssHash_Exists
64 * nssHash_Lookup
65 * nssHash_Iterate
68 struct nssHashStr {
69 NSSArena *arena;
70 PRBool i_alloced_arena;
71 PRLock *mutex;
74 * The invariant that mutex protects is:
75 * The count accurately reflects the hashtable state.
78 PLHashTable *plHashTable;
79 PRUint32 count;
82 static PLHashNumber
83 nss_identity_hash
85 const void *key
88 PRUint32 i = (PRUint32)key;
89 PR_ASSERT(sizeof(PLHashNumber) == sizeof(PRUint32));
90 return (PLHashNumber)i;
93 static PLHashNumber
94 nss_item_hash
96 const void *key
99 unsigned int i;
100 PLHashNumber h;
101 NSSItem *it = (NSSItem *)key;
102 h = 0;
103 for (i=0; i<it->size; i++)
104 h = (h >> 28) ^ (h << 4) ^ ((unsigned char *)it->data)[i];
105 return h;
108 static int
109 nss_compare_items(const void *v1, const void *v2)
111 PRStatus ignore;
112 return (int)nssItem_Equal((NSSItem *)v1, (NSSItem *)v2, &ignore);
116 * nssHash_create
119 NSS_IMPLEMENT nssHash *
120 nssHash_Create
122 NSSArena *arenaOpt,
123 PRUint32 numBuckets,
124 PLHashFunction keyHash,
125 PLHashComparator keyCompare,
126 PLHashComparator valueCompare
129 nssHash *rv;
130 NSSArena *arena;
131 PRBool i_alloced;
133 #ifdef NSSDEBUG
134 if( arenaOpt && PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
135 nss_SetError(NSS_ERROR_INVALID_POINTER);
136 return (nssHash *)NULL;
138 #endif /* NSSDEBUG */
140 if (arenaOpt) {
141 arena = arenaOpt;
142 i_alloced = PR_FALSE;
143 } else {
144 arena = nssArena_Create();
145 i_alloced = PR_TRUE;
148 rv = nss_ZNEW(arena, nssHash);
149 if( (nssHash *)NULL == rv ) {
150 goto loser;
153 rv->mutex = PZ_NewLock(nssILockOther);
154 if( (PZLock *)NULL == rv->mutex ) {
155 goto loser;
158 rv->plHashTable = PL_NewHashTable(numBuckets,
159 keyHash, keyCompare, valueCompare,
160 &nssArenaHashAllocOps, arena);
161 if( (PLHashTable *)NULL == rv->plHashTable ) {
162 (void)PZ_DestroyLock(rv->mutex);
163 goto loser;
166 rv->count = 0;
167 rv->arena = arena;
168 rv->i_alloced_arena = i_alloced;
170 return rv;
171 loser:
172 (void)nss_ZFreeIf(rv);
173 return (nssHash *)NULL;
177 * nssHash_CreatePointer
180 NSS_IMPLEMENT nssHash *
181 nssHash_CreatePointer
183 NSSArena *arenaOpt,
184 PRUint32 numBuckets
187 return nssHash_Create(arenaOpt, numBuckets,
188 nss_identity_hash, PL_CompareValues, PL_CompareValues);
192 * nssHash_CreateString
195 NSS_IMPLEMENT nssHash *
196 nssHash_CreateString
198 NSSArena *arenaOpt,
199 PRUint32 numBuckets
202 return nssHash_Create(arenaOpt, numBuckets,
203 PL_HashString, PL_CompareStrings, PL_CompareStrings);
207 * nssHash_CreateItem
210 NSS_IMPLEMENT nssHash *
211 nssHash_CreateItem
213 NSSArena *arenaOpt,
214 PRUint32 numBuckets
217 return nssHash_Create(arenaOpt, numBuckets,
218 nss_item_hash, nss_compare_items, PL_CompareValues);
222 * nssHash_Destroy
225 NSS_IMPLEMENT void
226 nssHash_Destroy
228 nssHash *hash
231 (void)PZ_DestroyLock(hash->mutex);
232 PL_HashTableDestroy(hash->plHashTable);
233 if (hash->i_alloced_arena) {
234 nssArena_Destroy(hash->arena);
235 } else {
236 nss_ZFreeIf(hash);
241 * nssHash_Add
244 NSS_IMPLEMENT PRStatus
245 nssHash_Add
247 nssHash *hash,
248 const void *key,
249 const void *value
252 PRStatus error = PR_FAILURE;
253 PLHashEntry *he;
255 PZ_Lock(hash->mutex);
257 he = PL_HashTableAdd(hash->plHashTable, key, (void *)value);
258 if( (PLHashEntry *)NULL == he ) {
259 nss_SetError(NSS_ERROR_NO_MEMORY);
260 } else if (he->value != value) {
261 nss_SetError(NSS_ERROR_HASH_COLLISION);
262 } else {
263 hash->count++;
264 error = PR_SUCCESS;
267 (void)PZ_Unlock(hash->mutex);
269 return error;
273 * nssHash_Remove
276 NSS_IMPLEMENT void
277 nssHash_Remove
279 nssHash *hash,
280 const void *it
283 PRBool found;
285 PZ_Lock(hash->mutex);
287 found = PL_HashTableRemove(hash->plHashTable, it);
288 if( found ) {
289 hash->count--;
292 (void)PZ_Unlock(hash->mutex);
293 return;
297 * nssHash_Count
300 NSS_IMPLEMENT PRUint32
301 nssHash_Count
303 nssHash *hash
306 PRUint32 count;
308 PZ_Lock(hash->mutex);
310 count = hash->count;
312 (void)PZ_Unlock(hash->mutex);
314 return count;
318 * nssHash_Exists
321 NSS_IMPLEMENT PRBool
322 nssHash_Exists
324 nssHash *hash,
325 const void *it
328 void *value;
330 PZ_Lock(hash->mutex);
332 value = PL_HashTableLookup(hash->plHashTable, it);
334 (void)PZ_Unlock(hash->mutex);
336 if( (void *)NULL == value ) {
337 return PR_FALSE;
338 } else {
339 return PR_TRUE;
344 * nssHash_Lookup
347 NSS_IMPLEMENT void *
348 nssHash_Lookup
350 nssHash *hash,
351 const void *it
354 void *rv;
356 PZ_Lock(hash->mutex);
358 rv = PL_HashTableLookup(hash->plHashTable, it);
360 (void)PZ_Unlock(hash->mutex);
362 return rv;
365 struct arg_str {
366 nssHashIterator fcn;
367 void *closure;
370 static PRIntn
371 nss_hash_enumerator
373 PLHashEntry *he,
374 PRIntn index,
375 void *arg
378 struct arg_str *as = (struct arg_str *)arg;
379 as->fcn(he->key, he->value, as->closure);
380 return HT_ENUMERATE_NEXT;
384 * nssHash_Iterate
386 * NOTE that the iteration function will be called with the hashtable locked.
388 NSS_IMPLEMENT void
389 nssHash_Iterate
391 nssHash *hash,
392 nssHashIterator fcn,
393 void *closure
396 struct arg_str as;
397 as.fcn = fcn;
398 as.closure = closure;
400 PZ_Lock(hash->mutex);
402 PL_HashTableEnumerateEntries(hash->plHashTable, nss_hash_enumerator, &as);
404 (void)PZ_Unlock(hash->mutex);
406 return;