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 * pkix_pl_primhash.c | |
6 * | |
7 * Primitive (non-object) Hashtable Functions | |
8 * | |
9 */ | |
10 | |
11 #include "pkix_pl_primhash.h" | |
12 | |
13 /* --Private-Functions---------------------------------------- */ | |
14 | |
15 /* | |
16 * FUNCTION: pkix_pl_KeyComparator_Default | |
17 * DESCRIPTION: | |
18 * | |
19 * Compares the integer pointed to by "firstKey" with the integer pointed to | |
20 * by "secondKey" for equality and stores the Boolean result at "pResult". | |
21 * This default key comparator assumes each key is a PKIX_UInt32, and it | |
22 * simply tests them for equality. | |
23 * | |
24 * PARAMETERS: | |
25 * "firstKey" | |
26 * Address of the first integer key to compare. Must be non-NULL. | |
27 * The EqualsCallback for this Object will be called. | |
28 * "secondKey" | |
29 * Address of the second integer key to compare. Must be non-NULL. | |
30 * "pResult" | |
31 * Address where Boolean will be stored. Must be non-NULL. | |
32 * "plContext" | |
33 * Platform-specific context pointer. | |
34 * THREAD SAFETY: | |
35 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
36 * RETURNS: | |
37 * Returns NULL if the function succeeds. | |
38 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
39 */ | |
40 static PKIX_Error * | |
41 pkix_pl_KeyComparator_Default( | |
42 PKIX_UInt32 *firstKey, | |
43 PKIX_UInt32 *secondKey, | |
44 PKIX_Boolean *pResult, | |
45 void *plContext) | |
46 { | |
47 /* Assume both keys are pointers to PKIX_UInt32 */ | |
48 PKIX_UInt32 firstInt, secondInt; | |
49 | |
50 PKIX_ENTER(HASHTABLE, "pkix_pl_KeyComparator_Default"); | |
51 PKIX_NULLCHECK_THREE(firstKey, secondKey, pResult); | |
52 | |
53 firstInt = *firstKey; | |
54 secondInt = *secondKey; | |
55 | |
56 *pResult = (firstInt == secondInt)?PKIX_TRUE:PKIX_FALSE; | |
57 | |
58 PKIX_RETURN(HASHTABLE); | |
59 } | |
60 | |
61 | |
62 /* | |
63 * FUNCTION: pkix_pl_PrimHashTable_Create | |
64 * DESCRIPTION: | |
65 * | |
66 * Creates a new PrimHashtable object with a number of buckets equal to | |
67 * "numBuckets" and stores the result at "pResult". | |
68 * | |
69 * PARAMETERS: | |
70 * "numBuckets" | |
71 * The number of hash table buckets. Must be non-zero. | |
72 * "pResult" | |
73 * Address where PrimHashTable pointer will be stored. Must be non-NULL. | |
74 * "plContext" | |
75 * Platform-specific context pointer. | |
76 * THREAD SAFETY: | |
77 * Thread Safe (see Thread Safety Definitions in Programmer's Guide) | |
78 * RETURNS: | |
79 * Returns NULL if the function succeeds. | |
80 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
81 */ | |
82 PKIX_Error * | |
83 pkix_pl_PrimHashTable_Create( | |
84 PKIX_UInt32 numBuckets, | |
85 pkix_pl_PrimHashTable **pResult, | |
86 void *plContext) | |
87 { | |
88 pkix_pl_PrimHashTable *primHashTable = NULL; | |
89 PKIX_UInt32 i; | |
90 | |
91 PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Create"); | |
92 PKIX_NULLCHECK_ONE(pResult); | |
93 | |
94 if (numBuckets == 0) { | |
95 PKIX_ERROR(PKIX_NUMBUCKETSEQUALSZERO); | |
96 } | |
97 | |
98 /* Allocate a new hashtable */ | |
99 PKIX_CHECK(PKIX_PL_Malloc | |
100 (sizeof (pkix_pl_PrimHashTable), | |
101 (void **)&primHashTable, | |
102 plContext), | |
103 PKIX_MALLOCFAILED); | |
104 | |
105 primHashTable->size = numBuckets; | |
106 | |
107 /* Allocate space for the buckets */ | |
108 PKIX_CHECK(PKIX_PL_Malloc | |
109 (numBuckets * sizeof (pkix_pl_HT_Elem*), | |
110 (void **)&primHashTable->buckets, | |
111 plContext), | |
112 PKIX_MALLOCFAILED); | |
113 | |
114 for (i = 0; i < numBuckets; i++) { | |
115 primHashTable->buckets[i] = NULL; | |
116 } | |
117 | |
118 *pResult = primHashTable; | |
119 | |
120 cleanup: | |
121 | |
122 if (PKIX_ERROR_RECEIVED){ | |
123 PKIX_FREE(primHashTable); | |
124 } | |
125 | |
126 PKIX_RETURN(HASHTABLE); | |
127 } | |
128 | |
129 /* | |
130 * FUNCTION: pkix_pl_PrimHashTable_Add | |
131 * DESCRIPTION: | |
132 * | |
133 * Adds the value pointed to by "value" to the PrimHashTable pointed to by | |
134 * "ht" using the key pointed to by "key" and the hashCode value equal to | |
135 * "hashCode", using the function pointed to by "keyComp" to compare keys. | |
136 * Assumes the key is either a PKIX_UInt32 or a PKIX_PL_Object. If the value | |
137 * already exists in the hashtable, this function returns a non-fatal error. | |
138 * | |
139 * PARAMETERS: | |
140 * "ht" | |
141 * Address of PrimHashtable to insert into. Must be non-NULL. | |
142 * "key" | |
143 * Address of key. Typically a PKIX_UInt32 or PKIX_PL_Object. | |
144 * Must be non-NULL. | |
145 * "value" | |
146 * Address of Object to be added to PrimHashtable. Must be non-NULL. | |
147 * "hashCode" | |
148 * Hashcode value of the key. | |
149 * "keyComp" | |
150 * Address of function used to determine if two keys are equal. | |
151 * If NULL, pkix_pl_KeyComparator_Default is used. | |
152 * "plContext" | |
153 * Platform-specific context pointer. | |
154 * THREAD SAFETY: | |
155 * Not Thread Safe - assumes exclusive access to "ht" | |
156 * (see Thread Safety Definitions in Programmer's Guide) | |
157 * RETURNS: | |
158 * Returns NULL if the function succeeds. | |
159 * Returns a HashTable Error if the function fails in a non-fatal way. | |
160 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
161 */ | |
162 PKIX_Error * | |
163 pkix_pl_PrimHashTable_Add( | |
164 pkix_pl_PrimHashTable *ht, | |
165 void *key, | |
166 void *value, | |
167 PKIX_UInt32 hashCode, | |
168 PKIX_PL_EqualsCallback keyComp, | |
169 void *plContext) | |
170 { | |
171 pkix_pl_HT_Elem **elemPtr = NULL; | |
172 pkix_pl_HT_Elem *element = NULL; | |
173 PKIX_Boolean compResult = PKIX_FALSE; | |
174 | |
175 PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Add"); | |
176 PKIX_NULLCHECK_THREE(ht, key, value); | |
177 | |
178 for (elemPtr = &((ht->buckets)[hashCode%ht->size]), element = *elemPtr; | |
179 element != NULL; elemPtr = &(element->next), element = *elemPtr) { | |
180 | |
181 if (element->hashCode != hashCode){ | |
182 /* no possibility of a match */ | |
183 continue; | |
184 } | |
185 | |
186 if (keyComp == NULL){ | |
187 PKIX_CHECK(pkix_pl_KeyComparator_Default | |
188 ((PKIX_UInt32 *)key, | |
189 (PKIX_UInt32 *)(element->key), | |
190 &compResult, | |
191 plContext), | |
192 PKIX_COULDNOTTESTWHETHERKEYSEQUAL); | |
193 } else { | |
194 PKIX_CHECK(keyComp | |
195 ((PKIX_PL_Object *)key, | |
196 (PKIX_PL_Object *)(element->key), | |
197 &compResult, | |
198 plContext), | |
199 PKIX_COULDNOTTESTWHETHERKEYSEQUAL); | |
200 } | |
201 | |
202 if ((element->hashCode == hashCode) && | |
203 (compResult == PKIX_TRUE)){ | |
204 /* Same key already exists in the table */ | |
205 PKIX_ERROR(PKIX_ATTEMPTTOADDDUPLICATEKEY); | |
206 } | |
207 } | |
208 | |
209 /* Next Element should be NULL at this point */ | |
210 if (element != NULL) { | |
211 PKIX_ERROR(PKIX_ERRORTRAVERSINGBUCKET); | |
212 } | |
213 | |
214 /* Create a new HT_Elem */ | |
215 PKIX_CHECK(PKIX_PL_Malloc | |
216 (sizeof (pkix_pl_HT_Elem), (void **)elemPtr, plContext), | |
217 PKIX_MALLOCFAILED); | |
218 | |
219 element = *elemPtr; | |
220 | |
221 element->key = key; | |
222 element->value = value; | |
223 element->hashCode = hashCode; | |
224 element->next = NULL; | |
225 | |
226 cleanup: | |
227 | |
228 PKIX_RETURN(HASHTABLE); | |
229 } | |
230 | |
231 /* | |
232 * FUNCTION: pkix_pl_PrimHashTable_Remove | |
233 * DESCRIPTION: | |
234 * | |
235 * Removes any objects with the key pointed to by "key" and hashCode value | |
236 * equal to "hashCode" from the PrimHashtable pointed to by "ht", using the | |
237 * function pointed to by "keyComp" to compare keys, and stores the object's | |
238 * value at "pResult". Assumes "key" is a PKIX_UInt32 or a PKIX_PL_Object. | |
239 * This function sets "pResult" to NULL if the key is not in the hashtable. | |
240 * | |
241 * PARAMETERS: | |
242 * "ht" | |
243 * Address of PrimHashtable to remove object. Must be non-NULL. | |
244 * "key" | |
245 * Address of key for lookup. Typically a PKIX_UInt32 or PKIX_PL_Object. | |
246 * Must be non-NULL. | |
247 * "value" | |
248 * Address of Object to be added to PrimHashtable. Must be non-NULL. | |
249 * "hashCode" | |
250 * Hashcode value of the key. | |
251 * "keyComp" | |
252 * Address of function used to determine if two keys are equal. | |
253 * If NULL, pkix_pl_KeyComparator_Default is used. | |
254 * "pResult" | |
255 * Address where value will be stored. Must be non-NULL. | |
256 * "plContext" | |
257 * Platform-specific context pointer. | |
258 * THREAD SAFETY: | |
259 * Not Thread Safe - assumes exclusive access to "ht" | |
260 * (see Thread Safety Definitions in Programmer's Guide) | |
261 * RETURNS: | |
262 * Returns NULL if the function succeeds. | |
263 * Returns a HashTable Error if the function fails in a non-fatal way. | |
264 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
265 */ | |
266 PKIX_Error * | |
267 pkix_pl_PrimHashTable_Remove( | |
268 pkix_pl_PrimHashTable *ht, | |
269 void *key, | |
270 PKIX_UInt32 hashCode, | |
271 PKIX_PL_EqualsCallback keyComp, | |
272 void **pKey, | |
273 void **pValue, | |
274 void *plContext) | |
275 { | |
276 pkix_pl_HT_Elem *element = NULL; | |
277 pkix_pl_HT_Elem *prior = NULL; | |
278 PKIX_Boolean compResult; | |
279 | |
280 PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Remove"); | |
281 PKIX_NULLCHECK_FOUR(ht, key, pKey, pValue); | |
282 | |
283 *pKey = NULL; | |
284 *pValue = NULL; | |
285 | |
286 for (element = ht->buckets[hashCode%ht->size], prior = element; | |
287 (element != NULL); | |
288 prior = element, element = element->next) { | |
289 | |
290 if (element->hashCode != hashCode){ | |
291 /* no possibility of a match */ | |
292 continue; | |
293 } | |
294 | |
295 if (keyComp == NULL){ | |
296 PKIX_CHECK(pkix_pl_KeyComparator_Default | |
297 ((PKIX_UInt32 *)key, | |
298 (PKIX_UInt32 *)(element->key), | |
299 &compResult, | |
300 plContext), | |
301 PKIX_COULDNOTTESTWHETHERKEYSEQUAL); | |
302 } else { | |
303 PKIX_CHECK(keyComp | |
304 ((PKIX_PL_Object *)key, | |
305 (PKIX_PL_Object *)(element->key), | |
306 &compResult, | |
307 plContext), | |
308 PKIX_COULDNOTTESTWHETHERKEYSEQUAL); | |
309 } | |
310 | |
311 if ((element->hashCode == hashCode) && | |
312 (compResult == PKIX_TRUE)){ | |
313 if (element != prior) { | |
314 prior->next = element->next; | |
315 } else { | |
316 ht->buckets[hashCode%ht->size] = element->next; | |
317 } | |
318 *pKey = element->key; | |
319 *pValue = element->value; | |
320 element->key = NULL; | |
321 element->value = NULL; | |
322 element->next = NULL; | |
323 PKIX_FREE(element); | |
324 goto cleanup; | |
325 } | |
326 } | |
327 | |
328 cleanup: | |
329 | |
330 PKIX_RETURN(HASHTABLE); | |
331 } | |
332 | |
333 | |
334 /* | |
335 * FUNCTION: pkix_pl_HashTableLookup | |
336 * DESCRIPTION: | |
337 * | |
338 * Looks up object using the key pointed to by "key" and hashCode value | |
339 * equal to "hashCode" from the PrimHashtable pointed to by "ht", using the | |
340 * function pointed to by "keyComp" to compare keys, and stores the object's | |
341 * value at "pResult". Assumes "key" is a PKIX_UInt32 or a PKIX_PL_Object. | |
342 * This function sets "pResult" to NULL if the key is not in the hashtable. | |
343 * | |
344 * PARAMETERS: | |
345 * "ht" | |
346 * Address of PrimHashtable to lookup object from. Must be non-NULL. | |
347 * "key" | |
348 * Address of key for lookup. Typically a PKIX_UInt32 or PKIX_PL_Object. | |
349 * Must be non-NULL. | |
350 * "keyComp" | |
351 * Address of function used to determine if two keys are equal. | |
352 * If NULL, pkix_pl_KeyComparator_Default is used. | |
353 * "hashCode" | |
354 * Hashcode value of the key. | |
355 * "pResult" | |
356 * Address where value will be stored. Must be non-NULL. | |
357 * "plContext" | |
358 * Platform-specific context pointer. | |
359 * THREAD SAFETY: | |
360 * Conditionally Thread Safe | |
361 * (see Thread Safety Definitions in Programmer's Guide) | |
362 * RETURNS: | |
363 * Returns NULL if the function succeeds. | |
364 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
365 */ | |
366 PKIX_Error * | |
367 pkix_pl_PrimHashTable_Lookup( | |
368 pkix_pl_PrimHashTable *ht, | |
369 void *key, | |
370 PKIX_UInt32 hashCode, | |
371 PKIX_PL_EqualsCallback keyComp, | |
372 void **pResult, | |
373 void *plContext) | |
374 { | |
375 pkix_pl_HT_Elem *element = NULL; | |
376 PKIX_Boolean compResult = PKIX_FALSE; | |
377 | |
378 PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Lookup"); | |
379 PKIX_NULLCHECK_THREE(ht, key, pResult); | |
380 | |
381 *pResult = NULL; | |
382 | |
383 for (element = (ht->buckets)[hashCode%ht->size]; | |
384 (element != NULL) && (*pResult == NULL); | |
385 element = element->next) { | |
386 | |
387 if (element->hashCode != hashCode){ | |
388 /* no possibility of a match */ | |
389 continue; | |
390 } | |
391 | |
392 if (keyComp == NULL){ | |
393 PKIX_CHECK(pkix_pl_KeyComparator_Default | |
394 ((PKIX_UInt32 *)key, | |
395 (PKIX_UInt32 *)(element->key), | |
396 &compResult, | |
397 plContext), | |
398 PKIX_COULDNOTTESTWHETHERKEYSEQUAL); | |
399 } else { | |
400 pkixErrorResult = | |
401 keyComp((PKIX_PL_Object *)key, | |
402 (PKIX_PL_Object *)(element->key), | |
403 &compResult, | |
404 plContext); | |
405 if (pkixErrorResult) { | |
406 pkixErrorClass = PKIX_FATAL_ERROR; | |
407 pkixErrorCode = PKIX_COULDNOTTESTWHETHERKEYSEQUAL; | |
408 goto cleanup; | |
409 } | |
410 } | |
411 | |
412 if ((element->hashCode == hashCode) && | |
413 (compResult == PKIX_TRUE)){ | |
414 *pResult = element->value; | |
415 goto cleanup; | |
416 } | |
417 } | |
418 | |
419 /* if we've reached here, specified key doesn't exist in hashtable */ | |
420 *pResult = NULL; | |
421 | |
422 cleanup: | |
423 | |
424 PKIX_RETURN(HASHTABLE); | |
425 } | |
426 | |
427 /* | |
428 * FUNCTION: pkix_pl_PrimHashTable_Destroy | |
429 * | |
430 * Destroys PrimHashTable pointed to by "ht". | |
431 * | |
432 * PARAMETERS: | |
433 * "ht" | |
434 * Address of PrimHashtable to free. Must be non-NULL. | |
435 * "plContext" | |
436 * Platform-specific context pointer. | |
437 * THREAD SAFETY: | |
438 * Not Thread Safe - assumes exclusive access to "ht" | |
439 * (see Thread Safety Definitions in Programmer's Guide) | |
440 * RETURNS | |
441 * Returns NULL if the function succeeds. | |
442 * Returns a HashTable Error if the function fails in a non-fatal way. | |
443 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
444 */ | |
445 PKIX_Error * | |
446 pkix_pl_PrimHashTable_Destroy( | |
447 pkix_pl_PrimHashTable *ht, | |
448 void *plContext) | |
449 { | |
450 pkix_pl_HT_Elem *element = NULL; | |
451 pkix_pl_HT_Elem *temp = NULL; | |
452 PKIX_UInt32 i; | |
453 | |
454 PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Destroy"); | |
455 PKIX_NULLCHECK_ONE(ht); | |
456 | |
457 /* Free each element (list) */ | |
458 for (i = 0; i < ht->size; i++) { | |
459 for (element = ht->buckets[i]; | |
460 element != NULL; | |
461 element = temp) { | |
462 temp = element->next; | |
463 element->value = NULL; | |
464 element->key = NULL; | |
465 element->hashCode = 0; | |
466 element->next = NULL; | |
467 PKIX_FREE(element); | |
468 } | |
469 } | |
470 | |
471 /* Free the pointer to the list array */ | |
472 PKIX_FREE(ht->buckets); | |
473 ht->size = 0; | |
474 | |
475 /* Free the table itself */ | |
476 PKIX_FREE(ht); | |
477 | |
478 PKIX_RETURN(HASHTABLE); | |
479 } | |
480 | |
481 /* | |
482 * FUNCTION: pkix_pl_PrimHashTable_GetBucketSize | |
483 * DESCRIPTION: | |
484 * | |
485 * Retruns number of entries in the bucket the "hashCode" is designated in | |
486 * the hashtable "ht" in the address "pBucketSize". | |
487 * | |
488 * PARAMETERS: | |
489 * "ht" | |
490 * Address of PrimHashtable to get entries count. Must be non-NULL. | |
491 * "hashCode" | |
492 * Hashcode value of the key. | |
493 * "pBucketSize" | |
494 * Address that an PKIX_UInt32 is returned for number of entries in the | |
495 * bucket associated with the hashCode. Must be non-NULL. | |
496 * "plContext" | |
497 * Platform-specific context pointer. | |
498 * THREAD SAFETY: | |
499 * Not Thread Safe - assumes exclusive access to "ht" | |
500 * (see Thread Safety Definitions in Programmer's Guide) | |
501 * RETURNS: | |
502 * Returns NULL if the function succeeds. | |
503 * Returns a HashTable Error if the function fails in a non-fatal way. | |
504 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
505 */ | |
506 PKIX_Error * | |
507 pkix_pl_PrimHashTable_GetBucketSize( | |
508 pkix_pl_PrimHashTable *ht, | |
509 PKIX_UInt32 hashCode, | |
510 PKIX_UInt32 *pBucketSize, | |
511 void *plContext) | |
512 { | |
513 pkix_pl_HT_Elem **elemPtr = NULL; | |
514 pkix_pl_HT_Elem *element = NULL; | |
515 PKIX_UInt32 bucketSize = 0; | |
516 | |
517 PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_GetBucketSize"); | |
518 PKIX_NULLCHECK_TWO(ht, pBucketSize); | |
519 | |
520 for (elemPtr = &((ht->buckets)[hashCode%ht->size]), element = *elemPtr; | |
521 element != NULL; elemPtr = &(element->next), element = *elemPtr) { | |
522 bucketSize++; | |
523 } | |
524 | |
525 *pBucketSize = bucketSize; | |
526 | |
527 PKIX_RETURN(HASHTABLE); | |
528 } | |
529 | |
530 /* | |
531 * FUNCTION: pkix_pl_PrimHashTable_RemoveFIFO | |
532 * DESCRIPTION: | |
533 * | |
534 * Remove the first entry in the bucket the "hashCode" is designated in | |
535 * the hashtable "ht". Since new entry is added at end of the link list | |
536 * the first one is the oldest (FI) therefore removed first (FO). | |
537 * | |
538 * PARAMETERS: | |
539 * "ht" | |
540 * Address of PrimHashtable to get entries count. Must be non-NULL. | |
541 * "hashCode" | |
542 * Hashcode value of the key. | |
543 * "pKey" | |
544 * Address of key of the entry deleted. Must be non-NULL. | |
545 * "pValue" | |
546 * Address of Value of the entry deleted. Must be non-NULL. | |
547 * "plContext" | |
548 * Platform-specific context pointer. | |
549 * THREAD SAFETY: | |
550 * Not Thread Safe - assumes exclusive access to "ht" | |
551 * (see Thread Safety Definitions in Programmer's Guide) | |
552 * RETURNS: | |
553 * Returns NULL if the function succeeds. | |
554 * Returns a HashTable Error if the function fails in a non-fatal way. | |
555 * Returns a Fatal Error if the function fails in an unrecoverable way. | |
556 */ | |
557 PKIX_Error * | |
558 pkix_pl_PrimHashTable_RemoveFIFO( | |
559 pkix_pl_PrimHashTable *ht, | |
560 PKIX_UInt32 hashCode, | |
561 void **pKey, | |
562 void **pValue, | |
563 void *plContext) | |
564 { | |
565 pkix_pl_HT_Elem *element = NULL; | |
566 | |
567 PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Remove"); | |
568 PKIX_NULLCHECK_THREE(ht, pKey, pValue); | |
569 | |
570 element = (ht->buckets)[hashCode%ht->size]; | |
571 | |
572 if (element != NULL) { | |
573 | |
574 *pKey = element->key; | |
575 *pValue = element->value; | |
576 ht->buckets[hashCode%ht->size] = element->next; | |
577 element->key = NULL; | |
578 element->value = NULL; | |
579 element->next = NULL; | |
580 PKIX_FREE(element); | |
581 } | |
582 | |
583 PKIX_RETURN(HASHTABLE); | |
584 } | |
OLD | NEW |