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.

553 lines
18 KiB

  1. #ifndef _HASH_HPP_
  2. #define _HASH_HPP_
  3. // Ruler
  4. // 1 2 3 4 5 6 7 8
  5. //345678901234567890123456789012345678901234567890123456789012345678901234567890
  6. /********************************************************************/
  7. /* */
  8. /* The standard layout. */
  9. /* */
  10. /* The standard layout for 'hpp' files for this code is as */
  11. /* follows: */
  12. /* */
  13. /* 1. Include files. */
  14. /* 2. Constants exported from the class. */
  15. /* 3. Data structures exported from the class. */
  16. /* 4. Forward references to other data structures. */
  17. /* 5. Class specifications (including inline functions). */
  18. /* 6. Additional large inline functions. */
  19. /* */
  20. /* Any portion that is not required is simply omitted. */
  21. /* */
  22. /********************************************************************/
  23. #include "Global.hpp"
  24. /********************************************************************/
  25. /* */
  26. /* Include files for inherited classes. */
  27. /* */
  28. /* The include files for inherited classes are required in the */
  29. /* specification of this class. */
  30. /* */
  31. /********************************************************************/
  32. #include "Common.hpp"
  33. #include "Lock.hpp"
  34. #include "Stack.hpp"
  35. #include "Vector.hpp"
  36. /********************************************************************/
  37. /* */
  38. /* Macros exported from this class. */
  39. /* */
  40. /* This class has three template parameters so to make it more */
  41. /* readable a macro is specified here to simplify the code. */
  42. /* */
  43. /********************************************************************/
  44. #define HASH_TEMPLATE class KEY,class TYPE,class LOCK
  45. /********************************************************************/
  46. /* */
  47. /* Constants exported from the class. */
  48. /* */
  49. /* The stack constants specify the initial size of the map. */
  50. /* */
  51. /********************************************************************/
  52. CONST SBIT32 HashSize = 1024;
  53. CONST SBIT32 MinHashFree = (100/25);
  54. CONST SBIT32 ValueSize = 256;
  55. /********************************************************************/
  56. /* */
  57. /* Hash table. */
  58. /* */
  59. /* This class provides general purpose hash table functions to */
  60. /* safely map sparse integer keys into some pointer or value. */
  61. /* */
  62. /********************************************************************/
  63. template <HASH_TEMPLATE=NO_LOCK> class HASH : public LOCK
  64. {
  65. //
  66. // Private structures.
  67. //
  68. typedef struct
  69. {
  70. KEY Key;
  71. SBIT32 Next;
  72. TYPE Value;
  73. }
  74. VALUE;
  75. //
  76. // Private data.
  77. //
  78. SBIT32 MaxHash;
  79. SBIT32 MaxValues;
  80. SBIT32 ValuesUsed;
  81. SBIT32 Active;
  82. VECTOR<SBIT32> Hash;
  83. SBIT32 HashMask;
  84. SBIT32 HashShift;
  85. STACK<SBIT32> FreeStack;
  86. VECTOR<VALUE> Values;
  87. public:
  88. //
  89. // Public functions.
  90. //
  91. HASH
  92. (
  93. SBIT32 NewMaxHash = HashSize,
  94. SBIT32 NewMaxValues = ValueSize,
  95. SBIT32 Alignment = 1
  96. );
  97. VOID AddToHash( CONST KEY & Key, CONST TYPE & Value );
  98. VIRTUAL SBIT32 ComputeHashKey( CONST KEY & Key );
  99. BOOLEAN FindInHash( CONST KEY & Key, TYPE *Value );
  100. VIRTUAL BOOLEAN MatchingKeys( CONST KEY & Key1, CONST KEY & Key2 );
  101. VOID RemoveFromHash( CONST KEY & Key );
  102. ~HASH( VOID );
  103. private:
  104. //
  105. // Private functions.
  106. //
  107. BOOLEAN FindHashKeyValue( CONST KEY & Key, SBIT32 **HashIndex );
  108. VOID Resize( VOID );
  109. //
  110. // Disabled operations.
  111. //
  112. HASH( CONST HASH & Copy );
  113. VOID operator=( CONST HASH & Copy );
  114. };
  115. /********************************************************************/
  116. /* */
  117. /* Class constructor. */
  118. /* */
  119. /* Create a new hash and prepare it for use. This call is */
  120. /* not thread safe and should only be made in a single thread */
  121. /* environment. */
  122. /* */
  123. /********************************************************************/
  124. template <HASH_TEMPLATE> HASH<KEY,TYPE,LOCK>::HASH
  125. (
  126. SBIT32 NewMaxHash,
  127. SBIT32 NewMaxValues,
  128. SBIT32 Alignment
  129. ) :
  130. //
  131. // Call the constructors for the contained classes.
  132. //
  133. Hash( (COMMON::ForceToPowerOfTwo( NewMaxHash )),1,CacheLineSize ),
  134. FreeStack( (NewMaxValues / 2) ),
  135. Values( NewMaxValues,Alignment,CacheLineSize )
  136. {
  137. if
  138. (
  139. (NewMaxHash > 0)
  140. &&
  141. (
  142. COMMON::ConvertDivideToShift
  143. (
  144. (COMMON::ForceToPowerOfTwo( NewMaxHash )),
  145. & HashMask
  146. )
  147. )
  148. &&
  149. (NewMaxValues > 0)
  150. )
  151. {
  152. REGISTER SBIT32 Count;
  153. //
  154. // Setup the hash table size information.
  155. //
  156. MaxHash = (COMMON::ForceToPowerOfTwo( NewMaxHash ));
  157. MaxValues = NewMaxValues;
  158. ValuesUsed = 0;
  159. //
  160. // Zero the control values compute the
  161. // hash table shift values.
  162. //
  163. Active = 0;
  164. HashShift = (32-HashMask);
  165. HashMask = ((1 << HashMask)-1);
  166. for( Count=0;Count < MaxHash;Count ++ )
  167. { Hash[ Count ] = EndOfList; }
  168. }
  169. else
  170. { Failure( "Max sizes in constructor for HASH" ); }
  171. }
  172. /********************************************************************/
  173. /* */
  174. /* Add to the hash table. */
  175. /* */
  176. /* We add an key to the hash table if it does not already exist. */
  177. /* Then we add (or update) the current value. If the is not */
  178. /* space we expand the size of the 'Values' table. */
  179. /* */
  180. /********************************************************************/
  181. template <HASH_TEMPLATE> VOID HASH<KEY,TYPE,LOCK>::AddToHash
  182. (
  183. CONST KEY & Key,
  184. CONST TYPE & Value
  185. )
  186. {
  187. AUTO SBIT32 *HashIndex;
  188. //
  189. // Claim an exclusive lock (if enabled).
  190. //
  191. ClaimExclusiveLock();
  192. if ( ! FindHashKeyValue( Key, & HashIndex ) )
  193. {
  194. AUTO SBIT32 NewIndex;
  195. REGISTER VALUE *NewValue;
  196. //
  197. // Extract a free element from the stack.
  198. // If the stack is empty then allocated one
  199. // from the array.
  200. //
  201. if ( ! FreeStack.PopStack( & NewIndex ) )
  202. {
  203. //
  204. // If the array is full then resize it.
  205. // We need to be careful here as a resize
  206. // can change the address of the 'Values'
  207. // array.
  208. //
  209. if ( (NewIndex = ValuesUsed ++) >= MaxValues )
  210. { Values.Resize( (MaxValues *= ExpandStore) ); }
  211. }
  212. //
  213. // Add the new element into the hash table
  214. // and link it into any overflow chains.
  215. //
  216. NewValue = & Values[ NewIndex ];
  217. Active ++;
  218. //
  219. // Link in the new element.
  220. //
  221. NewValue -> Key = Key;
  222. NewValue -> Next = (*HashIndex);
  223. (*HashIndex) = NewIndex;
  224. NewValue -> Value = Value;
  225. }
  226. else
  227. { Values[ (*HashIndex) ].Value = Value; }
  228. //
  229. // If the hash table has grown too big we
  230. // resize it.
  231. //
  232. if ( (Active + (MaxHash / MinHashFree)) > MaxHash )
  233. { Resize(); }
  234. //
  235. // Release any lock we got earlier.
  236. //
  237. ReleaseExclusiveLock();
  238. }
  239. /********************************************************************/
  240. /* */
  241. /* Compute the hash key. . */
  242. /* */
  243. /* Compute a hash value from the supplied key. */
  244. /* */
  245. /********************************************************************/
  246. template <HASH_TEMPLATE> SBIT32 HASH<KEY,TYPE,LOCK>::ComputeHashKey
  247. (
  248. CONST KEY & Key
  249. )
  250. {
  251. //
  252. // When the key is larger than an integer the we need
  253. // to do a bit more work.
  254. //
  255. if ( sizeof(KEY) > sizeof(SBIT32) )
  256. {
  257. REGISTER SBIT32 HighWord = ((SBIT32) (Key >> 32));
  258. REGISTER SBIT32 LowWord = ((SBIT32) Key);
  259. //
  260. // We compute the hash key using both the high
  261. // and low order words.
  262. //
  263. return
  264. (
  265. (HighWord * 2964557531)
  266. +
  267. (LowWord * 2964557531)
  268. +
  269. (HighWord + LowWord)
  270. );
  271. }
  272. else
  273. { return ((((SBIT32) Key) * 2964557531) + ((SBIT32) Key)); }
  274. }
  275. /********************************************************************/
  276. /* */
  277. /* Find a key in the hash table. */
  278. /* */
  279. /* Find a key in the hash table and return the associated value. */
  280. /* */
  281. /********************************************************************/
  282. template <HASH_TEMPLATE> BOOLEAN HASH<KEY,TYPE,LOCK>::FindInHash
  283. (
  284. CONST KEY & Key,
  285. TYPE *Value
  286. )
  287. {
  288. AUTO SBIT32 *Index;
  289. REGISTER BOOLEAN Result;
  290. //
  291. // Claim an shared lock (if enabled).
  292. //
  293. ClaimSharedLock();
  294. //
  295. // Find the key in the hash table.
  296. //
  297. if ( (Result = FindHashKeyValue( Key,& Index )) )
  298. { (*Value) = Values[ (*Index) ].Value; }
  299. //
  300. // Release any lock we got earlier.
  301. //
  302. ReleaseSharedLock();
  303. return Result;
  304. }
  305. /********************************************************************/
  306. /* */
  307. /* Find the hash key value. */
  308. /* */
  309. /* Find the value associated with the supplied hash key. */
  310. /* */
  311. /********************************************************************/
  312. template <HASH_TEMPLATE> BOOLEAN HASH<KEY,TYPE,LOCK>::FindHashKeyValue
  313. (
  314. CONST KEY & Key,
  315. SBIT32 **Index
  316. )
  317. {
  318. REGISTER SBIT32 *Current;
  319. REGISTER VALUE *List;
  320. //
  321. // Find the bucket in the hash table that should
  322. // contain this key.
  323. //
  324. (*Index) = & Hash[ ((ComputeHashKey( Key ) >> HashShift) & HashMask) ];
  325. //
  326. // Walk the overflow chain and look for the key.
  327. //
  328. for ( Current = (*Index);(*Current) != EndOfList;Current = & List -> Next )
  329. {
  330. List = & Values[ (*Current) ];
  331. //
  332. // If the keys match we are out of here.
  333. //
  334. if ( MatchingKeys( Key,List -> Key ) )
  335. {
  336. (*Index) = Current;
  337. return True;
  338. }
  339. }
  340. return False;
  341. }
  342. /********************************************************************/
  343. /* */
  344. /* Compare two hask keys. . */
  345. /* */
  346. /* Compare two hash keys to see if they match. */
  347. /* */
  348. /********************************************************************/
  349. template <HASH_TEMPLATE> BOOLEAN HASH<KEY,TYPE,LOCK>::MatchingKeys
  350. (
  351. CONST KEY & Key1,
  352. CONST KEY & Key2
  353. )
  354. { return (Key1 == Key2); }
  355. /********************************************************************/
  356. /* */
  357. /* Remove a key from the hash table. */
  358. /* */
  359. /* The supplied key is removed from the hash table (if it exists) */
  360. /* and the associated value is deleted. */
  361. /* */
  362. /********************************************************************/
  363. template <HASH_TEMPLATE> VOID HASH<KEY,TYPE,LOCK>::RemoveFromHash
  364. (
  365. CONST KEY & Key
  366. )
  367. {
  368. AUTO SBIT32 *Index;
  369. //
  370. // Claim an exclusive lock (if enabled).
  371. //
  372. ClaimExclusiveLock();
  373. //
  374. // Find the key in the hash table.. If it
  375. // exists then delete it.
  376. //
  377. if ( FindHashKeyValue( Key,& Index ) )
  378. {
  379. Active --;
  380. FreeStack.PushStack( (*Index) );
  381. (*Index) = Values[ (*Index) ].Next;
  382. }
  383. //
  384. // Release any lock we got earlier.
  385. //
  386. ReleaseExclusiveLock();
  387. }
  388. /********************************************************************/
  389. /* */
  390. /* Resize the hash table. */
  391. /* */
  392. /* The hash table is resized if it becomes more than 75% full */
  393. /* and all the keys are rehashed. */
  394. /* */
  395. /********************************************************************/
  396. template <HASH_TEMPLATE> VOID HASH<KEY,TYPE,LOCK>::Resize( VOID )
  397. {
  398. REGISTER SBIT32 Count;
  399. REGISTER SBIT32 List = EndOfList;
  400. //
  401. // Walk the hash table and link all the active
  402. // values into a single linked list.
  403. //
  404. for ( Count=0;Count < MaxHash;Count ++ )
  405. {
  406. REGISTER SBIT32 Start = Hash[ Count ];
  407. //
  408. // We know that some of the hash buckets may
  409. // be empty so we skip these.
  410. //
  411. if ( Start != EndOfList )
  412. {
  413. REGISTER SBIT32 Last = Start;
  414. //
  415. // Walk along the overflow chain until
  416. // we find the end.
  417. //
  418. while ( Values[ Last ].Next != EndOfList )
  419. { Last = Values[ Last ].Next; }
  420. //
  421. // Add the list on the front of the new
  422. // global list.
  423. //
  424. Values[ Last ].Next = List;
  425. List = Start;
  426. }
  427. }
  428. //
  429. // Resize the hash table.
  430. //
  431. Hash.Resize( (MaxHash *= ExpandStore) );
  432. if ( COMMON::ConvertDivideToShift( MaxHash,& HashMask ) )
  433. {
  434. REGISTER SBIT32 Count;
  435. //
  436. // Update the shift values.
  437. //
  438. HashShift = (32-HashMask);
  439. HashMask = ((1 << HashMask)-1);
  440. //
  441. // Zero the resized table.
  442. //
  443. for ( Count=0;Count < MaxHash;Count ++ )
  444. { Hash[ Count ] = EndOfList; }
  445. }
  446. else
  447. { Failure( "Hash size in Resize" ); }
  448. //
  449. // Rehash all the existing values.
  450. //
  451. while ( List != EndOfList )
  452. {
  453. AUTO SBIT32 *Index;
  454. REGISTER VALUE *Current = & Values[ List ];
  455. REGISTER SBIT32 Next = Current -> Next;
  456. if ( ! FindHashKeyValue( Current -> Key,& Index ) )
  457. {
  458. Current -> Next = (*Index);
  459. (*Index) = List;
  460. List = Next;
  461. }
  462. else
  463. { Failure( "Duplicate hash key in Risize" ); }
  464. }
  465. }
  466. /********************************************************************/
  467. /* */
  468. /* Class destructor. */
  469. /* */
  470. /* Destory the hash. This call is not thread safe and should */
  471. /* only be made in a single thread environment. */
  472. /* */
  473. /********************************************************************/
  474. template <HASH_TEMPLATE> HASH<KEY,TYPE,LOCK>::~HASH( VOID )
  475. { /* void */ }
  476. #endif