HashIndex.h 10 KB

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