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 /* | |
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 } | |
OLD | NEW |