HashTable.h 21 KB

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