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.

440 lines
9.4 KiB

  1. /*++=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. hashtable.cxx
  5. Abstract:
  6. Simple hash table implementation.
  7. Author:
  8. Paul M Midgen (pmidge) 14-August-2000
  9. Revision History:
  10. 14-August-2000 pmidge
  11. Created
  12. =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=--*/
  13. #include <common.h>
  14. /*++===========================================================================
  15. An array is separated into N buckets that +---+
  16. each contain a pointer to a binary search | 0 |------> O
  17. tree. The tree's nodes are indexed by a +---+ / \
  18. DWORD identifier to enable speedy traversals. | 1 | O O
  19. The array buckets are indexed by the values +---+ / \ \
  20. generated by the hashing function supplied | 2 | O O O
  21. by a derived class. +---+
  22. | N |
  23. Clients derive a class from the hashtable ADT and specialize it for a
  24. given data type. Any data type can be used. The only function the client
  25. must implement is the GetHashAndBucket function, and their class must
  26. provide the number of buckets the ADT needs to support. This is usually
  27. some number that is modulo'd against the generated hashes to yield the
  28. bucket number.
  29. ===========================================================================--*/
  30. #define HT_COMPARE_LARGER 0x00000001
  31. #define HT_COMPARE_SMALLER 0x00000002
  32. #define HT_COMPARE_EQUAL 0x00000003
  33. #define HT_TREE_ROOT 0x00000004
  34. #define HT_TREE_RHSUBTREE 0x00000005
  35. #define HT_TREE_LHSUBTREE 0x00000006
  36. typedef struct _NODE
  37. {
  38. DWORD hash;
  39. DWORD bucket;
  40. LPVOID data;
  41. _NODE* parent;
  42. _NODE* rh_child;
  43. _NODE* lh_child;
  44. BOOL isLeft;
  45. }
  46. NODE, *PNODE;
  47. typedef VOID (*PFNCLEARFUNC)(LPVOID* ppv);
  48. template <class T> class CHashTable
  49. {
  50. public:
  51. CHashTable(DWORD buckets)
  52. {
  53. pfnClear = NULL;
  54. cBuckets = buckets;
  55. arBuckets = new PNODE[buckets];
  56. InitializeCriticalSection(&csTable);
  57. }
  58. ~CHashTable()
  59. {
  60. SAFEDELETEBUF(arBuckets);
  61. DeleteCriticalSection(&csTable);
  62. }
  63. virtual void GetHashAndBucket(T id, LPDWORD lpHash, LPDWORD lpBucket) =0;
  64. DWORD Insert(T id, LPVOID pv);
  65. DWORD Get(T id, LPVOID* ppv);
  66. DWORD Delete(T id, LPVOID* ppv);
  67. void Clear(void);
  68. void SetClearFunction(PFNCLEARFUNC pfn) { pfnClear = pfn; }
  69. private:
  70. void _Get(DWORD hash, PNODE& proot, PNODE& pnode);
  71. DWORD _Insert(PNODE& proot, PNODE pnew);
  72. void _Remove(DWORD hash, PNODE& proot, PNODE& pnode);
  73. PNODE _NewNode(T id, LPVOID pv);
  74. DWORD _CompareNodes(DWORD hash_target, DWORD hash_tree);
  75. BOOL _HasChildren(PNODE pnode);
  76. void _PostTraverseAndDelete(PNODE proot);
  77. void _Lock(void) { EnterCriticalSection(&csTable); }
  78. void _Unlock(void) { LeaveCriticalSection(&csTable); }
  79. PNODE* arBuckets;
  80. DWORD cBuckets;
  81. CRITSEC csTable;
  82. PFNCLEARFUNC pfnClear;
  83. };
  84. //-----------------------------------------------------------------------------
  85. //-----------------------------------------------------------------------------
  86. template <class T> DWORD CHashTable<T>::Insert(T id, LPVOID pv)
  87. {
  88. DWORD ret = ERROR_SUCCESS;
  89. PNODE pn = _NewNode(id, pv);
  90. _Lock();
  91. if( pn )
  92. {
  93. ret = _Insert(arBuckets[pn->bucket], pn);
  94. }
  95. else
  96. {
  97. ret = ERROR_OUTOFMEMORY;
  98. }
  99. _Unlock();
  100. return ret;
  101. }
  102. template <class T> DWORD CHashTable<T>::Get(T id, LPVOID* ppv)
  103. {
  104. DWORD ret = ERROR_SUCCESS;
  105. DWORD hash = 0L;
  106. DWORD bucket = 0L;
  107. PNODE pnode = NULL;
  108. GetHashAndBucket(id, &hash, &bucket);
  109. _Lock();
  110. _Get(hash, arBuckets[bucket], pnode);
  111. if( pnode )
  112. {
  113. *ppv = (void*) pnode->data;
  114. }
  115. else
  116. {
  117. *ppv = NULL;
  118. ret = ERROR_NOT_FOUND;
  119. }
  120. _Unlock();
  121. return ret;
  122. }
  123. template <class T> DWORD CHashTable<T>::Delete(T id, LPVOID* ppv)
  124. {
  125. DWORD ret = ERROR_SUCCESS;
  126. DWORD hash = 0L;
  127. DWORD bucket = 0L;
  128. PNODE pnode = NULL;
  129. GetHashAndBucket(id, &hash, &bucket);
  130. _Lock();
  131. _Remove(hash, arBuckets[bucket], pnode);
  132. if( pnode )
  133. {
  134. if( ppv )
  135. {
  136. *ppv = pnode->data;
  137. }
  138. else
  139. {
  140. if( pfnClear )
  141. {
  142. pfnClear(&pnode->data);
  143. }
  144. }
  145. delete pnode;
  146. }
  147. else
  148. {
  149. ret = ERROR_NOT_FOUND;
  150. if( ppv )
  151. {
  152. *ppv = NULL;
  153. }
  154. }
  155. _Unlock();
  156. return ret;
  157. }
  158. template <class T> void CHashTable<T>::Clear(void)
  159. {
  160. _Lock();
  161. for(DWORD n=0; n < cBuckets; n++)
  162. {
  163. if( arBuckets[n] )
  164. {
  165. _PostTraverseAndDelete(arBuckets[n]);
  166. arBuckets[n] = NULL;
  167. }
  168. }
  169. _Unlock();
  170. }
  171. //-----------------------------------------------------------------------------
  172. //-----------------------------------------------------------------------------
  173. template <class T> DWORD CHashTable<T>::_Insert(PNODE& proot, PNODE pnew)
  174. {
  175. DWORD ret = ERROR_SUCCESS;
  176. if( pnew )
  177. {
  178. if( !proot )
  179. {
  180. proot = pnew;
  181. }
  182. else
  183. {
  184. switch( _CompareNodes(pnew->hash, proot->hash) )
  185. {
  186. case HT_COMPARE_SMALLER :
  187. {
  188. pnew->isLeft = TRUE;
  189. pnew->parent = proot;
  190. ret = _Insert(proot->lh_child, pnew);
  191. }
  192. break;
  193. case HT_COMPARE_LARGER :
  194. {
  195. pnew->isLeft = FALSE;
  196. pnew->parent = proot;
  197. ret = _Insert(proot->rh_child, pnew);
  198. }
  199. break;
  200. case HT_COMPARE_EQUAL :
  201. {
  202. if( pfnClear )
  203. {
  204. pfnClear(&proot->data);
  205. }
  206. ret = ERROR_DUP_NAME;
  207. proot->data = pnew->data;
  208. delete pnew;
  209. }
  210. break;
  211. }
  212. }
  213. }
  214. return ret;
  215. }
  216. template <class T> void CHashTable<T>::_Get(DWORD hash, PNODE& proot, PNODE& pnode)
  217. {
  218. if( proot )
  219. {
  220. switch( _CompareNodes(hash, proot->hash) )
  221. {
  222. case HT_COMPARE_SMALLER :
  223. {
  224. _Get(hash, proot->lh_child, pnode);
  225. }
  226. break;
  227. case HT_COMPARE_LARGER :
  228. {
  229. _Get(hash, proot->rh_child, pnode);
  230. }
  231. break;
  232. case HT_COMPARE_EQUAL :
  233. {
  234. pnode = proot;
  235. }
  236. break;
  237. }
  238. }
  239. else
  240. {
  241. pnode = NULL;
  242. }
  243. }
  244. template <class T> void CHashTable<T>::_Remove(DWORD hash, PNODE& proot, PNODE& pnode)
  245. {
  246. if( proot )
  247. {
  248. switch( _CompareNodes(hash, proot->hash) )
  249. {
  250. case HT_COMPARE_SMALLER :
  251. {
  252. _Remove(hash, proot->lh_child, pnode);
  253. }
  254. break;
  255. case HT_COMPARE_LARGER :
  256. {
  257. _Remove(hash, proot->rh_child, pnode);
  258. }
  259. break;
  260. case HT_COMPARE_EQUAL :
  261. {
  262. pnode = proot;
  263. //
  264. // if proot has no parent it is the tree's root node
  265. //
  266. // - if it has children, promote the left child to root
  267. // and insert the right child in the new tree. after
  268. // inserting, make sure the new root has no parent.
  269. //
  270. // - if it has no children the tree is empty, set the root
  271. // to null
  272. //
  273. if( !proot->parent )
  274. {
  275. if( _HasChildren(proot) )
  276. {
  277. proot = proot->lh_child;
  278. _Insert(proot, pnode->rh_child);
  279. proot->parent = NULL;
  280. }
  281. else
  282. {
  283. proot = NULL;
  284. }
  285. }
  286. else
  287. {
  288. if( proot->isLeft )
  289. {
  290. proot->parent->lh_child = NULL;
  291. }
  292. else
  293. {
  294. proot->parent->rh_child = NULL;
  295. }
  296. _Insert(pnode->parent, pnode->lh_child);
  297. _Insert(pnode->parent, pnode->rh_child);
  298. }
  299. }
  300. break;
  301. }
  302. }
  303. else
  304. {
  305. pnode = NULL;
  306. }
  307. }
  308. template <class T> void CHashTable<T>::_PostTraverseAndDelete(PNODE proot)
  309. {
  310. if( proot )
  311. {
  312. _PostTraverseAndDelete(proot->lh_child);
  313. _PostTraverseAndDelete(proot->rh_child);
  314. if( pfnClear )
  315. {
  316. pfnClear(&proot->data);
  317. }
  318. delete proot;
  319. proot = NULL;
  320. }
  321. }
  322. //-----------------------------------------------------------------------------
  323. //-----------------------------------------------------------------------------
  324. template <class T> DWORD CHashTable<T>::_CompareNodes(DWORD hash_target, DWORD hash_tree)
  325. {
  326. if( hash_target == hash_tree )
  327. {
  328. return HT_COMPARE_EQUAL;
  329. }
  330. else if( hash_target < hash_tree )
  331. {
  332. return HT_COMPARE_SMALLER;
  333. }
  334. else
  335. {
  336. return HT_COMPARE_LARGER;
  337. }
  338. }
  339. template <class T> PNODE CHashTable<T>::_NewNode(T id, LPVOID pv)
  340. {
  341. PNODE pn = new NODE;
  342. if( pn )
  343. {
  344. GetHashAndBucket(id, &pn->hash, &pn->bucket);
  345. pn->data = pv;
  346. }
  347. return pn;
  348. }
  349. template <class T> BOOL CHashTable<T>::_HasChildren(PNODE pnode)
  350. {
  351. if( pnode )
  352. {
  353. return (pnode->lh_child || pnode->rh_child);
  354. }
  355. else
  356. {
  357. return FALSE;
  358. }
  359. }