PageRenderTime 39ms CodeModel.GetById 9ms app.highlight 24ms RepoModel.GetById 2ms app.codeStats 0ms

/security/nss/lib/base/hash.c

http://github.com/zpao/v8monkey
C | 409 lines | 250 code | 54 blank | 105 comment | 25 complexity | 795f7c2d1556ad80035223d32b1ab103 MD5 | raw file
  1/* ***** BEGIN LICENSE BLOCK *****
  2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
  3 *
  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/
  8 *
  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.
 13 *
 14 * The Original Code is the Netscape security libraries.
 15 *
 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.
 20 *
 21 * Contributor(s):
 22 *
 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.
 34 *
 35 * ***** END LICENSE BLOCK ***** */
 36
 37#ifdef DEBUG
 38static const char CVS_ID[] = "@(#) $RCSfile: hash.c,v $ $Revision: 1.11 $ $Date: 2008/02/03 01:59:48 $";
 39#endif /* DEBUG */
 40
 41/*
 42 * hash.c
 43 *
 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.
 49 */
 50
 51#ifndef BASE_H
 52#include "base.h"
 53#endif /* BASE_H */
 54
 55#include "prbit.h"
 56
 57/*
 58 * nssHash
 59 *
 60 *  nssHash_Create
 61 *  nssHash_Destroy
 62 *  nssHash_Add
 63 *  nssHash_Remove
 64 *  nssHash_Count
 65 *  nssHash_Exists
 66 *  nssHash_Lookup
 67 *  nssHash_Iterate
 68 */
 69
 70struct nssHashStr {
 71  NSSArena *arena;
 72  PRBool i_alloced_arena;
 73  PRLock *mutex;
 74
 75  /*
 76   * The invariant that mutex protects is:
 77   *   The count accurately reflects the hashtable state.
 78   */
 79
 80  PLHashTable *plHashTable;
 81  PRUint32 count;
 82};
 83
 84static PLHashNumber
 85nss_identity_hash
 86(
 87  const void *key
 88)
 89{
 90  PRUint32 i = (PRUint32)key;
 91  PR_ASSERT(sizeof(PLHashNumber) == sizeof(PRUint32));
 92  return (PLHashNumber)i;
 93}
 94
 95static PLHashNumber
 96nss_item_hash
 97(
 98  const void *key
 99)
