IPP Software Navigation Tools IPP Links Communication Pan-STARRS Links

Ignore:
Timestamp:
Jun 9, 2004, 2:09:55 PM (22 years ago)
Author:
gusciora
Message:

Renamed psLog messages, commented the psHash code.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/psLib/src/sysUtils/psHash.c

    r919 r964  
    44 *
    55 *  This file will hold the functions for defining a hash table with arbitrary
    6  *  data types, allocating/deallocating that has table, adding and removing
     6 *  data types, allocating/deallocating that hash table, adding and removing
    77 *  data from that hash table, and listing all keys defined in the hash table.
    88 *
     
    1010 *  @author George Gusciora, MHPCC
    1111 *   
    12  *  @version $Revision: 1.7 $ $Name: not supported by cvs2svn $
    13  *  @date $Date: 2004-06-08 19:08:40 $
     12 *  @version $Revision: 1.8 $ $Name: not supported by cvs2svn $
     13 *  @date $Date: 2004-06-10 00:09:55 $
    1414 *
    1515 *  Copyright 2004 Maui High Performance Computing Center, University of Hawaii
     
    1818#include <stdio.h>
    1919#include <string.h>
    20 //#include "psLib.h"
    2120#include "psHash.h"
    2221#include "psMemory.h"
     
    2524#include "psAbort.h"
    2625
     26
     27/******************************************************************************
     28psHashKeyList(table): this function creates a linked list with an entry in
     29that list for every key in the hash table.
     30Inputs:
     31    table: a hash table
     32Return;
     33    The linked list
     34 *****************************************************************************/
    2735psList *psHashKeyList(psHash *table)
    2836{
    29     int i = 0;
    30     psList *myLinkList = NULL;
     37    int i = 0;                          // Loop index variable
     38    psList *myLinkList = NULL;  // The output data structure
     39    psHashBucket *ptr = NULL;           // Used to step thru linked list.
    3140
    3241    if (table == NULL) {
     
    3443    }
    3544
     45    // Create the linked list
    3646    myLinkList = psListAlloc(NULL);
    3747
     48    // Loop through every bucket in the hash table.  If that bucket is not
     49    // NULL, then add the bucket's key to the linked list.
    3850    for (i=0;i<table->nbucket;i++) {
    3951        if (table->buckets[i] != NULL) {
    40             psListAdd(myLinkList, (table->buckets[i])->key, PS_LIST_HEAD);
     52            // Since a bucket contains a linked list of keys/data, we must
     53            // step trough each key in that linked list:
     54
     55            ptr = table->buckets[i];
     56            while (ptr != NULL) {
     57                psListAdd(myLinkList, ptr->key, PS_LIST_HEAD);
     58                ptr = ptr->next;
     59            }
    4160        }
    4261    }
    4362
     63    // Return the linked list
    4464    return(myLinkList);
    4565}
    4666
    47 /******************************************************************************
    48     Construct buckets
     67
     68
     69/******************************************************************************
     70hashBucketAlloc(key, data, next): This procedure creates a new hash bucket
     71with the specified key, data, and next.
     72Inputs:
     73    key:  the new bucket's key pointer
     74    data: the new bucket's data pointer
     75    next: the new bucket's key pointer
     76Return:
     77    the new hash bucket.
    4978 *****************************************************************************/
    5079static psHashBucket *hashBucketAlloc(const char *key,
     
    5281                                     psHashBucket *next)
    5382{
     83    if (key == NULL) {
     84        psAbort(__func__, "psHashBucket() called with NULL key.");
     85    }
     86
     87    // Allocate memory for the new hash bucket.
    5488    psHashBucket *bucket = psAlloc(sizeof(psHashBucket));
    5589
     90    // Initialize the bucket.
    5691    bucket->key = psStringCopy(key);
    57     bucket->data = psMemIncrRefCounter(data);
     92
     93    if (data == NULL) {
     94        // NOTE: Should we flag a warning message?
     95        bucket->data = NULL;
     96    } else {
     97        bucket->data = psMemIncrRefCounter(data);
     98    }
     99
    58100    bucket->next = next;
    59101
     
    61103}
    62104
    63 /******************************************************************************
    64     Destruct buckets
     105
     106/******************************************************************************
     107hashBucketFree(bucket, itemFree): This procedure deallocates the specified
     108hash bucket.  If "itemFree" is NULL, then we simply free the data with the
     109standard psFree() function.  If "itemFree" is not NULL, then it must be a
     110function pointer which takes the hash bucket as a parameter, and frees the
     111data in that hash bucket.
     112Inputs:
     113    bucket: the hash bucket to be freed.
     114    itemFree: a function pointer, possibly NULL.
     115Return:
     116    NONE
    65117 *****************************************************************************/
    66118static void hashBucketFree(psHashBucket *bucket,   // bucket to free
     
    72124    }
    73125
     126    // A bucket is actually a linked list of buckets.  We recursively step
     127    // through that linked list, free each bucket.
    74128    if (bucket->next != NULL)
    75129    {
     
    83137    {
    84138        itemFree(bucket->data);
     139    } else
     140    {
     141        psFree(bucket->data);
    85142    }
    86143
     
    88145}
    89146
    90 /******************************************************************************
    91     Con/Destruct psHash tables
     147
     148/******************************************************************************
     149psHashAlloc(nbucket): this procedure creates a new hash table with the
     150specified number of buckets.
     151Inputs:
     152    nbucket: initial number of buckets
     153Return:
     154    The new hash table.
    92155 *****************************************************************************/
    93156psHash *psHashAlloc(int nbucket) // initial number of buckets
    94157{
     158    int i = 0;   // loop index variable
     159    // Create the new hash table.
    95160    psHash *table = psAlloc(sizeof(psHash));
     161
     162    // Allocate memory for the buckets.
    96163    table->buckets = psAlloc(nbucket*sizeof(psHashBucket *));
    97164    table->nbucket = nbucket;
     
    99166    psTrace("utils.hash", 1, "Creating %d-element hash table\n", nbucket);
    100167
    101     for (int i = 0; i < nbucket; i++)
     168    // Initialize all buckets to NULL.
     169    for (i = 0; i < nbucket; i++)
    102170    {
    103171        table->buckets[i] = NULL;
    104172    }
    105173
     174    // Return the new hash table.
    106175    return table;
    107176}
    108177
    109 /******************************************************************************
     178
     179
     180/******************************************************************************
     181psHashFree(table, itemFree): This procedure deallocates the specified hash
     182table.  It loops through each bucket, and calls hashBucketFree() on that
     183bucket.
    110184 
     185Inputs:
     186    table: a hash table
     187    itemFree: a function pointer, possibly NULL.
     188Return:
     189    NONE
    111190 *****************************************************************************/
    112191void psHashFree(psHash *table,  // hash table to be freed
    113192                void (*itemFree)(void *item)) // how to free hashed data; or NULL
    114193{
     194    psHashBucket *tmp = NULL;           // Used to step through linked list.
     195    psHashBucket *ptr = NULL;           // Used to step through linked list.
     196    int i = 0;                          // Loop index variable.
     197
    115198    if (table == NULL)
    116199    {
    117200        return;
    118201    }
    119     /*
    120      * Release data interned on the list, and delete the buckets
    121      */
    122 
    123     for (int i = 0; i < table->nbucket; i++)
    124     {
     202
     203    // Loop through each bucket in the hash table.  If that bucket is not
     204    // NULL, then free the bucket via a function call to hashBucketFree();
     205
     206    for (i = 0; i < table->nbucket; i++)
     207    {
     208        // A bucket is composed of a linked list of buckets.  We use the
     209        // "tmp" and "ptr" pointers to step through that list and free each
     210        // non-NULL bucket.
     211
    125212        if (table->buckets[i] != NULL) {
    126             psHashBucket *ptr = table->buckets[i];
     213            ptr = table->buckets[i];
    127214            while (ptr != NULL) {
    128                 psHashBucket *tmp = ptr->next;
     215                tmp = ptr->next;
    129216                hashBucketFree(ptr, itemFree);
    130217                ptr = tmp;
     
    133220    }
    134221
     222    // Free the bucket structure, then the hash table.
    135223    psFree(table->buckets);
    136224    psFree(table);
     
    138226
    139227/******************************************************************************
    140     Here's the routine to do the work of insertion/retrieval/removal
     228doHashWork(table, key, data, remove, itemFree): This is an internal
     229procedure which does the bulk of the work in using the hash table.  Depending
     230upon the input parameters, it will either insert a new key/data into the hash
     231table, retrieve the data for a specified key, or remove a key/data item.  If
     232we try to insert a key that already exists in the hash table, then we call
     233the user-supplied function itemfree (or psFree if that is NULL), to free the
     234existing data/key item.
     235Inputs:
     236    table: a hash table
     237    key: the key to insert, retrieve, or remove.  Must not be NULL.
     238    data: the data to insert, if not NULL
     239    remove: set to non-zero if the key/data should be removed from the table.
     240    itemFree: function pointer
     241Return:
     242    NONE
    141243 
    142     We need itemFree if the key is already in use and we're inserting
     244NOTE: consider removing this private function and simply putting the code
     245into the psHashInsert(), psHashLookup(), and psHashRemove().  Why?  Because
     246there is little common code between those functions.
    143247  *****************************************************************************/
    144248static void *doHashWork(psHash     *table,   // table to insert in
     
    149253                            void (*itemFree)(void *item)) // how to free hashed data
    150254{
    151     long int hash = 1;                  // This will contained an integer value
     255    long int hash = 1;                  // This will contain an integer value
    152256    // "hashed" from the key.
    153     psHashBucket *ptr = NULL;           // Used to retrieve the requested hash
    154     // bucket.
    155     psHashBucket *optr = NULL;
    156     char *tmpchar = NULL;
    157 
    158     // NOTE: this is NOT a good hash function!  See Knuth.
    159     //
     257    char *tmpchar = NULL;               // Used in computing the hash function.
     258    psHashBucket *ptr = NULL;           // Used to retrieve the hash bucket.
     259    psHashBucket *optr = NULL;          // "original pointer": used to step
     260    // thru the linked list for a bucket.
     261
     262    // The following condition should never be true, since this is a private
     263    // function, but I'm checking it anyway since future coders might change
     264    // the way this procedure is called.
     265    if ((table == NULL) || (key == NULL)) {
     266
     267        psAbort(__func__, "psHashRemove() called with NULL key or table.");
     268    }
     269
     270    // NOTE: This is the originally supplied hash function.
    160271    //    for (int i = 0, len = strlen(key); i < len; i++) {
    161272    //        hash = (hash << 1) ^ key[i];
     
    172283    // NOTE: This should not be necessary, but for now, I'm checking bounds
    173284    // anyway.
    174     if ((hash < 0) ||
    175             (hash >= table->nbucket)) {
    176         psAbort(__func__,"Internal hash function out of range (%d)",
    177                 hash);
    178     }
    179 
     285    if ((hash < 0) || (hash >= table->nbucket)) {
     286        psAbort(__func__,"Internal hash function out of range (%d)", hash);
     287    }
     288
     289    // ptr will have the correct hash bucket.
    180290    ptr = table->buckets[hash];
    181291
    182     // We've found the correct hash bucket, now we need to know what to do.
     292    // We know the correct hash bucket, now we need to know what to do.
    183293    // If the data parameter is NULL, then, by definition, this is a retrieve
    184294    // or a remove operation on the hash table.
     295
    185296    if (data == NULL) {
    186297        if (remove
     
    191302            optr = ptr;
    192303            while (ptr != NULL) {
     304                // Dtermine if this entry holds the correct key.
    193305                if (strcmp(key, ptr->key) == 0) {
     306                    // The following lines of code are fairly standard ways
     307                    // of removing an item from a single-linked list.
     308
    194309                    void *data = ptr->data;
    195310                    optr->next = ptr->next;
    196 
    197311                    if (ptr == table->buckets[hash]) {
    198312                        table->buckets[hash] = ptr->next;
    199313                    }
    200314
    201                     //                    if (itemFree != NULL) {
    202                     //                        printf("Calling itemFree()\n");
    203                     //                        itemFree(psMemDecrRefCounter(ptr->data));
    204                     //                        printf("Called itemFree()\n");
    205                     //                    }
    206 
    207315                    psFree(ptr->key);
    208316                    psFree(ptr);
    209317
    210                     return psMemDecrRefCounter(data); // return data
     318                    // By definition, the data associated with that key
     319                    // must be returned, not freed.
     320                    return psMemDecrRefCounter(data);
    211321                }
    212 
    213322                optr = ptr;
    214323                ptr = ptr->next;
    215324            }
     325            return NULL;   // not in hash
    216326        }
    217327        else {
     328            // If we get here, then a retrieve operation is requested.  So,
     329            // we step trough the linked list at this bucket, and return the
     330            // data once we find it, or return NULL if we don't.
    218331            while (ptr != NULL) {
    219                 if (strcmp(key, ptr->key) == 0) { // found it!
     332                if (strcmp(key, ptr->key) == 0) {
    220333                    return ptr->data;
    221334                }
    222335                ptr = ptr->next;
    223336            }
     337            return NULL;   // not in hash
    224338        }
    225 
    226         return NULL;   // not in hash
    227339    } else {
    228340        // We get here if this procedure was called with non-NULL data.
     
    231343        // the hash table and look for a duplicate entry for this key.
    232344
    233 
    234345        while (ptr != NULL) {
    235346            if (strcmp(key, ptr->key) == 0) {
    236347                // We have found this key in the hash table.
    237                 if (itemFree == NULL) {
    238                     // The user has not supplied a routine, so we cannot
    239                     // insert the data.
    240                     return NULL;
    241                 }
    242348
    243349                psTrace("utils.hash.insert", 3, "Replacing data for %s\n",
    244350                        key);
    245351
    246                 itemFree(psMemDecrRefCounter(ptr->data));
     352                // NOTE: I have changed this behavior from the originally
     353                // supplied code.  Formerly, if itemFree was NULL, then
     354                // the new data was not inserted into the hash table.
     355
     356                if (itemFree == NULL) {
     357                    psFree(psMemDecrRefCounter(ptr->data));
     358                } else {
     359                    itemFree(psMemDecrRefCounter(ptr->data));
     360                }
     361
    247362                ptr->data = psMemIncrRefCounter(data);
    248 
    249363                return data;
    250364            }
    251365        }
    252 
    253366        // We did not found key in the linked list for this bucket of the hash
    254367        // table.  So, we insert this data at the head of that linked list.
     368
    255369        table->buckets[hash] = hashBucketAlloc(key,
    256370                                               data,
    257371                                               table->buckets[hash]);
    258 
    259372        return data;
    260373    }
     
    262375
    263376/******************************************************************************
    264     Insert a value into a hash table
     377psHashInsert(table, key, data, itemFree): this procedure, which is part of
     378the public API, inserts a new key/data pair into the hash table.
     379Inputs:
     380    table: a hash table
     381    key: the key to use
     382    data: the data to insert.
     383    itemFree: a function pointer
     384Return:
     385    NONE
    265386 *****************************************************************************/
    266387void *psHashInsert(psHash *table,   // table to insert in
     
    269390                   void (*itemFree)(void *item)) // how to free hashed data;
    270391{
    271     void *tmp;
    272 
    273     tmp = doHashWork(table, key, data, 0, itemFree);
    274     return(tmp);
    275 }
    276 
    277 /******************************************************************************
    278     Lookup a value in a hash table
     392    if (table == NULL) {
     393        psAbort(__func__, "psHashInsert() called with NULL hash table.");
     394    }
     395    if (key == NULL) {
     396        psAbort(__func__, "psHashInsert() called with NULL key.");
     397    }
     398    if (data == NULL) {
     399        psAbort(__func__, "psHashLookup() called with NULL data.");
     400    }
     401
     402    return doHashWork(table, key, data, 0, itemFree);
     403}
     404
     405/******************************************************************************
     406psHashLookup(table, key): this procedure, which is part of the public API,
     407looks up the specified key in the hash table and returns the data associated
     408with that key.
     409 
     410Inputs:
     411    table: a hash table
     412    key: the key to use
     413Return:
     414    The data associated with that key.
    279415 *****************************************************************************/
    280416void *psHashLookup(psHash *table,   // table to lookup key in
    281417                   const char *key) // key to lookup
    282418{
     419    if (table == NULL) {
     420        psAbort(__func__, "psHashLookup() called with NULL hash table.");
     421    }
     422    if (key == NULL) {
     423        psAbort(__func__, "psHashLookup() called with NULL key.");
     424    }
     425
     426
    283427    return doHashWork(table, key, NULL, 0, NULL);
    284428}
    285429
    286430/******************************************************************************
    287     Remove and return a value from a hash table
     431psHashRemove(table, key, itemFree): this procedure, which is part of the
     432public API, removes the specified key from the hash table.
     433Inputs:
     434    table: a hash table
     435    key: the key to remove
     436    itemFree: a function pointer
     437Return:
     438    The data that was associated with that key.
    288439 *****************************************************************************/
    289440void *psHashRemove(psHash *table,   // table to lookup key in
     
    291442                   void (*itemFree)(void *item)) // how to free hashed data;
    292443{
     444    if (table == NULL) {
     445        psAbort(__func__, "psHashRemove() called with NULL hash table.");
     446    }
     447    if (key == NULL) {
     448        psAbort(__func__, "psHashRemove() called with NULL key.");
     449    }
     450
    293451    return doHashWork(table, key, NULL, 1, itemFree);
    294452}
Note: See TracChangeset for help on using the changeset viewer.