00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
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
00173 while ((ptr != 0) && (ptr->key != key)) {
00174
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
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);
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 }