sc_hash.cpp

Go to the documentation of this file.
00001 /*****************************************************************************
00002 
00003   The following code is derived, directly or indirectly, from the SystemC
00004   source code Copyright (c) 1996-2006 by all Contributors.
00005   All Rights reserved.
00006 
00007   The contents of this file are subject to the restrictions and limitations
00008   set forth in the SystemC Open Source License Version 2.4 (the "License");
00009   You may not use this file except in compliance with such restrictions and
00010   limitations. You may obtain instructions on how to receive a copy of the
00011   License at http://www.systemc.org/. Software distributed by Contributors
00012   under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF
00013   ANY KIND, either express or implied. See the License for the specific
00014   language governing rights and limitations under the License.
00015 
00016  *****************************************************************************/
00017 
00018 /*****************************************************************************
00019 
00020   sc_hash.cpp -- Implementation of a chained hash table with MTF
00021                  (move-to-front).
00022 
00023   Original Author: Stan Y. Liao, Synopsys, Inc.
00024 
00025  *****************************************************************************/
00026 
00027 /*****************************************************************************
00028 
00029   MODIFICATION LOG - modifiers, enter your name, affiliation, date and
00030   changes you are making here.
00031 
00032       Name, Affiliation, Date:
00033   Description of Modification:
00034 
00035  *****************************************************************************/
00036 
00037 
00038 // $Log: sc_hash.cpp,v $
00039 // Revision 1.1.1.1  2006/12/15 20:31:39  acg
00040 // SystemC 2.2
00041 //
00042 // Revision 1.3  2006/01/13 18:53:10  acg
00043 // Andy Goodrich: Added $Log command so that CVS comments are reproduced in
00044 // the source.
00045 //
00046 
00047 #include <assert.h>
00048 #include <cstdlib>
00049 
00050 #include "sysc/kernel/sc_cmnhdr.h"
00051 #include "sysc/utils/sc_hash.h"
00052 #include "sysc/utils/sc_mempool.h"
00053 
00054 namespace sc_core {
00055 
00056 const double PHASH_DEFAULT_GROW_FACTOR     = 2.0;
00057 
00058 class sc_phash_elem {
00059     friend class sc_phash_base;
00060     friend class sc_phash_base_iter;
00061 
00062 private:
00063     void* key;
00064     void* contents;
00065     sc_phash_elem* next;
00066 
00067     sc_phash_elem( void* k, void* c, sc_phash_elem* n )
00068         : key(k), contents(c), next(n) { }
00069     sc_phash_elem() { }
00070     ~sc_phash_elem() { }
00071 
00072     static void* operator new(std::size_t sz)            { return sc_mempool::allocate(sz); }
00073     static void operator delete(void* p, std::size_t sz) { sc_mempool::release(p, sz);      }
00074 };
00075 
00076 
00077 sc_phash_base::sc_phash_base(
00078     void* def,
00079     int size,
00080     int density,
00081     double grow,
00082     bool reorder,
00083     unsigned (*hash_fn)(const void*),
00084     int (*cmp_fn)(const void*, const void*)
00085 )
00086 {
00087     default_value = def;
00088     hash          = hash_fn;
00089     num_entries   = 0;
00090     max_density   = density;
00091     grow_factor   = grow;
00092     reorder_flag  = reorder;
00093 
00094     if (size <= 0)
00095         size = PHASH_DEFAULT_INIT_TABLE_SIZE;
00096     else if ((size % 2) == 0)
00097         size += 1;
00098     num_bins = size;
00099     bins = new sc_phash_elem*[size];
00100     for (int i = 0; i < size; ++i)
00101         bins[i] = 0;
00102 
00103     set_cmpr_fn(cmp_fn);
00104 }
00105 
00106 void
00107 sc_phash_base::set_cmpr_fn(cmpr_fn_t c)
00108 {
00109     cmpr = c;
00110 }
00111 
00112 void
00113 sc_phash_base::set_hash_fn(hash_fn_t h)
00114 {
00115     hash = h;
00116 }
00117 
00118 sc_phash_base::~sc_phash_base()
00119 {
00120     sc_phash_elem* ptr;
00121     sc_phash_elem* next;
00122 
00123     for (int i = 0; i < num_bins; ++i) {
00124         ptr = bins[i];
00125         while (ptr != 0) {
00126             next = ptr->next;
00127             delete ptr;
00128             ptr = next;
00129         }
00130     }
00131     delete[] bins;
00132 }
00133 
00134 void
00135 sc_phash_base::rehash()
00136 {
00137     sc_phash_elem* ptr;
00138     sc_phash_elem* next;
00139     sc_phash_elem** old_bins = bins;
00140 
00141     int old_num_bins = num_bins;
00142     unsigned hash_val;
00143 
00144     num_bins = (int) (grow_factor * old_num_bins);
00145     if (num_bins % 2 == 0)
00146         ++num_bins;
00147 
00148     num_entries = 0;
00149     bins = new sc_phash_elem*[num_bins];
00150     memset( bins, 0, sizeof(sc_phash_elem*) * num_bins );
00151 
00152     for (int i = 0; i < old_num_bins; ++i) {
00153         ptr = old_bins[i];
00154         while (ptr != 0) {
00155             next = ptr->next;
00156             hash_val = do_hash(ptr->key);
00157             ptr->next = bins[hash_val];
00158             bins[hash_val] = ptr;
00159             ++num_entries;
00160             ptr = next;
00161         }
00162     }
00163     delete[] old_bins;
00164 }
00165 
00166 sc_phash_elem*
00167 sc_phash_base::find_entry_q( unsigned hash_val, const void* key, sc_phash_elem*** plast )
00168 {
00169     sc_phash_elem** last = &(bins[hash_val]);
00170     sc_phash_elem*  ptr  = *last;
00171 
00172     /* The (ptr->key != key) here is meant by the "q" */
00173     while ((ptr != 0) && (ptr->key != key)) {
00174         /*                         ^^ right here */
00175         last = &(ptr->next);
00176         ptr  = *last;
00177     }
00178     if ((ptr != 0) && reorder_flag) {
00179         *last = ptr->next;
00180         ptr->next = bins[hash_val];
00181         bins[hash_val] = ptr;
00182         last = &(bins[hash_val]);
00183     }
00184     if (plast) *plast = last;
00185     return ptr;
00186 }
00187 
00188 sc_phash_elem*
00189 sc_phash_base::find_entry_c( unsigned hash_val, const void* key, sc_phash_elem*** plast )
00190 {
00191     sc_phash_elem** last = &(bins[hash_val]);
00192     sc_phash_elem*  ptr  = *last;
00193 
00194     while ((ptr != 0) && ((*cmpr)(ptr->key, key) != 0)) {
00195         last = &(ptr->next);
00196         ptr = *last;
00197     }
00198         /* Bring to front */
00199     if ((ptr != 0) && reorder_flag) {
00200         *last = ptr->next;
00201         ptr->next = bins[hash_val];
00202         bins[hash_val] = ptr;
00203         last = &(bins[hash_val]);
00204     }
00205     if (plast) *plast = last;
00206     return ptr;
00207 }
00208 
00209 sc_phash_elem*
00210 sc_phash_base::add_direct( void* key, void* contents, unsigned hash_val )
00211 {
00212     if (num_entries / num_bins >= max_density) {
00213         rehash();
00214         hash_val = do_hash(key);
00215     }
00216 
00217     sc_phash_elem* new_entry = new sc_phash_elem(key, contents, bins[hash_val]);
00218     bins[hash_val] = new_entry;
00219     ++num_entries;
00220     return new_entry;
00221 }
00222 
00223 void
00224 sc_phash_base::erase()
00225 {
00226     for (int i = 0; i < num_bins; ++i) {
00227         sc_phash_elem* ptr = bins[i];
00228         while (ptr != 0) {
00229             sc_phash_elem* next = ptr->next;
00230             delete ptr;
00231             ptr = next;
00232             --num_entries;
00233         }
00234         bins[i] = 0;
00235     }
00236     assert(num_entries == 0);
00237 }
00238 
00239 void
00240 sc_phash_base::erase(void (*kfree)(void*))
00241 {
00242     for (int i = 0; i < num_bins; ++i) {
00243         sc_phash_elem* ptr = bins[i];
00244         while (ptr != 0) {
00245             sc_phash_elem* next = ptr->next;
00246             (*kfree)(ptr->key);
00247             delete ptr;
00248             ptr = next;
00249             --num_entries;
00250         }
00251         bins[i] = 0;
00252     }
00253     assert(num_entries == 0);
00254 }
00255 
00256 void
00257 sc_phash_base::copy( const sc_phash_base* b )
00258 {
00259     erase();
00260     iterator iter((sc_phash_base*) b);  /* cast away the const */
00261     for ( ; ! iter.empty(); iter++)
00262         insert( iter.key(), iter.contents() );
00263 }
00264 
00265 void
00266 sc_phash_base::copy(const sc_phash_base& b, void* (*kdup)(const void*), void (*kfree)(void*))
00267 {
00268     erase(kfree);
00269     iterator iter((sc_phash_base&) b);
00270     for ( ; ! iter.empty(); iter++)
00271         insert( (*kdup)(iter.key()), iter.contents() );
00272 }
00273 
00274 int
00275 sc_phash_base::insert( void* k, void* c )
00276 {
00277     unsigned hash_val = do_hash(k);
00278     sc_phash_elem* ptr = find_entry( hash_val, k );
00279     if (ptr == 0) {
00280         (void) add_direct(k, c, hash_val);
00281         return 0;
00282     }
00283     else {
00284         ptr->contents = c;
00285         return 1;
00286     }
00287 }
00288 
00289 int
00290 sc_phash_base::insert( void* k, void* c, void* (*kdup)(const void*) )
00291 {
00292     unsigned hash_val = do_hash(k);
00293     sc_phash_elem* ptr = find_entry( hash_val, k );
00294     if (ptr == 0) {
00295         (void) add_direct((*kdup)(k), c, hash_val);
00296         return 0;
00297     }
00298     else {
00299         ptr->contents = c;
00300         return 1;
00301     }
00302 }
00303 
00304 int
00305 sc_phash_base::insert_if_not_exists( void* k, void* c )
00306 {
00307     unsigned hash_val = do_hash(k);
00308     sc_phash_elem* ptr = find_entry( hash_val, k );
00309     if (ptr == 0) {
00310         (void) add_direct( k, c, hash_val );
00311         return 0;
00312     }
00313     else
00314         return 1;
00315 }
00316 
00317 int
00318 sc_phash_base::insert_if_not_exists( void* k, void* c, void* (*kdup)(const void*) )
00319 {
00320     unsigned hash_val = do_hash(k);
00321     sc_phash_elem* ptr = find_entry( hash_val, k );
00322     if (ptr == 0) {
00323         (void) add_direct( (*kdup)(k), c, hash_val );
00324         return 0;
00325     }
00326     else
00327         return 1;
00328 }
00329 
00330 int
00331 sc_phash_base::remove( const void* k )
00332 {
00333     unsigned hash_val = do_hash(k);
00334     sc_phash_elem** last;
00335     sc_phash_elem*  ptr = find_entry( hash_val, k, &last );
00336 
00337     if (ptr == 0)
00338         return 0;
00339 
00340     assert(*last == ptr);
00341     *last = ptr->next;
00342     delete ptr;
00343     --num_entries;
00344     return 1;
00345 }
00346 
00347 int
00348 sc_phash_base::remove( const void* k, void** pk, void** pc )
00349 {
00350     unsigned hash_val = do_hash(k);
00351     sc_phash_elem** last;
00352     sc_phash_elem*  ptr = find_entry( hash_val, k, &last );
00353 
00354     if (ptr == 0) {
00355         *pk = 0;
00356         *pc = 0;
00357         return 0;
00358     }
00359     else {
00360         *pk = ptr->key;
00361         *pc = ptr->contents;
00362     }
00363 
00364     assert(*last == ptr);
00365     *last = ptr->next;
00366     delete ptr;
00367     --num_entries;
00368     return 1;
00369 }
00370 
00371 int
00372 sc_phash_base::remove(const void* k, void (*kfree)(void*))
00373 {
00374     void* rk;
00375     void* rc;
00376     if (remove(k, &rk, &rc)) {
00377         (*kfree)(rk);
00378         return 1;
00379     }
00380     else
00381         return 0;
00382 }
00383 
00384 int
00385 sc_phash_base::remove_by_contents( const void* c )
00386 {
00387     sc_phash_elem** last;
00388     sc_phash_elem*  ptr;
00389 
00390     int num_removed = 0;
00391     for (int i = 0; i < num_bins; ++i) {
00392         last = &(bins[i]);
00393         ptr = *last;
00394         while (ptr != 0) {
00395             if (ptr->contents != c) {
00396                 last = &(ptr->next);
00397                 ptr  = *last;
00398             }
00399             else {
00400                 *last = ptr->next;
00401                 delete ptr;
00402                 ptr = *last;
00403                 --num_entries;
00404                 ++num_removed;
00405             }
00406         }
00407     }
00408     return num_removed;
00409 }
00410 
00411 int
00412 sc_phash_base::remove_by_contents( bool (*predicate)(const void* c, void* arg), void* arg )
00413 {
00414     sc_phash_elem** last;
00415     sc_phash_elem*  ptr;
00416 
00417     int num_removed = 0;
00418     for (int i = 0; i < num_bins; ++i) {
00419         last = &(bins[i]);
00420         ptr = *last;
00421         while (ptr != 0) {
00422             if (! (*predicate)(ptr->contents, arg)) {
00423                 last = &(ptr->next);
00424                 ptr  = *last;
00425             }
00426             else {
00427                 *last = ptr->next;
00428                 delete ptr;
00429                 ptr = *last;
00430                 --num_entries;
00431                 ++num_removed;
00432             }
00433         }
00434     }
00435     return num_removed;
00436 }
00437 
00438 int
00439 sc_phash_base::remove_by_contents( const void* c, void (*kfree)(void*) )
00440 {
00441     sc_phash_elem** last;
00442     sc_phash_elem*  ptr;
00443 
00444     int num_removed = 0;
00445     for (int i = 0; i < num_bins; ++i) {
00446         last = &(bins[i]);
00447         ptr = *last;
00448         while (ptr != 0) {
00449             if (ptr->contents != c) {
00450                 last = &(ptr->next);
00451                 ptr  = *last;
00452             }
00453             else {
00454                 *last = ptr->next;
00455                 (*kfree)(ptr->key);
00456                 delete ptr;
00457                 ptr = *last;
00458                 --num_entries;
00459                 ++num_removed;
00460             }
00461         }
00462     }
00463     return num_removed;
00464 }
00465 
00466 int
00467 sc_phash_base::remove_by_contents( bool (*predicate)(const void*, void*), void* arg, void (*kfree)(void*))
00468 {
00469     sc_phash_elem** last;
00470     sc_phash_elem*  ptr;
00471 
00472     int num_removed = 0;
00473     for (int i = 0; i < num_bins; ++i) {
00474         last = &(bins[i]);
00475         ptr = *last;
00476         while (ptr != 0) {
00477             if (! (*predicate)(ptr->contents, arg)) {
00478                 last = &(ptr->next);
00479                 ptr  = *last;
00480             }
00481             else {
00482                 *last = ptr->next;
00483                 (*kfree)(ptr->key);
00484                 delete ptr;
00485                 ptr = *last;
00486                 --num_entries;
00487                 ++num_removed;
00488             }
00489         }
00490     }
00491     return num_removed;
00492 }
00493 
00494 int
00495 sc_phash_base::lookup( const void* k, void** c_ptr ) const
00496 {
00497     unsigned hash_val = do_hash(k);
00498     sc_phash_elem* ptr = find_entry( hash_val, k );
00499     if (ptr == 0) {
00500         if (c_ptr != 0) *c_ptr = default_value;
00501         return 0;
00502     }
00503     else {
00504         if (c_ptr != 0) *c_ptr = ptr->contents;
00505         return 1;
00506     }
00507 }
00508 
00509 void*
00510 sc_phash_base::operator[]( const void* key ) const
00511 {
00512     void* contents;
00513     lookup( key, &contents );
00514     return contents;
00515 }
00516 
00517 /***************************************************************************/
00518 
00519 void
00520 sc_phash_base_iter::reset( sc_phash_base* t )
00521 {
00522     table = t;
00523     index = 0;
00524     entry = 0;
00525     next  = 0;
00526 
00527     for (int i = index; i < table->num_bins; ++i) {
00528         if (table->bins[i] != 0) {
00529             index = i + 1;
00530             last  = &(table->bins[i]);
00531             entry = *last;
00532             next  = entry->next;
00533             break;
00534         }
00535     }
00536 }
00537 
00538 bool
00539 sc_phash_base_iter::empty() const
00540 {
00541     return (entry == 0);
00542 }
00543 
00544 void
00545 sc_phash_base_iter::step()
00546 {
00547     if (entry) {
00548         last = &(entry->next);
00549     }
00550     entry = next;
00551     if (! entry) {
00552         for (int i = index; i < table->num_bins; ++i) {
00553             if (table->bins[i] != 0) {
00554                 index = i + 1;
00555                 last = &(table->bins[i]);
00556                 entry = *last;
00557                 next = entry->next;
00558                 break;
00559             }
00560         }
00561     }
00562     else {
00563         next = entry->next;
00564     }
00565 }
00566 
00567 void
00568 sc_phash_base_iter::remove()
00569 {
00570     delete entry;
00571     *last = next;
00572     entry = 0;
00573     --table->num_entries;
00574     step();
00575 }
00576 
00577 void
00578 sc_phash_base_iter::remove(void (*kfree)(void*))
00579 {
00580     (*kfree)(entry->key);
00581     delete entry;
00582     *last = next;
00583     entry = 0;
00584     --table->num_entries;
00585     step();
00586 }
00587 
00588 void*
00589 sc_phash_base_iter::key() const
00590 {
00591     return entry->key;
00592 }
00593 
00594 void*
00595 sc_phash_base_iter::contents() const
00596 {
00597     return entry->contents;
00598 }
00599 
00600 void*
00601 sc_phash_base_iter::set_contents( void* c )
00602 {
00603     return entry->contents = c;
00604 }
00605 
00606 /****************************************************************************/
00607 
00608 unsigned 
00609 default_ptr_hash_fn(const void* p)
00610 {
00611     return ((unsigned long)(p) >> 2) * 2654435789U;
00612 
00613 }
00614 
00615 unsigned
00616 default_int_hash_fn(const void* p)
00617 {
00618     return (unsigned long)(p) * 3141592661U;
00619 }
00620 
00621 
00622 unsigned
00623 default_str_hash_fn(const void* p)
00624 {
00625     if (!p) return 0;
00626 
00627     const char* x = (const char*) p;
00628     unsigned int h = 0;
00629     unsigned int g;
00630 
00631     while (*x != 0) {
00632         h = (h << 4) + *x++;
00633         if ((g = h & 0xf0000000) != 0)
00634             h = (h ^ (g >> 24)) ^ g;
00635     }
00636     return h;
00637 }
00638 
00639 int
00640 sc_strhash_cmp( const void* a, const void* b )
00641 {
00642     return strcmp( (const char*) a, (const char*) b );
00643 }
00644 
00645 void*
00646 sc_strhash_kdup(const void* k)
00647 {
00648     return strdup((const char*) k);
00649 }
00650 
00651 void
00652 sc_strhash_kfree(void* k)
00653 {
00654     if (k) free((char*) k);
00655 }
00656  } // namespace sc_core

Generated on Wed Jan 21 15:32:10 2009 for SystemC by  doxygen 1.5.5