pkix_pl_primhash.c (19319B)
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 }