DOOM-3-BFG

DOOM 3 BFG Edition
Log | Files | Refs

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__ */