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.

442 lines
9.5 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. typedef class CHashTable<LPWSTR> WSZHASHTBL;
  85. //-----------------------------------------------------------------------------
  86. //-----------------------------------------------------------------------------
  87. template <class T> DWORD CHashTable<T>::Insert(T id, LPVOID pv)
  88. {
  89. DWORD ret = ERROR_SUCCESS;
  90. PNODE pn = _NewNode(id, pv);
  91. _Lock();
  92. if( pn )
  93. {
  94. ret = _Insert(arBuckets[pn->bucket], pn);
  95. }
  96. else
  97. {
  98. ret = ERROR_OUTOFMEMORY;
  99. }
  100. _Unlock();
  101. return ret;
  102. }
  103. template <class T> DWORD CHashTable<T>::Get(T id, LPVOID* ppv)
  104. {
  105. DWORD ret = ERROR_SUCCESS;
  106. DWORD hash = 0L;
  107. DWORD bucket = 0L;
  108. PNODE pnode = NULL;
  109. GetHashAndBucket(id, &hash, &bucket);
  110. _Lock();
  111. _Get(hash, arBuckets[bucket], pnode);
  112. if( pnode )
  113. {
  114. *ppv = (void*) pnode->data;
  115. }
  116. else
  117. {
  118. *ppv = NULL;
  119. ret = ERROR_NOT_FOUND;
  120. }
  121. _Unlock();
  122. return ret;
  123. }
  124. template <class T> DWORD CHashTable<T>::Delete(T id, LPVOID* ppv)
  125. {
  126. DWORD ret = ERROR_SUCCESS;
  127. DWORD hash = 0L;
  128. DWORD bucket = 0L;
  129. PNODE pnode = NULL;
  130. GetHashAndBucket(id, &hash, &bucket);
  131. _Lock();
  132. _Remove(hash, arBuckets[bucket], pnode);
  133. if( pnode )
  134. {
  135. if( ppv )
  136. {
  137. *ppv = pnode->data;
  138. }
  139. else
  140. {
  141. if( pfnClear )
  142. {
  143. pfnClear(&pnode->data);
  144. }
  145. }
  146. delete pnode;
  147. }
  148. else
  149. {
  150. ret = ERROR_NOT_FOUND;
  151. if( ppv )
  152. {
  153. *ppv = NULL;
  154. }
  155. }
  156. _Unlock();
  157. return ret;
  158. }
  159. template <class T> void CHashTable<T>::Clear(void)
  160. {
  161. _Lock();
  162. for(DWORD n=0; n < cBuckets; n++)
  163. {
  164. if( arBuckets[n] )
  165. {
  166. _PostTraverseAndDelete(arBuckets[n]);
  167. arBuckets[n] = NULL;
  168. }
  169. }
  170. _Unlock();
  171. }
  172. //-----------------------------------------------------------------------------
  173. //-----------------------------------------------------------------------------
  174. template <class T> DWORD CHashTable<T>::_Insert(PNODE& proot, PNODE pnew)
  175. {
  176. DWORD ret = ERROR_SUCCESS;
  177. if( pnew )
  178. {
  179. if( !proot )
  180. {
  181. proot = pnew;
  182. }
  183. else
  184. {
  185. switch( _CompareNodes(pnew->hash, proot->hash) )
  186. {
  187. case HT_COMPARE_SMALLER :
  188. {
  189. pnew->isLeft = TRUE;
  190. pnew->parent = proot;
  191. ret = _Insert(proot->lh_child, pnew);
  192. }
  193. break;
  194. case HT_COMPARE_LARGER :
  195. {
  196. pnew->isLeft = FALSE;
  197. pnew->parent = proot;
  198. ret = _Insert(proot->rh_child, pnew);
  199. }
  200. break;
  201. case HT_COMPARE_EQUAL :
  202. {
  203. if( pfnClear )
  204. {
  205. pfnClear(&proot->data);
  206. }
  207. ret = ERROR_DUP_NAME;
  208. proot->data = pnew->data;
  209. delete pnew;
  210. }
  211. break;
  212. }
  213. }
  214. }
  215. return ret;
  216. }
  217. template <class T> void CHashTable<T>::_Get(DWORD hash, PNODE& proot, PNODE& pnode)
  218. {
  219. if( proot )
  220. {
  221. switch( _CompareNodes(hash, proot->hash) )
  222. {
  223. case HT_COMPARE_SMALLER :
  224. {
  225. _Get(hash, proot->lh_child, pnode);
  226. }
  227. break;
  228. case HT_COMPARE_LARGER :
  229. {
  230. _Get(hash, proot->rh_child, pnode);
  231. }
  232. break;
  233. case HT_COMPARE_EQUAL :
  234. {
  235. pnode = proot;
  236. }
  237. break;
  238. }
  239. }
  240. else
  241. {
  242. pnode = NULL;
  243. }
  244. }
  245. template <class T> void CHashTable<T>::_Remove(DWORD hash, PNODE& proot, PNODE& pnode)
  246. {
  247. if( proot )
  248. {
  249. switch( _CompareNodes(hash, proot->hash) )
  250. {
  251. case HT_COMPARE_SMALLER :
  252. {
  253. _Remove(hash, proot->lh_child, pnode);
  254. }
  255. break;
  256. case HT_COMPARE_LARGER :
  257. {
  258. _Remove(hash, proot->rh_child, pnode);
  259. }
  260. break;
  261. case HT_COMPARE_EQUAL :
  262. {
  263. pnode = proot;
  264. //
  265. // if proot has no parent it is the tree's root node
  266. //
  267. // - if it has children, promote the left child to root
  268. // and insert the right child in the new tree. after
  269. // inserting, make sure the new root has no parent.
  270. //
  271. // - if it has no children the tree is empty, set the root
  272. // to null
  273. //
  274. if( !proot->parent )
  275. {
  276. if( _HasChildren(proot) )
  277. {
  278. proot = proot->lh_child;
  279. _Insert(proot, pnode->rh_child);
  280. proot->parent = NULL;
  281. }
  282. else
  283. {
  284. proot = NULL;
  285. }
  286. }
  287. else
  288. {
  289. if( proot->isLeft )
  290. {
  291. proot->parent->lh_child = NULL;
  292. }
  293. else
  294. {
  295. proot->parent->rh_child = NULL;
  296. }
  297. _Insert(pnode->parent, pnode->lh_child);
  298. _Insert(pnode->parent, pnode->rh_child);
  299. }
  300. }
  301. break;
  302. }
  303. }
  304. else
  305. {
  306. pnode = NULL;
  307. }
  308. }
  309. template <class T> void CHashTable<T>::_PostTraverseAndDelete(PNODE proot)
  310. {
  311. if( proot )
  312. {
  313. _PostTraverseAndDelete(proot->lh_child);
  314. _PostTraverseAndDelete(proot->rh_child);
  315. if( pfnClear )
  316. {
  317. pfnClear(&proot->data);
  318. }
  319. delete proot;
  320. proot = NULL;
  321. }
  322. }
  323. //-----------------------------------------------------------------------------
  324. //-----------------------------------------------------------------------------
  325. template <class T> DWORD CHashTable<T>::_CompareNodes(DWORD hash_target, DWORD hash_tree)
  326. {
  327. if( hash_target == hash_tree )
  328. {
  329. return HT_COMPARE_EQUAL;
  330. }
  331. else if( hash_target < hash_tree )
  332. {
  333. return HT_COMPARE_SMALLER;
  334. }
  335. else
  336. {
  337. return HT_COMPARE_LARGER;
  338. }
  339. }
  340. template <class T> PNODE CHashTable<T>::_NewNode(T id, LPVOID pv)
  341. {
  342. PNODE pn = new NODE;
  343. if( pn )
  344. {
  345. GetHashAndBucket(id, &pn->hash, &pn->bucket);
  346. pn->data = pv;
  347. }
  348. return pn;
  349. }
  350. template <class T> BOOL CHashTable<T>::_HasChildren(PNODE pnode)
  351. {
  352. if( pnode )
  353. {
  354. return (pnode->lh_child || pnode->rh_child);
  355. }
  356. else
  357. {
  358. return FALSE;
  359. }
  360. }