100{
101  unsigned int i;
102  PLHashNumber h;
103  NSSItem *it = (NSSItem *)key;
104  h = 0;
105  for (i=0; i<it->size; i++)
106    h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)it->data)[i];
107  return h;
108}
109
110static int
111nss_compare_items(const void *v1, const void *v2)
112{
113  PRStatus ignore;
114  return (int)nssItem_Equal((NSSItem *)v1, (NSSItem *)v2, &ignore);
115}
116
117/*
118 * nssHash_create
119 *
120 */
121NSS_IMPLEMENT nssHash *
122nssHash_Create
123(
124  NSSArena *arenaOpt,
125  PRUint32 numBuckets,
126  PLHashFunction keyHash,
127  PLHashComparator keyCompare,
128  PLHashComparator valueCompare
129)
130{
131  nssHash *rv;
132  NSSArena *arena;
133  PRBool i_alloced;
134
135#ifdef NSSDEBUG
136  if( arenaOpt && PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
137    nss_SetError(NSS_ERROR_INVALID_POINTER);
138    return (nssHash *)NULL;
139  }
140#endif /* NSSDEBUG */
141
142  if (arenaOpt) {
143    arena = arenaOpt;
144    i_alloced = PR_FALSE;
145  } else {
146    arena = nssArena_Create();
147    i_alloced = PR_TRUE;
148  }
149
150  rv = nss_ZNEW(arena, nssHash);
151  if( (nssHash *)NULL == rv ) {
152    goto loser;
153  }
154
155  rv->mutex = PZ_NewLock(nssILockOther);
156  if( (PZLock *)NULL == rv->mutex ) {
157    goto loser;
158  }
159
160  rv->plHashTable = PL_NewHashTable(numBuckets, 
161                                    keyHash, keyCompare, valueCompare,
162                                    &nssArenaHashAllocOps, arena);
163  if( (PLHashTable *)NULL == rv->plHashTable ) {
164    (void)PZ_DestroyLock(rv->mutex);
165    goto loser;
166  }
167
168  rv->count = 0;
169  rv->arena = arena;
170  rv->i_alloced_arena = i_alloced;
171
172  return rv;
173loser:
174  (void)nss_ZFreeIf(rv);
175  return (nssHash *)NULL;
176}
177
178/*
179 * nssHash_CreatePointer
180 *
181 */
182NSS_IMPLEMENT nssHash *
183nssHash_CreatePointer
184(
185  NSSArena *arenaOpt,
186  PRUint32 numBuckets
187)
188{
189  return nssHash_Create(arenaOpt, numBuckets, 
190                        nss_identity_hash, PL_CompareValues, PL_CompareValues);
191}
192
193/*
194 * nssHash_CreateString
195 *
196 */
197NSS_IMPLEMENT nssHash *
198nssHash_CreateString
199(
200  NSSArena *arenaOpt,
201  PRUint32 numBuckets
202)
203{
204  return nssHash_Create(arenaOpt, numBuckets, 
205                        PL_HashString, PL_CompareStrings, PL_CompareStrings);
206}
207
208/*
209 * nssHash_CreateItem
210 *
211 */
212NSS_IMPLEMENT nssHash *
213nssHash_CreateItem
214(
215  NSSArena *arenaOpt,
216  PRUint32 numBuckets
217)
218{
219  return nssHash_Create(arenaOpt, numBuckets, 
220                        nss_item_hash, nss_compare_items, PL_CompareValues);
221}
222
223/*
224 * nssHash_Destroy
225 *
226 */
227NSS_IMPLEMENT void
228nssHash_Destroy
229(
230  nssHash *hash
231)
232{
233  (void)PZ_DestroyLock(hash->mutex);
234  PL_HashTableDestroy(hash->plHashTable);
235  if (hash->i_alloced_arena) {
236    nssArena_Destroy(hash->arena);
237  } else {
238    nss_ZFreeIf(hash);
239  }
240}
241
242/*
243 * nssHash_Add
244 *
245 */
246NSS_IMPLEMENT PRStatus
247nssHash_Add
248(
249  nssHash *hash,
250  const void *key,
251  const void *value
252)
253{
254  PRStatus error = PR_FAILURE;
255  PLHashEntry *he;
256
257  PZ_Lock(hash->mutex);
258  
259  he = PL_HashTableAdd(hash->plHashTable, key, (void *)value);
260  if( (PLHashEntry *)NULL == he ) {
261    nss_SetError(NSS_ERROR_NO_MEMORY);
262  } else if (he->value != value) {
263    nss_SetError(NSS_ERROR_HASH_COLLISION);
264  } else {
265    hash->count++;
266    error = PR_SUCCESS;
267  }
268
269  (void)PZ_Unlock(hash->mutex);
270
271  return error;
272}
273
274/*
275 * nssHash_Remove
276 *
277 */
278NSS_IMPLEMENT void
279nssHash_Remove
280(
281  nssHash *hash,
282  const void *it
283)
284{
285  PRBool found;
286
287  PZ_Lock(hash->mutex);
288
289  found = PL_HashTableRemove(hash->plHashTable, it);
290  if( found ) {
291    hash->count--;
292  }
293
294  (void)PZ_Unlock(hash->mutex);
295  return;
296}
297
298/*
299 * nssHash_Count
300 *
301 */
302NSS_IMPLEMENT PRUint32
303nssHash_Count
304(
305  nssHash *hash
306)
307{
308  PRUint32 count;
309
310  PZ_Lock(hash->mutex);
311
312  count = hash->count;
313
314  (void)PZ_Unlock(hash->mutex);
315
316  return count;
317}
318
319/*
320 * nssHash_Exists
321 *
322 */
323NSS_IMPLEMENT PRBool
324nssHash_Exists
325(
326  nssHash *hash,
327  const void *it
328)
329{
330  void *value;
331
332  PZ_Lock(hash->mutex);
333
334  value = PL_HashTableLookup(hash->plHashTable, it);
335
336  (void)PZ_Unlock(hash->mutex);
337
338  if( (void *)NULL == value ) {
339    return PR_FALSE;
340  } else {
341    return PR_TRUE;
342  }
343}
344
345/*
346 * nssHash_Lookup
347 *
348 */
349NSS_IMPLEMENT void *
350nssHash_Lookup
351(
352  nssHash *hash,
353  const void *it
354)
355{
356  void *rv;
357
358  PZ_Lock(hash->mutex);
359
360  rv = PL_HashTableLookup(hash->plHashTable, it);
361
362  (void)PZ_Unlock(hash->mutex);
363
364  return rv;
365}
366
367struct arg_str {
368  nssHashIterator fcn;
369  void *closure;
370};
371
372static PRIntn
373nss_hash_enumerator
374(
375  PLHashEntry *he,
376  PRIntn index,
377  void *arg
378)
379{
380  struct arg_str *as = (struct arg_str *)arg;
381  as->fcn(he->key, he->value, as->closure);
382  return HT_ENUMERATE_NEXT;
383}
384
385/*
386 * nssHash_Iterate
387 *
388 * NOTE that the iteration function will be called with the hashtable locked.
389 */
390NSS_IMPLEMENT void
391nssHash_Iterate
392(
393  nssHash *hash,
394  nssHashIterator fcn,
395  void *closure
396)
397{
398  struct arg_str as;
399  as.fcn = fcn;
400  as.closure = closure;
401
402  PZ_Lock(hash->mutex);
403
404  PL_HashTableEnumerateEntries(hash->plHashTable, nss_hash_enumerator, &as);
405
406  (void)PZ_Unlock(hash->mutex);
407
408  return;
409}