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