HashTable.h (21043B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition Source Code is free software: you can redistribute it and/or modify 10 it under the terms of the GNU General Public License as published by 11 the Free Software Foundation, either version 3 of the License, or 12 (at your option) any later version. 13 14 Doom 3 BFG Edition Source Code is distributed in the hope that it will be useful, 15 but WITHOUT ANY WARRANTY; without even the implied warranty of 16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 17 GNU General Public License for more details. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA. 25 26 =========================================================================== 27 */ 28 29 #ifndef __HASHTABLE_H__ 30 #define __HASHTABLE_H__ 31 32 /* 33 ================================================================================================ 34 idHashNodeT is a generic node for a HashTable. It is specialized by the 35 StringHashNode and CStringHashNode template classes. 36 ================================================================================================ 37 */ 38 template< typename _key_, class _value_ > 39 class idHashNodeT { 40 public: 41 idHashNodeT() 42 : next( NULL ) { 43 } 44 45 idHashNodeT( const _key_ & key, const _value_ & value, idHashNodeT * next ) 46 : key( key ), 47 value( value ), 48 next( next ) { 49 } 50 51 static int GetHash( const _key_ & key, const int tableMask ) { 52 return key & tableMask; 53 } 54 55 static int Compare( const _key_ & key1, const _key_ & key2 ) { 56 if ( key1 < key2 ) { 57 return -1; 58 } else if ( key1 > key2 ) { 59 return 1; 60 } 61 return 0; 62 } 63 64 public: 65 _key_ key; 66 _value_ value; 67 idHashNodeT< _key_, _value_ > * next; 68 }; 69 70 /* 71 ================================================ 72 idHashNodeT is a HashNode that provides for partial 73 specialization for the HashTable, allowing the String class's Cmp function to be used 74 for inserting values in sorted order. 75 ================================================ 76 */ 77 template< class _value_ > 78 class idHashNodeT< idStr, _value_ > { 79 public: 80 idHashNodeT( const idStr & key, const _value_ & value, idHashNodeT * next ) 81 : key( key ), 82 value( value ), 83 next( next ) { 84 } 85 86 static int GetHash( const idStr & key, const int tableMask ) { 87 return ( idStr::Hash( key ) & tableMask ); 88 } 89 90 static int Compare( const idStr & key1, const idStr & key2 ) { 91 return idStr::Icmp( key1, key2 ); 92 } 93 94 public: 95 idStr key; 96 _value_ value; 97 idHashNodeT< idStr, _value_ > * next; 98 }; 99 100 /* 101 ================================================ 102 idHashNodeT is a HashNode that provides for a partial specialization 103 for the HashTable, allowing the String class's Cmp function to 104 be used for inserting values in sorted order. It also ensures that a copy of the the key is 105 stored in a String (to more closely model the original implementation of the HashTable). 106 ================================================ 107 */ 108 template< class _value_ > 109 class idHashNodeT< const char*, _value_ > { 110 public: 111 idHashNodeT( const char* const & key, const _value_ & value, idHashNodeT * next ) 112 : key( key ), 113 value( value ), 114 next( next ) { 115 } 116 117 static int GetHash( const char* const & key, const int tableMask ) { 118 return ( idStr::Hash( key ) & tableMask ); 119 } 120 121 static int Compare( const char* const & key1, const char* const & key2 ) { 122 return idStr::Icmp( key1, key2 ); 123 } 124 125 public: 126 idStr key; // char * keys must still get stored in an idStr 127 _value_ value; 128 idHashNodeT< const char *, _value_ > * next; 129 }; 130 131 /* 132 ================================================ 133 idHashTableT is a general implementation of a hash table data type. It is 134 slower than the HashIndex, but it can also be used for LinkedLists and other data structures, 135 rather than just indexes and arrays. 136 137 It uses an arbitrary key type. For String keys, use the StringHashTable template 138 specialization. 139 ================================================ 140 */ 141 template< typename _key_, class _value_ > 142 class idHashTableT { 143 public: 144 idHashTableT( const int tableSize = 256 ); 145 idHashTableT( const idHashTableT & other ); 146 ~idHashTableT(); 147 148 size_t Allocated() const; 149 size_t Size() const; 150 151 _value_ & Set( const _key_ & key, const _value_ & value ); 152 153 bool Get( const _key_ & key, _value_ ** value = NULL ); 154 bool Get( const _key_ & key, const _value_ ** value = NULL ) const; 155 156 bool Remove( const _key_ & key ); 157 158 void Clear(); 159 void DeleteContents(); 160 161 int Num() const; 162 _value_ * GetIndex( const int index ) const; 163 bool GetIndexKey( const int index, _key_ & key ) const; 164 165 int GetSpread() const; 166 167 idHashTableT & operator=( const idHashTableT & other ); 168 169 protected: 170 void Copy( const idHashTableT & other ); 171 172 private: 173 typedef idHashNodeT< _key_, _value_ > hashnode_t; 174 175 hashnode_t ** heads; 176 177 int tableSize; 178 int numEntries; 179 int tableSizeMask; 180 }; 181 182 /* 183 ======================== 184 idHashTableT<_key_,_value_>::idHashTableT 185 ======================== 186 */ 187 template< typename _key_, class _value_ > 188 ID_INLINE idHashTableT<_key_,_value_>::idHashTableT( const int tableSize ) { 189 assert( idMath::IsPowerOfTwo( tableSize ) ); 190 191 this->tableSize = tableSize; 192 193 heads = new (TAG_IDLIB_HASH) hashnode_t *[ tableSize ]; 194 memset( heads, 0, sizeof( hashnode_t * ) * tableSize ); 195 196 numEntries = 0; 197 tableSizeMask = tableSize - 1; 198 } 199 200 /* 201 ======================== 202 idHashTableT<_key_,_value_>::idHashTableT 203 ======================== 204 */ 205 template< typename _key_, class _value_ > 206 ID_INLINE idHashTableT<_key_,_value_>::idHashTableT( const idHashTableT & other ) { 207 Copy( other ); 208 } 209 210 /* 211 ======================== 212 idHashTableT<_key_,_value_>::~idHashTableT 213 ======================== 214 */ 215 template< typename _key_, class _value_ > 216 ID_INLINE idHashTableT<_key_,_value_>::~idHashTableT() { 217 Clear(); 218 delete [] heads; 219 heads = NULL; 220 tableSize = 0; 221 tableSizeMask = 0; 222 numEntries = 0; 223 } 224 225 /* 226 ======================== 227 idHashTableT<_key_,_value_>::Allocated 228 ======================== 229 */ 230 template< typename _key_, class _value_ > 231 ID_INLINE size_t idHashTableT<_key_,_value_>::Allocated() const { 232 return sizeof( heads ) * tableSize + sizeof( hashnode_t* ) * numEntries; 233 } 234 235 /* 236 ======================== 237 idHashTableT<_key_,_value_>::Size 238 ======================== 239 */ 240 template< typename _key_, class _value_ > 241 ID_INLINE size_t idHashTableT<_key_,_value_>::Size() const { 242 return sizeof( idHashTableT ) + sizeof( heads )* tableSize + sizeof( hashnode_t* ) * numEntries; 243 } 244 245 /* 246 ======================== 247 idHashTableT<_key_,_value_>::Set 248 ======================== 249 */ 250 template< typename _key_, class _value_ > 251 ID_INLINE _value_ & idHashTableT<_key_,_value_>::Set( const _key_ & key, const _value_ & value ) { 252 // insert sorted 253 int hash = hashnode_t::GetHash( key, tableSizeMask ); 254 hashnode_t ** nextPtr = &(heads[ hash ] ); 255 hashnode_t * node = * nextPtr; 256 for ( ; 257 node != NULL; 258 nextPtr = &(node->next), node = *nextPtr ) { 259 int s = node->Compare( node->key, key ); 260 if ( s == 0 ) { 261 // return existing hashed item 262 node->value = value; 263 return node->value; 264 } 265 if ( s > 0 ) { 266 break; 267 } 268 } 269 270 numEntries++; 271 272 *nextPtr = new (TAG_IDLIB_HASH) hashnode_t( key, value, heads[ hash ] ); 273 (*nextPtr)->next = node; 274 return (*nextPtr)->value; 275 } 276 277 /* 278 ======================== 279 idHashTableT<_key_,_value_>::Get 280 ======================== 281 */ 282 template< typename _key_, class _value_ > 283 ID_INLINE bool idHashTableT<_key_,_value_>::Get( const _key_ & key, _value_ ** value ) { 284 int hash = hashnode_t::GetHash( key, tableSizeMask ); 285 hashnode_t * node = heads[ hash ]; 286 for ( ; node != NULL; node = node->next ) { 287 int s = node->Compare( node->key, key ); 288 if ( s == 0 ) { 289 if ( value ) { 290 *value = &node->value; 291 } 292 return true; 293 } 294 if ( s > 0 ) { 295 break; 296 } 297 } 298 if ( value ) { 299 *value = NULL; 300 } 301 return false; 302 } 303 304 /* 305 ======================== 306 idHashTableT<_key_,_value_>::Get 307 ======================== 308 */ 309 template< typename _key_, class _value_ > 310 ID_INLINE bool idHashTableT<_key_,_value_>::Get( const _key_ & key, const _value_ ** value ) const { 311 int hash = hashnode_t::GetHash( key, tableSizeMask ); 312 hashnode_t * node = heads[ hash ]; 313 for ( ; node != NULL; node = node->next ) { 314 int s = node->Compare( node->key, key ); 315 if ( s == 0 ) { 316 if ( value ) { 317 *value = &node->value; 318 } 319 return true; 320 } 321 if ( s > 0 ) { 322 break; 323 } 324 } 325 if ( value ) { 326 *value = NULL; 327 } 328 return false; 329 } 330 331 /* 332 ======================== 333 idHashTableT<_key_,_value_>::GetIndex 334 ======================== 335 */ 336 template< typename _key_, class _value_ > 337 ID_INLINE _value_ * idHashTableT<_key_,_value_>::GetIndex( const int index ) const { 338 if ( index < 0 || index > numEntries ) { 339 assert( 0 ); 340 return NULL; 341 } 342 343 int count = 0; 344 for ( int i = 0; i < tableSize; i++ ) { 345 for ( hashnode_t * node = heads[ i ]; node != NULL; node = node->next ) { 346 if ( count == index ) { 347 return &node->value; 348 } 349 count++; 350 } 351 } 352 return NULL; 353 } 354 355 /* 356 ======================== 357 idHashTableT<_key_,_value_>::GetIndexKey 358 ======================== 359 */ 360 template< typename _key_, class _value_ > 361 ID_INLINE bool idHashTableT<_key_,_value_>::GetIndexKey( const int index, _key_ & key ) const { 362 if ( index < 0 || index > numEntries ) { 363 assert( 0 ); 364 return false; 365 } 366 367 int count = 0; 368 for ( int i = 0; i < tableSize; i++ ) { 369 for ( hashnode_t * node = heads[ i ]; node != NULL; node = node->next ) { 370 if ( count == index ) { 371 key = node->key; 372 return true; 373 } 374 count++; 375 } 376 } 377 return false; 378 } 379 380 /* 381 ======================== 382 idHashTableT<_key_,_value_>::Remove 383 ======================== 384 */ 385 template< typename _key_, class _value_ > 386 ID_INLINE bool idHashTableT<_key_,_value_>::Remove( const _key_ & key ) { 387 int hash = hashnode_t::GetHash( key, tableSizeMask ); 388 hashnode_t ** head = &heads[ hash ]; 389 if ( *head ) { 390 hashnode_t * prev = NULL; 391 hashnode_t * node = *head; 392 for ( ; node != NULL; prev = node, node = node->next ) { 393 if ( node->key == key ) { 394 if ( prev ) { 395 prev->next = node->next; 396 } else { 397 *head = node->next; 398 } 399 400 delete node; 401 numEntries--; 402 return true; 403 } 404 } 405 } 406 return false; 407 } 408 409 /* 410 ======================== 411 idHashTableT<_key_,_value_>::Clear 412 ======================== 413 */ 414 template< typename _key_, class _value_ > 415 ID_INLINE void idHashTableT<_key_,_value_>::Clear() { 416 for ( int i = 0; i < tableSize; i++ ) { 417 hashnode_t * next = heads[ i ]; 418 while ( next != NULL ) { 419 hashnode_t * node = next; 420 next = next->next; 421 delete node; 422 } 423 heads[ i ] = NULL; 424 } 425 numEntries = 0; 426 } 427 428 /* 429 ======================== 430 idHashTableT<_key_,_value_>::DeleteContents 431 ======================== 432 */ 433 template< typename _key_, class _value_ > 434 ID_INLINE void idHashTableT<_key_,_value_>::DeleteContents() { 435 for ( int i = 0; i < tableSize; i++ ) { 436 hashnode_t * next = heads[ i ]; 437 while ( next != NULL ) { 438 hashnode_t * node = next; 439 next = next->next; 440 delete node->value; 441 delete node; 442 } 443 heads[ i ] = NULL; 444 } 445 numEntries = 0; 446 } 447 448 /* 449 ======================== 450 idHashTableT<_key_,_value_>::Num 451 ======================== 452 */ 453 template< typename _key_, class _value_ > 454 ID_INLINE int idHashTableT<_key_,_value_>::Num() const { 455 return numEntries; 456 } 457 458 /* 459 ======================== 460 idHashTableT<_key_,_value_>::GetSpread 461 ======================== 462 */ 463 template< typename _key_, class _value_ > 464 ID_INLINE int idHashTableT<_key_,_value_>::GetSpread() const { 465 if ( !numEntries ) { 466 return 100; 467 } 468 469 int average = numEntries / tableSize; 470 int error = 0; 471 for ( int i = 0; i < tableSize; i++ ) { 472 int numItems = 0; 473 for ( hashnode_t * node = heads[ i ]; node != NULL; node = node->next ) { 474 numItems++; 475 } 476 int e = abs( numItems - average ); 477 if ( e > 1 ) { 478 error += e - 1; 479 } 480 } 481 return 100 - ( error * 100 / numEntries ); 482 } 483 484 /* 485 ======================== 486 idHashTableT<_key_,_value_>::operator= 487 ======================== 488 */ 489 template< typename _key_, class _value_ > 490 ID_INLINE idHashTableT< _key_, _value_ > & idHashTableT<_key_,_value_>::operator=( const idHashTableT & other ) { 491 Copy( other ); 492 return *this; 493 } 494 495 /* 496 ======================== 497 idHashTableT<_key_,_value_>::Copy 498 ======================== 499 */ 500 template< typename _key_, class _value_ > 501 ID_INLINE void idHashTableT<_key_,_value_>::Copy( const idHashTableT & other ) { 502 if ( &other == this ) { 503 return; 504 } 505 assert( other.tableSize > 0 ); 506 507 tableSize = other.tableSize; 508 heads = new (TAG_IDLIB_HASH) hashnode_t *[ tableSize ]; 509 numEntries = other.numEntries; 510 tableSizeMask = other.tableSizeMask; 511 512 for ( int i = 0; i < tableSize; i++ ) { 513 if ( !other.heads[ i ] ) { 514 heads[ i ] = NULL; 515 continue; 516 } 517 hashnode_t ** prev = & heads[ i ]; 518 for ( hashnode_t * node = other.heads[ i ]; node != NULL; node = node->next ) { 519 *prev = new (TAG_IDLIB_HASH) hashnode_t( node->key, node->value, NULL ); 520 prev = &( *prev )->next; 521 } 522 } 523 } 524 525 /* 526 =============================================================================== 527 528 General hash table. Slower than idHashIndex but it can also be used for 529 linked lists and other data structures than just indexes or arrays. 530 531 =============================================================================== 532 */ 533 534 template< class Type > 535 class idHashTable { 536 public: 537 idHashTable( int newtablesize = 256 ); 538 idHashTable( const idHashTable<Type> &map ); 539 ~idHashTable(); 540 541 // returns total size of allocated memory 542 size_t Allocated() const; 543 // returns total size of allocated memory including size of hash table type 544 size_t Size() const; 545 546 void Set( const char *key, Type &value ); 547 bool Get( const char *key, Type **value = NULL ) const; 548 bool Remove( const char *key ); 549 550 void Clear(); 551 void DeleteContents(); 552 553 // the entire contents can be itterated over, but note that the 554 // exact index for a given element may change when new elements are added 555 int Num() const; 556 Type * GetIndex( int index ) const; 557 558 int GetSpread() const; 559 560 private: 561 struct hashnode_s { 562 idStr key; 563 Type value; 564 hashnode_s *next; 565 566 hashnode_s( const idStr &k, Type v, hashnode_s *n ) : key( k ), value( v ), next( n ) {}; 567 hashnode_s( const char *k, Type v, hashnode_s *n ) : key( k ), value( v ), next( n ) {}; 568 }; 569 570 hashnode_s ** heads; 571 572 int tablesize; 573 int numentries; 574 int tablesizemask; 575 576 int GetHash( const char *key ) const; 577 }; 578 579 /* 580 ================ 581 idHashTable<Type>::idHashTable 582 ================ 583 */ 584 template< class Type > 585 ID_INLINE idHashTable<Type>::idHashTable( int newtablesize ) { 586 587 assert( idMath::IsPowerOfTwo( newtablesize ) ); 588 589 tablesize = newtablesize; 590 assert( tablesize > 0 ); 591 592 heads = new (TAG_IDLIB_HASH) hashnode_s *[ tablesize ]; 593 memset( heads, 0, sizeof( *heads ) * tablesize ); 594 595 numentries = 0; 596 597 tablesizemask = tablesize - 1; 598 } 599 600 /* 601 ================ 602 idHashTable<Type>::idHashTable 603 ================ 604 */ 605 template< class Type > 606 ID_INLINE idHashTable<Type>::idHashTable( const idHashTable<Type> &map ) { 607 int i; 608 hashnode_s *node; 609 hashnode_s **prev; 610 611 assert( map.tablesize > 0 ); 612 613 tablesize = map.tablesize; 614 heads = new (TAG_IDLIB_HASH) hashnode_s *[ tablesize ]; 615 numentries = map.numentries; 616 tablesizemask = map.tablesizemask; 617 618 for( i = 0; i < tablesize; i++ ) { 619 if ( !map.heads[ i ] ) { 620 heads[ i ] = NULL; 621 continue; 622 } 623 624 prev = &heads[ i ]; 625 for( node = map.heads[ i ]; node != NULL; node = node->next ) { 626 *prev = new (TAG_IDLIB_HASH) hashnode_s( node->key, node->value, NULL ); 627 prev = &( *prev )->next; 628 } 629 } 630 } 631 632 /* 633 ================ 634 idHashTable<Type>::~idHashTable<Type> 635 ================ 636 */ 637 template< class Type > 638 ID_INLINE idHashTable<Type>::~idHashTable() { 639 Clear(); 640 delete[] heads; 641 } 642 643 /* 644 ================ 645 idHashTable<Type>::Allocated 646 ================ 647 */ 648 template< class Type > 649 ID_INLINE size_t idHashTable<Type>::Allocated() const { 650 return sizeof( heads ) * tablesize + sizeof( *heads ) * numentries; 651 } 652 653 /* 654 ================ 655 idHashTable<Type>::Size 656 ================ 657 */ 658 template< class Type > 659 ID_INLINE size_t idHashTable<Type>::Size() const { 660 return sizeof( idHashTable<Type> ) + sizeof( heads ) * tablesize + sizeof( *heads ) * numentries; 661 } 662 663 /* 664 ================ 665 idHashTable<Type>::GetHash 666 ================ 667 */ 668 template< class Type > 669 ID_INLINE int idHashTable<Type>::GetHash( const char *key ) const { 670 return ( idStr::Hash( key ) & tablesizemask ); 671 } 672 673 /* 674 ================ 675 idHashTable<Type>::Set 676 ================ 677 */ 678 template< class Type > 679 ID_INLINE void idHashTable<Type>::Set( const char *key, Type &value ) { 680 hashnode_s *node, **nextPtr; 681 int hash, s; 682 683 hash = GetHash( key ); 684 for( nextPtr = &(heads[hash]), node = *nextPtr; node != NULL; nextPtr = &(node->next), node = *nextPtr ) { 685 s = node->key.Cmp( key ); 686 if ( s == 0 ) { 687 node->value = value; 688 return; 689 } 690 if ( s > 0 ) { 691 break; 692 } 693 } 694 695 numentries++; 696 697 *nextPtr = new (TAG_IDLIB_HASH) hashnode_s( key, value, heads[ hash ] ); 698 (*nextPtr)->next = node; 699 } 700 701 /* 702 ================ 703 idHashTable<Type>::Get 704 ================ 705 */ 706 template< class Type > 707 ID_INLINE bool idHashTable<Type>::Get( const char *key, Type **value ) const { 708 hashnode_s *node; 709 int hash, s; 710 711 hash = GetHash( key ); 712 for( node = heads[ hash ]; node != NULL; node = node->next ) { 713 s = node->key.Cmp( key ); 714 if ( s == 0 ) { 715 if ( value ) { 716 *value = &node->value; 717 } 718 return true; 719 } 720 if ( s > 0 ) { 721 break; 722 } 723 } 724 725 if ( value ) { 726 *value = NULL; 727 } 728 729 return false; 730 } 731 732 /* 733 ================ 734 idHashTable<Type>::GetIndex 735 736 the entire contents can be itterated over, but note that the 737 exact index for a given element may change when new elements are added 738 ================ 739 */ 740 template< class Type > 741 ID_INLINE Type *idHashTable<Type>::GetIndex( int index ) const { 742 hashnode_s *node; 743 int count; 744 int i; 745 746 if ( ( index < 0 ) || ( index > numentries ) ) { 747 assert( 0 ); 748 return NULL; 749 } 750 751 count = 0; 752 for( i = 0; i < tablesize; i++ ) { 753 for( node = heads[ i ]; node != NULL; node = node->next ) { 754 if ( count == index ) { 755 return &node->value; 756 } 757 count++; 758 } 759 } 760 761 return NULL; 762 } 763 764 /* 765 ================ 766 idHashTable<Type>::Remove 767 ================ 768 */ 769 template< class Type > 770 ID_INLINE bool idHashTable<Type>::Remove( const char *key ) { 771 hashnode_s **head; 772 hashnode_s *node; 773 hashnode_s *prev; 774 int hash; 775 776 hash = GetHash( key ); 777 head = &heads[ hash ]; 778 if ( *head ) { 779 for( prev = NULL, node = *head; node != NULL; prev = node, node = node->next ) { 780 if ( node->key == key ) { 781 if ( prev ) { 782 prev->next = node->next; 783 } else { 784 *head = node->next; 785 } 786 787 delete node; 788 numentries--; 789 return true; 790 } 791 } 792 } 793 794 return false; 795 } 796 797 /* 798 ================ 799 idHashTable<Type>::Clear 800 ================ 801 */ 802 template< class Type > 803 ID_INLINE void idHashTable<Type>::Clear() { 804 int i; 805 hashnode_s *node; 806 hashnode_s *next; 807 808 for( i = 0; i < tablesize; i++ ) { 809 next = heads[ i ]; 810 while( next != NULL ) { 811 node = next; 812 next = next->next; 813 delete node; 814 } 815 816 heads[ i ] = NULL; 817 } 818 819 numentries = 0; 820 } 821 822 /* 823 ================ 824 idHashTable<Type>::DeleteContents 825 ================ 826 */ 827 template< class Type > 828 ID_INLINE void idHashTable<Type>::DeleteContents() { 829 int i; 830 hashnode_s *node; 831 hashnode_s *next; 832 833 for( i = 0; i < tablesize; i++ ) { 834 next = heads[ i ]; 835 while( next != NULL ) { 836 node = next; 837 next = next->next; 838 delete node->value; 839 delete node; 840 } 841 842 heads[ i ] = NULL; 843 } 844 845 numentries = 0; 846 } 847 848 /* 849 ================ 850 idHashTable<Type>::Num 851 ================ 852 */ 853 template< class Type > 854 ID_INLINE int idHashTable<Type>::Num() const { 855 return numentries; 856 } 857 858 #if defined(ID_TYPEINFO) 859 #define __GNUC__ 99 860 #endif 861 862 #if !defined(__GNUC__) || __GNUC__ < 4 863 /* 864 ================ 865 idHashTable<Type>::GetSpread 866 ================ 867 */ 868 template< class Type > 869 int idHashTable<Type>::GetSpread() const { 870 int i, average, error, e; 871 hashnode_s *node; 872 873 // if no items in hash 874 if ( !numentries ) { 875 return 100; 876 } 877 average = numentries / tablesize; 878 error = 0; 879 for ( i = 0; i < tablesize; i++ ) { 880 numItems = 0; 881 for( node = heads[ i ]; node != NULL; node = node->next ) { 882 numItems++; 883 } 884 e = abs( numItems - average ); 885 if ( e > 1 ) { 886 error += e - 1; 887 } 888 } 889 return 100 - (error * 100 / numentries); 890 } 891 #endif 892 893 #if defined(ID_TYPEINFO) 894 #undef __GNUC__ 895 #endif 896 897 #endif /* !__HASHTABLE_H__ */