Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

325 lines
9.0 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996-2000
  5. //
  6. // File: CHash.hxx
  7. //
  8. // Contents: Hash table
  9. //
  10. // Classes: CWidHashTable
  11. //
  12. // History: 10-Jan-96 KyleP Added header
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include "chash.hxx"
  18. //+---------------------------------------------------------------------------
  19. //
  20. // Member: CWidHashTable::CWidHashTable, public
  21. //
  22. // Synopsis: Null constructor
  23. //
  24. // History: 10-Jan-96 KyleP Added header
  25. //
  26. //----------------------------------------------------------------------------
  27. CWidHashTable::CWidHashTable( BOOL fAggressiveGrowth )
  28. : _size (0),
  29. _table(0),
  30. _count(0),
  31. _fAggressiveGrowth( fAggressiveGrowth )
  32. {
  33. Win4Assert( widInvalid == 0xFFFFFFFF );
  34. #ifdef DO_STATS
  35. _cMaxChainLen = 0;
  36. _cTotalSearches = 0;
  37. _cTotalLength = 0;
  38. #endif // DO_STATS
  39. }
  40. //+---------------------------------------------------------------------------
  41. //
  42. // Member: CWidHashTable::Init, public
  43. //
  44. // Synopsis: Initialize hash table
  45. //
  46. // Arguments: [count] -- Count of used elements
  47. // [size] -- Size of [table]
  48. // [table] -- Hash table
  49. //
  50. // History: 10-Jan-96 KyleP Added header
  51. //
  52. //----------------------------------------------------------------------------
  53. void CWidHashTable::Init( ULONG count, ULONG size, WORKID * table )
  54. {
  55. _count = count;
  56. _size = size;
  57. _table = table;
  58. } //Init
  59. //+---------------------------------------------------------------------------
  60. //
  61. // Member: CWidHashTable::ReInit, public
  62. //
  63. // Synopsis: "ReInitialize" to empty state.
  64. //
  65. // Arguments: [count] -- Count of used elements
  66. // [size] -- Size of [table]
  67. // [table] -- Hash table
  68. //
  69. // History: 10-Jan-96 KyleP Added header
  70. //
  71. //----------------------------------------------------------------------------
  72. void CWidHashTable::ReInit(ULONG count, ULONG size, WORKID* table )
  73. {
  74. Init( count, size, table );
  75. Win4Assert( widInvalid == 0xFFFFFFFF );
  76. RtlFillMemory( _table, _size * sizeof(_table[0]), 0xFF );
  77. } //ReInit
  78. //+---------------------------------------------------------------------------
  79. //
  80. // Member: CWidHashTable::GrowSize, public
  81. //
  82. // Synopsis: Compute new size for table
  83. //
  84. // Arguments: [count] -- Count of to-be-used elements
  85. //
  86. // Returns: Suggested new size
  87. //
  88. // History: 10-Jan-96 KyleP Added header
  89. //
  90. //----------------------------------------------------------------------------
  91. unsigned CWidHashTable::GrowSize ( unsigned count )
  92. {
  93. if ( count < 3 )
  94. return INIT_HASH_SIZE;
  95. if ( !_fAggressiveGrowth )
  96. return count * 2 - 1;
  97. // Make the hash table as large as possible without eathing too much
  98. // memory. 4 seems to work ok.
  99. // The hash table is deemed "full" in IsFull if half of the entries
  100. // are in use.
  101. // This is so aggressive in picking a new size because:
  102. // - rehashing is expensive
  103. // - walking on hash collisions is expensive
  104. // - it's resized mostly on the initial scan, and there are probably
  105. // a lot more files to be added soon.
  106. unsigned size = count * 4;
  107. // make it power of two + 1
  108. // a good approximation of a prime
  109. for ( unsigned sizeInit = 1; sizeInit < size; sizeInit *= 2 )
  110. continue;
  111. return sizeInit - 1;
  112. } //GrowSize
  113. //+---------------------------------------------------------------------------
  114. //
  115. // Member: CWidHashTable::Add, public
  116. //
  117. // Synopsis: Add a new entry
  118. //
  119. // Arguments: [hash] -- Best position for entry
  120. // [wid] -- Workid (entry)
  121. //
  122. // History: 10-Jan-96 KyleP Added header
  123. //
  124. //----------------------------------------------------------------------------
  125. void CWidHashTable::Add ( unsigned hash, WORKID wid )
  126. {
  127. Win4Assert ( !IsFull() );
  128. unsigned cur = hash % _size;
  129. unsigned start = cur;
  130. unsigned delta = Delta();
  131. // this loop has to terminate
  132. // since the table is NOT full!
  133. while ( _table[cur] != widInvalid && _table[cur] != widUnused )
  134. {
  135. cur = (cur + delta) % _size;
  136. if ( cur == start ) // wrapped around
  137. {
  138. Win4Assert( delta != 1 ); // table is full
  139. delta = 1;
  140. cur = (cur + 1) % _size;
  141. }
  142. }
  143. _count++;
  144. _table[cur] = wid;
  145. } //Add
  146. //+---------------------------------------------------------------------------
  147. //
  148. // Member: CWidHashTable::Remove, public
  149. //
  150. // Synopsis: Removes entry from table
  151. //
  152. // Arguments: [hash] -- Best position for entry
  153. // [wid] -- Workid (entry)
  154. // [fDisableDeletionCheck] -- Should we assert that the deleted
  155. // entry must be found ?
  156. //
  157. // History: 10-Jan-96 KyleP Added header
  158. //
  159. // Notes: An entry is 'removed' by marking its slot as unused. An
  160. // unused slot is like an empty slot, except it does not
  161. // terminate a CShortWidList.
  162. //
  163. //----------------------------------------------------------------------------
  164. void CWidHashTable::Remove( unsigned hash,
  165. WORKID wid,
  166. BOOL fDisableDeletionCheck )
  167. {
  168. //
  169. // This assert not true -- IsFull is checked before adding a new item,
  170. // so after the add it could be full. If we happen to do a delete at
  171. // this point, the table could be full and that's ok.
  172. //
  173. // Win4Assert ( !IsFull() );
  174. unsigned cur = hash % _size;
  175. unsigned start = cur;
  176. unsigned delta = Delta();
  177. // this loop has to terminate
  178. // since the table is NOT full!
  179. while ( _table[cur] != wid && _table[cur] != widInvalid )
  180. {
  181. cur = (cur + delta) % _size;
  182. if ( cur == start ) // wrapped around
  183. {
  184. Win4Assert( delta != 1 ); // table is full
  185. delta = 1;
  186. cur = (cur + 1) % _size;
  187. }
  188. }
  189. if ( !fDisableDeletionCheck )
  190. {
  191. Win4Assert( wid == _table[cur] );
  192. }
  193. if ( _table[cur] == wid )
  194. {
  195. _count--;
  196. _table[cur] = widUnused;
  197. }
  198. } //Remove
  199. //+---------------------------------------------------------------------------
  200. //
  201. // Member: CShortWidList::CShortWidList, public
  202. //
  203. // Synopsis: Iterator for closed hash 'bucket'.
  204. //
  205. // Arguments: [hash] -- Starting position
  206. // [hashTable] -- Table
  207. //
  208. // History: 10-Jan-96 KyleP Added header
  209. //
  210. //----------------------------------------------------------------------------
  211. CShortWidList::CShortWidList ( unsigned hash, CWidHashTable& hashTable )
  212. : _hashTable(hashTable),
  213. _counter(0),
  214. _size( hashTable.Size() )
  215. {
  216. if (_size == 0)
  217. _wid = widInvalid;
  218. else
  219. {
  220. _iCur = hash % _size;
  221. _iStart = _iCur;
  222. _delta = hashTable.Delta();
  223. _wid = _hashTable[_iCur];
  224. if ( widUnused == _wid )
  225. _wid = NextWorkId();
  226. }
  227. } //CShortWidList
  228. //+---------------------------------------------------------------------------
  229. //
  230. // Member: CShortWidList::NextWorkId, public
  231. //
  232. // Returns: Next workid in 'bucket', or widInvalid if at end.
  233. //
  234. // History: 10-Jan-96 KyleP Added header
  235. //
  236. //----------------------------------------------------------------------------
  237. WORKID CShortWidList::NextWorkId()
  238. {
  239. _wid = widUnused;
  240. do
  241. {
  242. _counter++;
  243. _iCur = ( _iCur + _delta ) % _size;
  244. if ( _iCur == _iStart ) // wrapped around
  245. {
  246. if (_counter >= _size) // looked at all
  247. {
  248. _wid = widInvalid;
  249. break;
  250. }
  251. else
  252. {
  253. _delta = 1; // try the fallback delta
  254. _iCur = (_iCur + 1) % _size;
  255. _wid = _hashTable[_iCur];
  256. }
  257. }
  258. else
  259. {
  260. _wid = _hashTable[_iCur];
  261. }
  262. } while ( _wid == widUnused );
  263. return _wid;
  264. } //NextWorkId
  265. //+---------------------------------------------------------------------------
  266. //
  267. // Member: CWidHashTable::IsFull, private
  268. //
  269. // Returns: TRUE if hash table is full (is running out of slack).
  270. //
  271. // History: 10-Jan-96 KyleP Added header
  272. //
  273. //----------------------------------------------------------------------------
  274. BOOL CWidHashTable::IsFull()
  275. {
  276. // If the hash table is greater than or equal to half full,
  277. // it's time to rehash.
  278. if ( _fAggressiveGrowth )
  279. return ( _count * 2 ) >= _size;
  280. return ( _count * 3 / 2 ) >= _size;
  281. } //IsFull