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
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120
00121
00122
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148 #ifndef id_map_INCLUDED
00149 #define id_map_INCLUDED "id_map.h"
00150
00151 #include "defs.h"
00152 #include "cxx_template.h"
00153 #include "tracing.h"
00154 #include "opt_defs.h"
00155 #include "erglob.h"
00156
00157 namespace idmap {
00158
00159
00160
00161
00162 #if defined(_LP64) && defined(_MATH_H)
00163 #else
00164 extern "C" {
00165 extern double floor(double);
00166 #ifdef __MATH_HAS_NO_SIDE_EFFECTS
00167 #pragma no side effects (floor)
00168 #endif
00169
00170 extern double ceil(double);
00171 #ifdef __MATH_HAS_NO_SIDE_EFFECTS
00172 #pragma no side effects (ceil)
00173 #endif
00174 }
00175 #endif
00176
00177 #define MIN_TABLE_SIZE 16
00178
00179 #define CAPACITY_FACTOR 0.75
00180
00181
00182
00183 #define GROWTH_FACTOR 2.0
00184
00185 template <class NODE_TYPE, class KEY_TYPE> class ID_MAP;
00186
00187 template <class NODE_TYPE, class KEY_TYPE>
00188 class ID_MAP_HASH_ENTRY {
00189 friend class ID_MAP<NODE_TYPE, KEY_TYPE>;
00190 NODE_TYPE _node;
00191 union {
00192 KEY_TYPE _key;
00193 mINT32 _prev;
00194 };
00195 mINT32 _next;
00196
00197 #ifdef DEBUG_ID_MAP
00198 enum {
00199 IMHE_UNKNOWN,
00200 IMHE_FREE,
00201 IMHE_USED
00202 } _state;
00203 #endif // DEBUG_ID_MAP
00204 };
00205
00206 template <class NODE_TYPE, class KEY_TYPE>
00207 class ID_MAP {
00208 private:
00209 NODE_TYPE _not_found_value;
00210 BOOL _constructed;
00211 const BOOL _tracing;
00212 const BOOL _verbose;
00213 MEM_POOL *const _pool;
00214 ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE> * _table;
00215
00216
00217
00218
00219
00220
00221 UINT32 _table_size;
00222 UINT32 _num_entries;
00223 mINT32 _free_list;
00224
00225
00226
00227 static UINT32 Capacity(UINT32 size)
00228 {
00229 return (UINT32) floor((double) size * CAPACITY_FACTOR);
00230 }
00231
00232
00233
00234 static UINT32 Size(UINT32 capacity)
00235 {
00236 return (UINT32) ceil((double) capacity / CAPACITY_FACTOR);
00237 }
00238
00239 void Alloc_table_space(UINT32 table_size);
00240 void Initialize_table(void);
00241
00242 mINT32 Hash(const KEY_TYPE key, const UINT32 tbl_size) const
00243 {
00244
00245 UINT32 key_uint32;
00246 if (sizeof(key) == sizeof(UINT32)) {
00247 key_uint32 = *((const UINT32 *) &key);
00248 }
00249 else if (sizeof(key) < sizeof(UINT32)) {
00250 key_uint32 = (*((const UINT32 *) &key) &
00251 ((1 << ((sizeof(key) & (sizeof(UINT32)-1)) * 8)) - 1));
00252
00253
00254
00255
00256 }
00257 else {
00258 const UINT32 *p = (const UINT32 *) &key;
00259 INT i;
00260 key_uint32 = 0;
00261 for (i = 0; i < (sizeof(key) / sizeof(UINT32)); i++) {
00262 key_uint32 = (key_uint32 << 19) + (key_uint32 >> 13);
00263 key_uint32 ^= *p++;
00264 }
00265 }
00266
00267
00268 const UINT64 multiplier = 2654435769LL;
00269
00270 mINT32 retval = (tbl_size * ((key_uint32 * multiplier) %
00271 0x100000000LL)) >> 32;
00272 return retval;
00273 }
00274
00275 void Add_to_free_list(const mINT32 idx)
00276 {
00277 Is_Trace(_tracing && _verbose,
00278 (TFile, "ID_MAP::Add_to_free_list(%d)\n", idx));
00279
00280 if (_free_list != -1) {
00281 _table[_free_list]._prev = idx;
00282 }
00283
00284 _table[idx]._next = _free_list;
00285 _table[idx]._node = _not_found_value;
00286
00287 Is_True(Check(_free_list != idx),
00288 ("ID_MAP::Add_to_free_list: Must not introduce loop"));
00289
00290 _free_list = idx;
00291
00292 }
00293
00294 void Enlarge(void);
00295
00296 void Remove_from_free_list(const mINT32 idx)
00297 {
00298 Is_Trace(_tracing && _verbose,
00299 (TFile, "ID_MAP::Remove_from_free_list(%d)\n", idx));
00300 Is_True(Check(_table[idx]._node == _not_found_value),
00301 ("ID_MAP::Remove_from_free_list: Node must be free: %ld", idx));
00302
00303 if (_free_list == idx) {
00304 _free_list = _table[idx]._next;
00305 Is_True(Check(_free_list != idx),
00306 ("ID_MAP::Remove_from_free_list: Inconsistent free list: %lu",
00307 _free_list));
00308 Is_True(Check(_table[idx]._node == _not_found_value),
00309 ("ID_MAP::Remove_from_free_list: Node must be free: %ld", idx));
00310 }
00311 else {
00312 Is_True(Check(_table[idx]._prev != -1),
00313 ("ID_MAP::Remove_from_free_list: Inconsistent free list"));
00314 Is_True(Check(_table[idx]._next != idx),
00315 ("ID_MAP::Remove_from_free_list: Loop in free list : %ld",
00316 idx));
00317 _table[_table[idx]._prev]._next = _table[idx]._next;
00318 }
00319 if (_table[idx]._next != -1) {
00320 _table[_table[idx]._next]._prev = _table[idx]._prev;
00321 _table[idx]._next = -1;
00322 }
00323 }
00324
00325 mINT32 Alloc_from_free_list(void)
00326 {
00327 Is_Trace(_tracing && _verbose,
00328 (TFile, "ID_MAP::Alloc_from_free_list()..."));
00329 Is_True(_free_list != -1,
00330 ("ID_MAP::Displace: free list must be nonempty; %lu / %lu",
00331 _num_entries, _table_size));
00332 mINT32 idx = _free_list;
00333
00334 Is_True(_table[_free_list]._node == _not_found_value,
00335 ("ID_MAP::Alloc_from_free_list: free list inconsistency"));
00336
00337 _free_list = _table[_free_list]._next;
00338
00339 Is_True(Check(idx != _free_list),
00340 ("ID_MAP::Alloc_from_free_list: loop in free list"));
00341
00342 Is_True(_table[_free_list]._node == _not_found_value,
00343 ("ID_MAP:Alloc_from_free_list: free list inconsistency"));
00344
00345 Is_Trace(_tracing && _verbose,
00346 (TFile, " returning %d\n", idx));
00347 return idx;
00348 }
00349
00350 BOOL Check(BOOL cond) const
00351 {
00352 if (!cond)
00353 Print(TFile);
00354 return cond;
00355 }
00356
00357 void Verify(void) const
00358 {
00359 #ifdef DEBUG_ID_MAP
00360 for (mINT32 idx = 0; idx < _table_size; idx++) {
00361 _table[idx]._state =
00362 ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE>::IMHE_UNKNOWN;
00363 }
00364 for (idx = _free_list; idx != -1; idx = _table[idx]._next) {
00365 Is_True(Check(_table[idx]._state ==
00366 ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE>::IMHE_UNKNOWN),
00367 ("ID_MAP::Verify: Loop in free list"));
00368 _table[idx]._state =
00369 ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE>::IMHE_FREE;
00370 }
00371 for (idx = 0; idx < _table_size; idx++) {
00372 if (_table[idx]._state !=
00373 ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE>::IMHE_FREE) {
00374
00375
00376 Is_True(Check(idx == Entry_lookup(_table[idx]._key)),
00377 ("ID_MAP::Verify: Dangling node: idx == %ld", idx));
00378 _table[idx]._state =
00379 ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE>::IMHE_USED;
00380 }
00381 }
00382 #endif // DEBUG_ID_MAP
00383 }
00384
00385 mINT32 Entry_lookup(KEY_TYPE) const;
00386
00387 public:
00388 ID_MAP(UINT32 initial_capacity,
00389 NODE_TYPE not_found_value,
00390 MEM_POOL *pool,
00391 BOOL tracing);
00392 ~ID_MAP(void);
00393
00394 void Init(void);
00395 void Init(UINT32);
00396
00397 NODE_TYPE Lookup(KEY_TYPE) const;
00398
00399 void Insert(KEY_TYPE, NODE_TYPE);
00400
00401 void Delete(KEY_TYPE);
00402
00403 void Print(FILE *) const;
00404 };
00405
00406
00407
00408
00409 template <class KEY_TYPE>
00410 UINT64 Key_as_llu(const KEY_TYPE k)
00411 {
00412 UINT64 llu;
00413
00414 switch (sizeof(k))
00415 {
00416 case 1:
00417 llu = *(UINT8 *)&k;
00418 break;
00419 case 2:
00420 llu = *(UINT16 *)&k;
00421 break;
00422 case 4:
00423 llu = *(UINT32 *)&k;
00424 break;
00425 default:
00426 llu = *(UINT64 *)&k;
00427 break;
00428 }
00429 return llu;
00430 }
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440 template <class NODE_TYPE, class KEY_TYPE>
00441 ID_MAP<NODE_TYPE, KEY_TYPE>::ID_MAP(const UINT32 init_capacity,
00442 const NODE_TYPE not_found_value,
00443 MEM_POOL *const pool,
00444 const BOOL tracing) :
00445 _not_found_value(not_found_value),
00446 _pool(pool),
00447 _tracing(tracing),
00448 _verbose(FALSE),
00449 _num_entries(0),
00450 _constructed(FALSE)
00451 {
00452 _table = NULL;
00453 _table_size = Size(init_capacity);
00454 }
00455
00456 template <class NODE_TYPE, class KEY_TYPE> void
00457 ID_MAP<NODE_TYPE, KEY_TYPE>::Alloc_table_space(UINT32 table_size)
00458 {
00459 if (_table == NULL) {
00460 if (table_size < MIN_TABLE_SIZE) {
00461 table_size = MIN_TABLE_SIZE;
00462 }
00463 _table_size = table_size;
00464
00465 _table = (ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE> *)
00466 MEM_POOL_Alloc(_pool,
00467 (table_size *
00468 sizeof(ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE>)));
00469 }
00470 else {
00471
00472
00473 if (_table_size < table_size) {
00474 _table = (ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE> *)
00475 MEM_POOL_Realloc(_pool,
00476 _table,
00477 _table_size *
00478 sizeof(ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE>),
00479 table_size *
00480 sizeof(ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE>));
00481 _table_size = table_size;
00482 }
00483 }
00484
00485 if (_table == NULL) ErrMsg(EC_No_Mem, "ID_MAP::ID_MAP");
00486
00487 Is_Trace(_tracing,
00488 (TFile, "ID_MAP::ID_MAP: allocated %u entries\n",
00489 _table_size));
00490 }
00491
00492 template <class NODE_TYPE, class KEY_TYPE> void
00493 ID_MAP<NODE_TYPE, KEY_TYPE>::Initialize_table(void)
00494 {
00495
00496 _free_list = 0;
00497 for (mINT32 i = 0; i < _table_size; i++) {
00498 _table[i]._node = _not_found_value;
00499 _table[i]._prev = i - 1;
00500 _table[i]._next = i + 1;
00501 }
00502 _table[_table_size - 1]._next = -1;
00503 }
00504
00505 template <class NODE_TYPE, class KEY_TYPE> void
00506 ID_MAP<NODE_TYPE, KEY_TYPE>::Init(UINT32 capacity)
00507 {
00508 Alloc_table_space(Size(capacity));
00509 Initialize_table();
00510 }
00511
00512 template <class NODE_TYPE, class KEY_TYPE> void
00513 ID_MAP<NODE_TYPE, KEY_TYPE>::Init(void)
00514 {
00515 _constructed = TRUE;
00516
00517 Alloc_table_space(_table_size);
00518 Initialize_table();
00519 }
00520
00521 template <class X>
00522 inline void Id_map_fprint(FILE *fp, X *x)
00523 {
00524 x->Print(fp);
00525 }
00526
00527 inline void Id_map_fprint(FILE *fp, IDTYPE *x)
00528 {
00529 fprintf(fp, "%d\n", *x);
00530 }
00531
00532 inline void Id_map_fprint(FILE *fp, INT x)
00533 {
00534 fprintf(fp, "%d\n", x);
00535 }
00536
00537 template <class NODE_TYPE, class KEY_TYPE> void
00538 ID_MAP<NODE_TYPE, KEY_TYPE>::Print(FILE *fp) const
00539 {
00540 fprintf(fp, "Number of entries: %u\n", _num_entries);
00541 fprintf(fp, "Free list --> %d\n", _free_list);
00542
00543 for (mINT32 i = 0; i < _table_size; i++) {
00544 fprintf(fp, "ID_MAP table[%d] : ", i);
00545 if (_table[i]._node != _not_found_value) {
00546 fprintf(fp, "[H(%llu)=%d; %d -->] ",
00547 Key_as_llu(_table[i]._key),
00548 Hash(_table[i]._key, _table_size),
00549 _table[i]._next);
00550 Id_map_fprint(fp, _table[i]._node);
00551 }
00552 else {
00553 fprintf(fp, "<-- %d, 0x%lx, %d -->\n",
00554 _table[i]._prev, (INTPTR) _table[i]._node, _table[i]._next);
00555 }
00556 }
00557 }
00558
00559 template <class NODE_TYPE, class KEY_TYPE>
00560 ID_MAP<NODE_TYPE, KEY_TYPE>::~ID_MAP(void)
00561 {
00562 if (_constructed) {
00563 Verify();
00564 if (_tracing) {
00565
00566 Is_Trace(TRUE, (TFile, "--- ID_MAP pre-destruct table dump:\n"));
00567 Print(TFile);
00568
00569
00570 }
00571 _constructed = FALSE;
00572 }
00573 }
00574
00575 template <class NODE_TYPE, class KEY_TYPE> void
00576 ID_MAP<NODE_TYPE, KEY_TYPE>::Enlarge(void)
00577 {
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593 mINT32 first_new_idx = _table_size;
00594 UINT32 save_num_entries = _num_entries;
00595
00596 mINT32 i;
00597
00598 Is_Trace(_tracing, (TFile, "ID_MAP enlarging from size %d\n",
00599 _table_size));
00600 Is_Trace_cmd(_tracing && _verbose, Print(TFile));
00601
00602 UINT32 new_table_size = (UINT32) ceil(GROWTH_FACTOR * (double) _table_size);
00603
00604 _table = (ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE> *)
00605 MEM_POOL_Realloc(_pool,
00606 _table,
00607 _table_size *
00608 sizeof(ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE>),
00609 new_table_size *
00610 sizeof(ID_MAP_HASH_ENTRY<NODE_TYPE, KEY_TYPE>));
00611
00612 if (_table == NULL) ErrMsg(EC_No_Mem, "ID_MAP::Enlarge");
00613
00614 _table_size = new_table_size;
00615
00616
00617
00618 for (i = _table_size - 1; i >= first_new_idx; i--) {
00619 _table[i]._next = -1;
00620 _table[i]._node = _not_found_value;
00621 }
00622
00623 for (; i >= 0; i--) {
00624 _table[i]._next = -1;
00625 }
00626
00627
00628
00629 for (i = 0; i < first_new_idx; i++) {
00630 if (_table[i]._node != _not_found_value) {
00631 mINT32 h = Hash(_table[i]._key, _table_size);
00632 if (_table[h]._next == -1) {
00633 Is_True(Check(save_num_entries != 0),
00634 ("ID_MAP::Enlarge: Bad save_num_entries logic"));
00635 --save_num_entries;
00636 _table[h]._next = 0;
00637 }
00638 }
00639 }
00640
00641
00642
00643
00644 for (i = 0; save_num_entries > 0; i++) {
00645 Is_True(i < _table_size,
00646 ("ID_MAP::Enlarge: Bad logic"));
00647 if (_table[i]._next == -1) {
00648 Is_True(Check(save_num_entries != 0),
00649 ("ID_MAP::Enlarge: Bad save_num_entries logic"));
00650 --save_num_entries;
00651 _table[i]._next = 0;
00652 }
00653 }
00654
00655
00656 i = _table_size;
00657 mINT32 unocc_head = -1;
00658
00659 while (TRUE) {
00660 --i;
00661 if (_table[i]._next == -1) {
00662 unocc_head = i;
00663 break;
00664 }
00665 Is_True(i > 0, ("ID_MAP::Enlarge: Bad logic"));
00666 }
00667
00668
00669
00670 while (i > 0) {
00671 --i;
00672 if (_table[i]._next == -1) {
00673 _table[i]._next = -unocc_head - 2;
00674 unocc_head = i;
00675 }
00676 }
00677
00678
00679
00680 mINT32 unocc = unocc_head;
00681 while (_table[unocc]._node != _not_found_value) {
00682 Is_True(0 <= unocc && unocc < _table_size,
00683 ("ID_MAP::Enlarge: Bad logic"));
00684 unocc = -_table[unocc]._next - 2;
00685 }
00686
00687 _free_list = -1;
00688
00689
00690
00691 for (i = _table_size - 1; i >= 0; i--) {
00692 if (_table[i]._next == 0) {
00693
00694 if (_table[i]._node != _not_found_value) {
00695 FmtAssert(unocc != -1,
00696 ("ID_MAP::Enlarge: Insufficient unoccupied entries.\n"
00697 " GROWTH_FACTOR too small WRT "
00698 "CAPACITY_FACTOR"));
00699 Is_True(Check(0 <= unocc && unocc < _table_size &&
00700 _table[unocc]._node == _not_found_value),
00701 ("ID_MAP::Enlarge: Bad logic"));
00702 _table[unocc]._node = _table[i]._node;
00703 _table[unocc]._key = _table[i]._key;
00704 do {
00705 Is_True(Check(0 <= unocc && unocc < _table_size),
00706 ("ID_MAP::Enlarge: Bad logic"));
00707 unocc = -_table[unocc]._next - 2;
00708 } while (_table[unocc]._node != _not_found_value);
00709 }
00710 Add_to_free_list(i);
00711 }
00712 }
00713
00714 save_num_entries = _num_entries;
00715
00716
00717
00718
00719 for (i = unocc_head; i != -1; i = unocc) {
00720 KEY_TYPE key = _table[i]._key;
00721 NODE_TYPE node = _table[i]._node;
00722
00723 unocc = -_table[i]._next - 2;
00724
00725
00726 Add_to_free_list(i);
00727
00728 if (node != _not_found_value) {
00729
00730 _num_entries = 0;
00731 Insert(key, node);
00732 }
00733 }
00734
00735 _num_entries = save_num_entries;
00736
00737 Is_Trace(_tracing, (TFile, "ID_MAP::Enlarge: Starting verification\n"));
00738 Verify();
00739 Is_Trace(_tracing, (TFile, "ID_MAP::Enlarge: Verification passed\n"));
00740 }
00741
00742 template <class NODE_TYPE, class KEY_TYPE> void
00743 ID_MAP<NODE_TYPE, KEY_TYPE>::Insert(const KEY_TYPE key,
00744 const NODE_TYPE node)
00745 {
00746 Is_Trace(_tracing && _verbose,
00747 (TFile, "ID_MAP::Insert(%llu, ...) ...\n", Key_as_llu(key)));
00748
00749 if (_num_entries + 1 > Capacity(_table_size)) {
00750 Is_Trace(_tracing,
00751 (TFile, "Enlarging: will have %u entries\n"
00752 " table size: %u\n"
00753 " table capacity: %u\n",
00754 _num_entries + 1, _table_size,
00755 Capacity(_table_size)));
00756 Enlarge();
00757 Is_True(_num_entries <= Capacity(_table_size),
00758 ("ID_MAP::Insert: Enlarge didn't get enough capacity"));
00759 }
00760 else {
00761 Is_Trace(_tracing && _verbose,
00762 (TFile, "Not enlarging: Capacity(%u) = %u\n",
00763 _table_size, Capacity(_table_size)));
00764 }
00765
00766 mINT32 idx = Hash(key, _table_size);
00767
00768 Is_Trace(_tracing && _verbose,
00769 (TFile, " ID_MAP::Insert: inserting at %d\n", idx));
00770
00771 if (_table[idx]._node != _not_found_value) {
00772 Is_True(Check(_table[idx]._next != _free_list),
00773 ("ID_MAP::Insert: inconsistent relocation"));
00774
00775 mINT32 displaced = Alloc_from_free_list();
00776
00777 Is_Trace(_tracing && _verbose,
00778 (TFile, " displacing [H(%llu)=%d; %d] to %d\n",
00779 Key_as_llu(_table[idx]._key),
00780 Hash(_table[idx]._key, _table_size),
00781 _table[idx]._next, displaced));
00782
00783 _table[displaced]._node = _table[idx]._node;
00784 _table[displaced]._key = _table[idx]._key;
00785
00786 Is_True(Check(_table[idx]._next != displaced),
00787 ("ID_MAP::Insert: inconsistent relocation"));
00788
00789 _table[displaced]._next = _table[idx]._next;
00790
00791 Is_True(Check(idx != displaced),
00792 ("ID_MAP::Insert: inconsistent relocation"));
00793 Is_True(Check(displaced != _free_list),
00794 ("ID_MAP::Insert: Bug in Alloc_from_free_list"));
00795
00796 mINT32 temp_idx = Hash(_table[displaced]._key, _table_size);
00797 if (idx == temp_idx) {
00798
00799 _table[idx]._next = displaced;
00800 }
00801 else {
00802 _table[idx]._next = -1;
00803
00804
00805 while (temp_idx != -1 && _table[temp_idx]._next != idx) {
00806 temp_idx = _table[temp_idx]._next;
00807 }
00808
00809 #if Is_True_On
00810 if (temp_idx == -1 || _table[temp_idx]._next != idx) {
00811 fprintf(TFile, "Insert %llu at idx = %d (%d)\n",
00812 Key_as_llu(key), idx,
00813 Hash(key, _table_size));
00814 fprintf(TFile, " -> displaced = %d\n", displaced);
00815 fprintf(TFile, "start [H(%llu)=%d]\n",
00816 Key_as_llu(_table[displaced]._key),
00817 Hash(_table[displaced]._key, _table_size));
00818 }
00819 #endif
00820 Is_True(Check(temp_idx != -1 && _table[temp_idx]._next == idx),
00821 ("ID_MAP::Insert: displaced item not found in hash table."));
00822 FmtAssert(temp_idx != -1 && _table[temp_idx]._next == idx,
00823 ("ID_MAP::Insert: displaced item not found in hash table."));
00824
00825 _table[temp_idx]._next = displaced;
00826 }
00827 }
00828 else {
00829 Remove_from_free_list(idx);
00830 _table[idx]._next = -1;
00831 }
00832
00833 _table[idx]._node = node;
00834 _table[idx]._key = key;
00835 ++_num_entries;
00836 }
00837
00838
00839 template <class NODE_TYPE, class KEY_TYPE> void
00840 ID_MAP<NODE_TYPE, KEY_TYPE>::Delete(const KEY_TYPE key)
00841 {
00842 mINT32 idx = Hash(key, _table_size);
00843 mINT32 prev_idx = -1;
00844
00845 while (idx != -1 &&
00846 _table[idx]._node != _not_found_value &&
00847 _table[idx]._key != key) {
00848 prev_idx = idx;
00849 idx = _table[idx]._next;
00850 }
00851
00852 FmtAssert(idx != -1 && _table[idx]._node != _not_found_value,
00853 ("ID_MAP::Delete: item not found in hash table."));
00854
00855 if (prev_idx != -1) {
00856 _table[prev_idx]._next = _table[idx]._next;
00857 }
00858 else {
00859 mINT32 next_idx = _table[idx]._next;
00860 if (next_idx != -1) {
00861 _table[idx]._node = _table[next_idx]._node;
00862 _table[idx]._key = _table[next_idx]._key;
00863 _table[idx]._next = _table[next_idx]._next;
00864 idx = next_idx;
00865 }
00866 }
00867 Add_to_free_list(idx);
00868 --_num_entries;
00869 }
00870
00871
00872 template <class NODE_TYPE, class KEY_TYPE> NODE_TYPE
00873 ID_MAP<NODE_TYPE, KEY_TYPE>::Lookup(const KEY_TYPE key) const
00874 {
00875 mINT32 idx = Entry_lookup(key);
00876 if (idx == -1) {
00877 return _not_found_value;
00878 }
00879 else {
00880 return _table[idx]._node;
00881 }
00882 }
00883
00884 template <class NODE_TYPE, class KEY_TYPE> mINT32
00885 ID_MAP<NODE_TYPE, KEY_TYPE>::Entry_lookup(const KEY_TYPE key) const
00886 {
00887 mINT32 idx = Hash(key, _table_size);
00888
00889 #if Is_True_On
00890 mINT32 loopcheck = idx;
00891 #endif
00892
00893 while (idx != -1 &&
00894 _table[idx]._node != _not_found_value &&
00895 !(_table[idx]._key == key)) {
00896 idx = _table[idx]._next;
00897
00898 #if Is_True_On
00899 if (loopcheck != -1) {
00900 loopcheck = _table[loopcheck]._next;
00901 }
00902 if (loopcheck != -1) {
00903 loopcheck = _table[loopcheck]._next;
00904 }
00905 if (loopcheck != -1) {
00906 Is_True(Check(loopcheck != idx),
00907 ("ID_MAP::Lookup: loop in hash bucket %lu", idx));
00908 }
00909 #endif
00910 }
00911 if (idx == -1 || _table[idx]._node == _not_found_value) {
00912 return -1;
00913 }
00914 else {
00915 return idx;
00916 }
00917 }
00918
00919 }
00920
00921 #endif