Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

hash.C

Go to the documentation of this file.
00001 /*************************************************************************
00002  *    NAME: Loring Holden
00003  *    USER: lsh
00004  *    FILE: hash.C
00005  *    DATE: Wed Aug 27 12:53:19 US/Eastern 1997
00006  *************************************************************************/
00007 #include <cstring>
00008 #include <cassert>
00009 #include "support.H"
00010 
00011 ThreadMutex mutex;
00012 
00013 static const int RIGHT_BITS_TO_DROP = 3;
00014 
00015 inline
00016 int
00017 HASH::hash(const long key) const
00018 {
00019    return (key & _mask) >> RIGHT_BITS_TO_DROP;
00020 }
00021 
00022 /*************************************************************************
00023  * Function Name: HASH::HASH
00024  * Parameters: int size
00025  * Effects: 
00026  *************************************************************************/
00027 HASH::HASH(int size)
00028 {
00029    if (size == 0) {
00030       _size    = 0;
00031       _mask    = 0;
00032       _lastval = 0;
00033       _table   = 0;
00034       return;
00035    }
00036    int       realsize;
00037    // size of 2 gives an actual _size of 1, which doesn't work w/ the
00038    // hash function
00039    if (size < 4) size = 4;
00040 
00041    /* Round up to next power of 2 */
00042    for (--size, realsize = 1; size; size >>= 1) realsize <<= 1;
00043 
00044    _table = new hash_node*[realsize];
00045    for (int i = 0; i < realsize; i++) _table[i] = 0;
00046 
00047    _mask = (realsize - 1) << RIGHT_BITS_TO_DROP;
00048    _size = (realsize - 1);
00049 
00050    _lastval = 0;
00051 }
00052 
00053 /*************************************************************************
00054  * Function Name: HASH::HASH
00055  * Parameters: const HASH &hash_table
00056  * Effects: Copy constructor
00057  *************************************************************************/
00058 
00059 HASH::HASH(const HASH &old)
00060    : _size(old._size),
00061      _mask(old._mask),
00062      _lastval(0)
00063 {
00064    _table = new hash_node*[_size + 1];
00065 
00066    for (int i =  0; i < _size + 1; i++) {
00067       if (old.table()[i]) {
00068     // Recursively copies buckets
00069     table()[i] = new hash_node(*old.table()[i]);
00070       }
00071    }
00072 }
00073 
00074 
00075 /*************************************************************************
00076  * Function Name: HASH::~HASH
00077  * Parameters: 
00078  * Effects: 
00079  *************************************************************************/
00080 
00081 HASH::~HASH()
00082 {
00083    clear();
00084    delete [] _table;
00085 }
00086 
00087 
00088 /*************************************************************************
00089  * Function Name: HASH::add
00090  * Parameters: long key, void *data
00091  * Returns: int
00092  * Effects: 
00093  * DESCR   : Add a new node to the hash table, associating the data pointer
00094  *           with the key value.  Any previous data associated with the key
00095  *           is overwritten.
00096  *
00097  * RETURNS : +1 if there was previous data assiciated with key.
00098  *           -1 if the allocation of the new HASH node failed.
00099  *            0 otherwise.
00100  *************************************************************************/
00101 int
00102 HASH::add(long key, void *data)
00103 {
00104    CriticalSection cs(&mutex);
00105    assert(table());
00106    hash_node *e, *new_node, *prev, **list = &table()[hash(key)];
00107 
00108    for (e = *list, prev=0; e != 0; prev = e, e = e->next()) {
00109       if (e->key() == key) {
00110     e->data(data);
00111     return  1;
00112       }
00113       else if (e->key() > key) break;
00114    }
00115 
00116    new_node  = new hash_node(key, data, e);
00117    if (prev == 0) *list = new_node;
00118    else     prev->next(new_node);
00119 
00120    return 0;
00121 }
00122 
00123 
00124 /*************************************************************************
00125  * Function Name: HASH::del
00126  * Parameters: long key
00127  * Returns: int
00128  * Effects: 
00129  *************************************************************************/
00130 int
00131 HASH::del(long key)
00132 {
00133    hash_node *e, *prev, **list = &table()[hash(key)];
00134 
00135    for (e = *list, prev = 0; e != 0; prev = e, e=e->next()) {
00136       if (e->key() == key) {
00137     if (prev == 0)
00138        *list = e->next();
00139     else
00140        prev->next(e->next());
00141     delete e;
00142     return 0;
00143       }
00144       else if (e->key() > key) break;
00145    }
00146 
00147    return 1;
00148 }
00149 
00150 
00151 /*************************************************************************
00152  * Function Name: HASH::find_addr
00153  * Parameters: long key
00154  * Returns: void **
00155  * Effects: 
00156  * DESCR   : Looks up the data associated with a key.
00157  *
00158  * RETURNS : A pointer to the data associated with the key.
00159  *           0 if the key was not in the table.
00160  *************************************************************************/
00161 void **
00162 HASH::find_addr(long key) const
00163 {
00164    CriticalSection cs(&mutex);
00165    hash_node **list, *e;
00166 
00167    list = &table()[hash(key)];
00168 
00169    for (e = *list; e != 0; e = e->next())
00170       if (e->key() == key)     return &e->data_ptr();
00171       else if (e->key() > key) break;
00172 
00173    return 0;
00174 }
00175 
00176 
00177 /*************************************************************************
00178  * Function Name: HASH::bfind
00179  * Parameters: long key, void *&data
00180  * Returns: int
00181  * Effects: 
00182  * DESCR   : Looks up the data associated with the key.  This "better" find
00183  *           will allow the user to distinguish between an unsuccessful
00184  *           search and a successful search for a key with 0 data.
00185  *
00186  * RETURNS : STD_1  - If the key was found in the table.
00187  *                       The data is also returned in the data parameter.
00188  *           STD_0 - If the key was not found.
00189  *************************************************************************/
00190 int
00191 HASH::bfind(long key, void *&data) const
00192 {
00193    hash_node **list, *e;
00194 
00195    list = &table()[hash(key)];
00196 
00197    for (e = *list; e != 0; e = e->next()) {
00198       if (e->key() == key) {
00199     data = e->data();
00200     return 1;
00201       }
00202       else if (e->key() > key) break;
00203    }
00204    return 0;
00205 }
00206 
00207 
00208 /*************************************************************************
00209  * Function Name: HASH::addn
00210  * Parameters: int num, char *key, void *data
00211  * Returns: int
00212  * Effects: 
00213  * DESCR   : Add a node to the table, where the key is n bytes long.
00214  *
00215  * RETURNS : +1 if there was previous data assiciated with key.
00216  *           -1 if the allocation of the new HASH node failed.
00217  *            0 otherwise.
00218  *************************************************************************/
00219 int
00220 HASH::add(const char *key, void *data, char *&loc, int create_new)
00221 {
00222    CriticalSection cs(&mutex);
00223    assert(table());
00224    hash_node *e, *prev, **list = &table()[hash(key)];
00225 
00226    for (e = *list, prev = 0; e != 0; prev = e, e=e->next())
00227       if (!strcmp((char *) e->key(), key)) {
00228          loc = (char *) e->key();
00229     e->data(data);
00230     return 0;
00231       }
00232 
00233    loc = create_new ? strdup(key) : (char *) key;
00234    hash_node *new_node = new hash_node((long) loc, data, e);
00235 
00236    if (prev == 0) *list = new_node;
00237    else     prev->next(new_node);
00238    return(0);
00239 }
00240 
00241 
00242 /*************************************************************************
00243  * Function Name: HASH::findn
00244  * Parameters: int num_bytes, char *key
00245  * Returns: void  *
00246  * Effects: 
00247  * DESCR   : Looks up the data associated with a key of n bytes.
00248  *
00249  * RETURNS : Data associated with the key.
00250  *           0 if the key was not in the table.
00251  *************************************************************************/
00252 void  *
00253 HASH::find(char *key) const
00254 {
00255    CriticalSection cs(&mutex);
00256    assert(table());
00257    hash_node *e, **list = &table()[hash(key)];
00258 
00259    for (e = *list; e != 0; e = e->next())
00260       if (!strcmp((char *) e->key(), key))
00261          return e->data();
00262 
00263    return(0);
00264 }
00265 
00266 void
00267 HASH::get_items(ARRAY<long> &keys, ARRAY<void *> &items) const
00268 {
00269    hash_node *seq_elt = 0;
00270    int        seq_val = -1;
00271    long       key;
00272    void      *data;
00273    keys.clear();
00274    items.clear();
00275    while (next_seq(key, data, seq_elt, seq_val)) {
00276        items += data;
00277        keys  += key;
00278    }
00279 }
00280 
00281 /*************************************************************************
00282  * Function Name: HASH::next_seq
00283  * Parameters: long &key, void *&data
00284  * Returns: int
00285  * Effects: 
00286  *************************************************************************/
00287 int
00288 HASH::next_seq(long &key, void *&data, hash_node *&seq_elt, int &seq_val) const
00289 {
00290    // If no items, return 0
00291    if (!table()) return 0;
00292 
00293    while (seq_elt == 0) {
00294       if (seq_val == _size) 
00295          return 0;
00296       seq_elt = table()[++seq_val];
00297    }
00298 
00299    key  = seq_elt->key();
00300    data = seq_elt->data();
00301 
00302    seq_elt = seq_elt->next();
00303 
00304    return 1;
00305 }
00306 
00307 /*************************************************************************
00308  * Function Name: HASH::hash
00309  * Parameters: char *
00310  * Returns: long
00311  * Effects: 
00312  *************************************************************************/
00313 long
00314 HASH::hash(const char *key) const
00315 {
00316    /* first value should be 0 */
00317    static int list[] = { 0, 4, 8, 12, 11, 5, 1, 9, 4, 10, 7, 1 };
00318    long i, k = 0;
00319 
00320    if (key == 0 || *key == '\0') return 0;
00321 
00322    for(i=0; key[i] != '\0'; ++i)  k += (long)(key[i]) << list[i % 12];
00323    return hash(k);
00324 }
00325 
00326 /***********************************************************************
00327  * Method    : HASH::clear
00328  * Parameters: 
00329  * Returns   : void
00330  * Effects   : 
00331  ***********************************************************************/
00332 void
00333 HASH::clear() 
00334 {
00335    hash_node **list, *e, *next;
00336    int         i;
00337 
00338    for (i = _size, list = &_table[i]; i--; --list) {
00339       for (e = *list; e; e = next) {
00340     next = e->next();
00341     delete e;
00342       }
00343       _table[i] = 0;
00344    }
00345 }
00346 
00347 double 
00348 HASH::load_factor() const
00349 {
00350    // return avg number of elements per slot
00351 
00352    if (_size < 1)
00353       return 0;
00354 
00355    int count = 0;
00356    for (int i = 0; i < _size; i++)
00357       for (hash_node* e = _table[i]; e; e = e->next())
00358          count++;
00359 
00360    return double(count)/_size;
00361 }

Generated on Mon Sep 18 11:39:31 2006 for jot by  doxygen 1.4.4