HashIndex.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /*
  2. ===========================================================================
  3. Doom 3 GPL Source Code
  4. Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
  5. This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
  6. Doom 3 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 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 Source Code. If not, see <http://www.gnu.org/licenses/>.
  16. In addition, the Doom 3 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 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 __HASHINDEX_H__
  21. #define __HASHINDEX_H__
  22. /*
  23. ===============================================================================
  24. Fast hash table for indexes and arrays.
  25. Does not allocate memory until the first key/index pair is added.
  26. ===============================================================================
  27. */
  28. #define DEFAULT_HASH_SIZE 1024
  29. #define DEFAULT_HASH_GRANULARITY 1024
  30. class idHashIndex {
  31. public:
  32. idHashIndex( void );
  33. idHashIndex( const int initialHashSize, const int initialIndexSize );
  34. ~idHashIndex( void );
  35. // returns total size of allocated memory
  36. size_t Allocated( void ) const;
  37. // returns total size of allocated memory including size of hash index type
  38. size_t Size( void ) const;
  39. idHashIndex & operator=( const idHashIndex &other );
  40. // add an index to the hash, assumes the index has not yet been added to the hash
  41. void Add( const int key, const int index );
  42. // remove an index from the hash
  43. void Remove( const int key, const int index );
  44. // get the first index from the hash, returns -1 if empty hash entry
  45. int First( const int key ) const;
  46. // get the next index from the hash, returns -1 if at the end of the hash chain
  47. int Next( const int index ) const;
  48. // insert an entry into the index and add it to the hash, increasing all indexes >= index
  49. void InsertIndex( const int key, const int index );
  50. // remove an entry from the index and remove it from the hash, decreasing all indexes >= index
  51. void RemoveIndex( const int key, const int index );
  52. // clear the hash
  53. void Clear( void );
  54. // clear and resize
  55. void Clear( const int newHashSize, const int newIndexSize );
  56. // free allocated memory
  57. void Free( void );
  58. // get size of hash table
  59. int GetHashSize( void ) const;
  60. // get size of the index
  61. int GetIndexSize( void ) const;
  62. // set granularity
  63. void SetGranularity( const int newGranularity );
  64. // force resizing the index, current hash table stays intact
  65. void ResizeIndex( const int newIndexSize );
  66. // returns number in the range [0-100] representing the spread over the hash table
  67. int GetSpread( void ) const;
  68. // returns a key for a string
  69. int GenerateKey( const char *string, bool caseSensitive = true ) const;
  70. // returns a key for a vector
  71. int GenerateKey( const idVec3 &v ) const;
  72. // returns a key for two integers
  73. int GenerateKey( const int n1, const int n2 ) const;
  74. private:
  75. int hashSize;
  76. int * hash;
  77. int indexSize;
  78. int * indexChain;
  79. int granularity;
  80. int hashMask;
  81. int lookupMask;
  82. static int INVALID_INDEX[1];
  83. void Init( const int initialHashSize, const int initialIndexSize );
  84. void Allocate( const int newHashSize, const int newIndexSize );
  85. };
  86. /*
  87. ================
  88. idHashIndex::idHashIndex
  89. ================
  90. */
  91. ID_INLINE idHashIndex::idHashIndex( void ) {
  92. Init( DEFAULT_HASH_SIZE, DEFAULT_HASH_SIZE );
  93. }
  94. /*
  95. ================
  96. idHashIndex::idHashIndex
  97. ================
  98. */
  99. ID_INLINE idHashIndex::idHashIndex( const int initialHashSize, const int initialIndexSize ) {
  100. Init( initialHashSize, initialIndexSize );
  101. }
  102. /*
  103. ================
  104. idHashIndex::~idHashIndex
  105. ================
  106. */
  107. ID_INLINE idHashIndex::~idHashIndex( void ) {
  108. Free();
  109. }
  110. /*
  111. ================
  112. idHashIndex::Allocated
  113. ================
  114. */
  115. ID_INLINE size_t idHashIndex::Allocated( void ) const {
  116. return hashSize * sizeof( int ) + indexSize * sizeof( int );
  117. }
  118. /*
  119. ================
  120. idHashIndex::Size
  121. ================
  122. */
  123. ID_INLINE size_t idHashIndex::Size( void ) const {
  124. return sizeof( *this ) + Allocated();
  125. }
  126. /*
  127. ================
  128. idHashIndex::operator=
  129. ================
  130. */
  131. ID_INLINE idHashIndex &idHashIndex::operator=( const idHashIndex &other ) {
  132. granularity = other.granularity;
  133. hashMask = other.hashMask;
  134. lookupMask = other.lookupMask;
  135. if ( other.lookupMask == 0 ) {
  136. hashSize = other.hashSize;
  137. indexSize = other.indexSize;
  138. Free();
  139. }
  140. else {
  141. if ( other.hashSize != hashSize || hash == INVALID_INDEX ) {
  142. if ( hash != INVALID_INDEX ) {
  143. delete[] hash;
  144. }
  145. hashSize = other.hashSize;
  146. hash = new int[hashSize];
  147. }
  148. if ( other.indexSize != indexSize || indexChain == INVALID_INDEX ) {
  149. if ( indexChain != INVALID_INDEX ) {
  150. delete[] indexChain;
  151. }
  152. indexSize = other.indexSize;
  153. indexChain = new int[indexSize];
  154. }
  155. memcpy( hash, other.hash, hashSize * sizeof( hash[0] ) );
  156. memcpy( indexChain, other.indexChain, indexSize * sizeof( indexChain[0] ) );
  157. }
  158. return *this;
  159. }
  160. /*
  161. ================
  162. idHashIndex::Add
  163. ================
  164. */
  165. ID_INLINE void idHashIndex::Add( const int key, const int index ) {
  166. int h;
  167. assert( index >= 0 );
  168. if ( hash == INVALID_INDEX ) {
  169. Allocate( hashSize, index >= indexSize ? index + 1 : indexSize );
  170. }
  171. else if ( index >= indexSize ) {
  172. ResizeIndex( index + 1 );
  173. }
  174. h = key & hashMask;
  175. indexChain[index] = hash[h];
  176. hash[h] = index;
  177. }
  178. /*
  179. ================
  180. idHashIndex::Remove
  181. ================
  182. */
  183. ID_INLINE void idHashIndex::Remove( const int key, const int index ) {
  184. int k = key & hashMask;
  185. if ( hash == INVALID_INDEX ) {
  186. return;
  187. }
  188. if ( hash[k] == index ) {
  189. hash[k] = indexChain[index];
  190. }
  191. else {
  192. for ( int i = hash[k]; i != -1; i = indexChain[i] ) {
  193. if ( indexChain[i] == index ) {
  194. indexChain[i] = indexChain[index];
  195. break;
  196. }
  197. }
  198. }
  199. indexChain[index] = -1;
  200. }
  201. /*
  202. ================
  203. idHashIndex::First
  204. ================
  205. */
  206. ID_INLINE int idHashIndex::First( const int key ) const {
  207. return hash[key & hashMask & lookupMask];
  208. }
  209. /*
  210. ================
  211. idHashIndex::Next
  212. ================
  213. */
  214. ID_INLINE int idHashIndex::Next( const int index ) const {
  215. assert( index >= 0 && index < indexSize );
  216. return indexChain[index & lookupMask];
  217. }
  218. /*
  219. ================
  220. idHashIndex::InsertIndex
  221. ================
  222. */
  223. ID_INLINE void idHashIndex::InsertIndex( const int key, const int index ) {
  224. int i, max;
  225. if ( hash != INVALID_INDEX ) {
  226. max = index;
  227. for ( i = 0; i < hashSize; i++ ) {
  228. if ( hash[i] >= index ) {
  229. hash[i]++;
  230. if ( hash[i] > max ) {
  231. max = hash[i];
  232. }
  233. }
  234. }
  235. for ( i = 0; i < indexSize; i++ ) {
  236. if ( indexChain[i] >= index ) {
  237. indexChain[i]++;
  238. if ( indexChain[i] > max ) {
  239. max = indexChain[i];
  240. }
  241. }
  242. }
  243. if ( max >= indexSize ) {
  244. ResizeIndex( max + 1 );
  245. }
  246. for ( i = max; i > index; i-- ) {
  247. indexChain[i] = indexChain[i-1];
  248. }
  249. indexChain[index] = -1;
  250. }
  251. Add( key, index );
  252. }
  253. /*
  254. ================
  255. idHashIndex::RemoveIndex
  256. ================
  257. */
  258. ID_INLINE void idHashIndex::RemoveIndex( const int key, const int index ) {
  259. int i, max;
  260. Remove( key, index );
  261. if ( hash != INVALID_INDEX ) {
  262. max = index;
  263. for ( i = 0; i < hashSize; i++ ) {
  264. if ( hash[i] >= index ) {
  265. if ( hash[i] > max ) {
  266. max = hash[i];
  267. }
  268. hash[i]--;
  269. }
  270. }
  271. for ( i = 0; i < indexSize; i++ ) {
  272. if ( indexChain[i] >= index ) {
  273. if ( indexChain[i] > max ) {
  274. max = indexChain[i];
  275. }
  276. indexChain[i]--;
  277. }
  278. }
  279. for ( i = index; i < max; i++ ) {
  280. indexChain[i] = indexChain[i+1];
  281. }
  282. indexChain[max] = -1;
  283. }
  284. }
  285. /*
  286. ================
  287. idHashIndex::Clear
  288. ================
  289. */
  290. ID_INLINE void idHashIndex::Clear( void ) {
  291. // only clear the hash table because clearing the indexChain is not really needed
  292. if ( hash != INVALID_INDEX ) {
  293. memset( hash, 0xff, hashSize * sizeof( hash[0] ) );
  294. }
  295. }
  296. /*
  297. ================
  298. idHashIndex::Clear
  299. ================
  300. */
  301. ID_INLINE void idHashIndex::Clear( const int newHashSize, const int newIndexSize ) {
  302. Free();
  303. hashSize = newHashSize;
  304. indexSize = newIndexSize;
  305. }
  306. /*
  307. ================
  308. idHashIndex::GetHashSize
  309. ================
  310. */
  311. ID_INLINE int idHashIndex::GetHashSize( void ) const {
  312. return hashSize;
  313. }
  314. /*
  315. ================
  316. idHashIndex::GetIndexSize
  317. ================
  318. */
  319. ID_INLINE int idHashIndex::GetIndexSize( void ) const {
  320. return indexSize;
  321. }
  322. /*
  323. ================
  324. idHashIndex::SetGranularity
  325. ================
  326. */
  327. ID_INLINE void idHashIndex::SetGranularity( const int newGranularity ) {
  328. assert( newGranularity > 0 );
  329. granularity = newGranularity;
  330. }
  331. /*
  332. ================
  333. idHashIndex::GenerateKey
  334. ================
  335. */
  336. ID_INLINE int idHashIndex::GenerateKey( const char *string, bool caseSensitive ) const {
  337. if ( caseSensitive ) {
  338. return ( idStr::Hash( string ) & hashMask );
  339. } else {
  340. return ( idStr::IHash( string ) & hashMask );
  341. }
  342. }
  343. /*
  344. ================
  345. idHashIndex::GenerateKey
  346. ================
  347. */
  348. ID_INLINE int idHashIndex::GenerateKey( const idVec3 &v ) const {
  349. return ( (((int) v[0]) + ((int) v[1]) + ((int) v[2])) & hashMask );
  350. }
  351. /*
  352. ================
  353. idHashIndex::GenerateKey
  354. ================
  355. */
  356. ID_INLINE int idHashIndex::GenerateKey( const int n1, const int n2 ) const {
  357. return ( ( n1 + n2 ) & hashMask );
  358. }
  359. #endif /* !__HASHINDEX_H__ */