tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }