/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. #ifdef DEBUG
  37. static const char CVS_ID[] = "@(#) $RCSfile: hash.c,v $ $Revision: 1.11 $ $Date: 2008/02/03 01:59:48 $";
  38. #endif /* DEBUG */
  39. /*
  40. * hash.c
  41. *
  42. * This is merely a couple wrappers around NSPR's PLHashTable, using
  43. * the identity hash and arena-aware allocators.
  44. * This is a copy of ckfw/hash.c, with modifications to use NSS types
  45. * (not Cryptoki types). Would like for this to be a single implementation,
  46. * but doesn't seem like it will work.
  47. */
  48. #ifndef BASE_H
  49. #include "base.h"
  50. #endif /* BASE_H */
  51. #include "prbit.h"
  52. /*
  53. * nssHash
  54. *
  55. * nssHash_Create
  56. * nssHash_Destroy
  57. * nssHash_Add
  58. * nssHash_Remove
  59. * nssHash_Count
  60. * nssHash_Exists
  61. * nssHash_Lookup
  62. * nssHash_Iterate
  63. */
  64. struct nssHashStr {
  65. NSSArena *arena;
  66. PRBool i_alloced_arena;
  67. PRLock *mutex;
  68. /*
  69. * The invariant that mutex protects is:
  70. * The count accurately reflects the hashtable state.
  71. */
  72. PLHashTable *plHashTable;
  73. PRUint32 count;
  74. };
  75. static PLHashNumber
  76. nss_identity_hash
  77. (
  78. const void *key
  79. )
  80. {
  81. PRUint32 i = (PRUint32)key;
  82. PR_ASSERT(sizeof(PLHashNumber) == sizeof(PRUint32));
  83. return (PLHashNumber)i;
  84. }
  85. static PLHashNumber
  86. nss_item_hash
  87. (
  88. const void *key
  89. )
  90. {
  91. unsigned int i;
  92. PLHashNumber h;
  93. NSSItem *it = (NSSItem *)key;
  94. h = 0;
  95. for (i=0; i<it->size; i++)
  96. h = PR_ROTATE_LEFT32(h, 4) ^ ((unsigned char *)it->data)[i];
  97. return h;
  98. }
  99. static int
  100. nss_compare_items(const void *v1, const void *v2)
  101. {
  102. PRStatus ignore;
  103. return (int)nssItem_Equal((NSSItem *)v1, (NSSItem *)v2, &ignore);
  104. }
  105. /*
  106. * nssHash_create
  107. *
  108. */
  109. NSS_IMPLEMENT nssHash *
  110. nssHash_Create
  111. (
  112. NSSArena *arenaOpt,
  113. PRUint32 numBuckets,
  114. PLHashFunction keyHash,
  115. PLHashComparator keyCompare,
  116. PLHashComparator valueCompare
  117. )
  118. {
  119. nssHash *rv;
  120. NSSArena *arena;
  121. PRBool i_alloced;
  122. #ifdef NSSDEBUG
  123. if( arenaOpt && PR_SUCCESS != nssArena_verifyPointer(arenaOpt) ) {
  124. nss_SetError(NSS_ERROR_INVALID_POINTER);
  125. return (nssHash *)NULL;
  126. }
  127. #endif /* NSSDEBUG */
  128. if (arenaOpt) {
  129. arena = arenaOpt;
  130. i_alloced = PR_FALSE;
  131. } else {
  132. arena = nssArena_Create();
  133. i_alloced = PR_TRUE;
  134. }
  135. rv = nss_ZNEW(arena, nssHash);
  136. if( (nssHash *)NULL == rv ) {
  137. goto loser;
  138. }
  139. rv->mutex = PZ_NewLock(nssILockOther);
  140. if( (PZLock *)NULL == rv->mutex ) {
  141. goto loser;
  142. }
  143. rv->plHashTable = PL_NewHashTable(numBuckets,
  144. keyHash, keyCompare, valueCompare,
  145. &nssArenaHashAllocOps, arena);
  146. if( (PLHashTable *)NULL == rv->plHashTable ) {
  147. (void)PZ_DestroyLock(rv->mutex);
  148. goto loser;
  149. }
  150. rv->count = 0;
  151. rv->arena = arena;
  152. rv->i_alloced_arena = i_alloced;
  153. return rv;
  154. loser:
  155. (void)nss_ZFreeIf(rv);
  156. return (nssHash *)NULL;
  157. }
  158. /*
  159. * nssHash_CreatePointer
  160. *
  161. */
  162. NSS_IMPLEMENT nssHash *
  163. nssHash_CreatePointer
  164. (
  165. NSSArena *arenaOpt,
  166. PRUint32 numBuckets
  167. )
  168. {
  169. return nssHash_Create(arenaOpt, numBuckets,
  170. nss_identity_hash, PL_CompareValues, PL_CompareValues);
  171. }
  172. /*
  173. * nssHash_CreateString
  174. *
  175. */
  176. NSS_IMPLEMENT nssHash *
  177. nssHash_CreateString
  178. (
  179. NSSArena *arenaOpt,
  180. PRUint32 numBuckets
  181. )
  182. {
  183. return nssHash_Create(arenaOpt, numBuckets,
  184. PL_HashString, PL_CompareStrings, PL_CompareStrings);
  185. }
  186. /*
  187. * nssHash_CreateItem
  188. *
  189. */
  190. NSS_IMPLEMENT nssHash *
  191. nssHash_CreateItem
  192. (
  193. NSSArena *arenaOpt,
  194. PRUint32 numBuckets
  195. )
  196. {
  197. return nssHash_Create(arenaOpt, numBuckets,
  198. nss_item_hash, nss_compare_items, PL_CompareValues);
  199. }
  200. /*
  201. * nssHash_Destroy
  202. *
  203. */
  204. NSS_IMPLEMENT void
  205. nssHash_Destroy
  206. (
  207. nssHash *hash
  208. )
  209. {
  210. (void)PZ_DestroyLock(hash->mutex);
  211. PL_HashTableDestroy(hash->plHashTable);
  212. if (hash->i_alloced_arena) {
  213. nssArena_Destroy(hash->arena);
  214. } else {
  215. nss_ZFreeIf(hash);
  216. }
  217. }
  218. /*
  219. * nssHash_Add
  220. *
  221. */
  222. NSS_IMPLEMENT PRStatus
  223. nssHash_Add
  224. (
  225. nssHash *hash,
  226. const void *key,
  227. const void *value
  228. )
  229. {
  230. PRStatus error = PR_FAILURE;
  231. PLHashEntry *he;
  232. PZ_Lock(hash->mutex);
  233. he = PL_HashTableAdd(hash->plHashTable, key, (void *)value);
  234. if( (PLHashEntry *)NULL == he ) {
  235. nss_SetError(NSS_ERROR_NO_MEMORY);
  236. } else if (he->value != value) {
  237. nss_SetError(NSS_ERROR_HASH_COLLISION);
  238. } else {
  239. hash->count++;
  240. error = PR_SUCCESS;
  241. }
  242. (void)PZ_Unlock(hash->mutex);
  243. return error;
  244. }
  245. /*
  246. * nssHash_Remove
  247. *
  248. */
  249. NSS_IMPLEMENT void
  250. nssHash_Remove
  251. (
  252. nssHash *hash,
  253. const void *it
  254. )
  255. {
  256. PRBool found;
  257. PZ_Lock(hash->mutex);
  258. found = PL_HashTableRemove(hash->plHashTable, it);
  259. if( found ) {
  260. hash->count--;
  261. }
  262. (void)PZ_Unlock(hash->mutex);
  263. return;
  264. }
  265. /*
  266. * nssHash_Count
  267. *
  268. */
  269. NSS_IMPLEMENT PRUint32
  270. nssHash_Count
  271. (
  272. nssHash *hash
  273. )
  274. {
  275. PRUint32 count;
  276. PZ_Lock(hash->mutex);
  277. count = hash->count;
  278. (void)PZ_Unlock(hash->mutex);
  279. return count;
  280. }
  281. /*
  282. * nssHash_Exists
  283. *
  284. */
  285. NSS_IMPLEMENT PRBool
  286. nssHash_Exists
  287. (
  288. nssHash *hash,
  289. const void *it
  290. )
  291. {
  292. void *value;
  293. PZ_Lock(hash->mutex);
  294. value = PL_HashTableLookup(hash->plHashTable, it);
  295. (void)PZ_Unlock(hash->mutex);
  296. if( (void *)NULL == value ) {
  297. return PR_FALSE;
  298. } else {
  299. return PR_TRUE;
  300. }
  301. }
  302. /*
  303. * nssHash_Lookup
  304. *
  305. */
  306. NSS_IMPLEMENT void *
  307. nssHash_Lookup
  308. (
  309. nssHash *hash,
  310. const void *it
  311. )
  312. {
  313. void *rv;
  314. PZ_Lock(hash->mutex);
  315. rv = PL_HashTableLookup(hash->plHashTable, it);
  316. (void)PZ_Unlock(hash->mutex);
  317. return rv;
  318. }
  319. struct arg_str {
  320. nssHashIterator fcn;
  321. void *closure;
  322. };
  323. static PRIntn
  324. nss_hash_enumerator
  325. (
  326. PLHashEntry *he,
  327. PRIntn index,
  328. void *arg
  329. )
  330. {
  331. struct arg_str *as = (struct arg_str *)arg;
  332. as->fcn(he->key, he->value, as->closure);
  333. return HT_ENUMERATE_NEXT;
  334. }
  335. /*
  336. * nssHash_Iterate
  337. *
  338. * NOTE that the iteration function will be called with the hashtable locked.
  339. */
  340. NSS_IMPLEMENT void
  341. nssHash_Iterate
  342. (
  343. nssHash *hash,
  344. nssHashIterator fcn,
  345. void *closure
  346. )
  347. {
  348. struct arg_str as;
  349. as.fcn = fcn;
  350. as.closure = closure;
  351. PZ_Lock(hash->mutex);
  352. PL_HashTableEnumerateEntries(hash->plHashTable, nss_hash_enumerator, &as);
  353. (void)PZ_Unlock(hash->mutex);
  354. return;
  355. }