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