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.

430 lines
11 KiB

  1. /*
  2. * tree.c
  3. *
  4. * data type providing a map between a KEY and a VALUE. The KEY is a
  5. * 32-bit DWORD, and the VALUE is any arbitrary area of storage.
  6. *
  7. * memory is allocated from gmem_get, using hHeap as the heap handle.
  8. * hHeap must be declared and initialised elsewhere.
  9. *
  10. * currently implemented as a unbalanced binary tree.
  11. *
  12. * Geraint Davies, July 92
  13. */
  14. #include <precomp.h>
  15. #include "tree.h"
  16. /* -- data types ----------------------------------------------- */
  17. /* on creating a tree, we return a TREE handle. This is in fact a pointer
  18. * to a struct tree, defined here.
  19. */
  20. struct tree {
  21. HANDLE hHeap;
  22. TREEITEM first;
  23. };
  24. /* each element in the tree is stored in a TREEITEM. a TREEITEM handle
  25. * is a pointer to a struct treeitem, defined here
  26. */
  27. struct treeitem {
  28. TREE root;
  29. TREEKEY key;
  30. TREEITEM left, right;
  31. UINT length; /* length of the user's data */
  32. LPVOID data; /* pointer to our copy of the users data */
  33. };
  34. /* -- internal functions ---------------------------------------------*/
  35. /* free up an element of the tree. recursively calls itself to
  36. * free left and right children
  37. */
  38. void
  39. tree_delitem(TREEITEM item)
  40. {
  41. if (item == NULL) {
  42. return;
  43. }
  44. if (item->left != NULL) {
  45. tree_delitem(item->left);
  46. }
  47. if (item->right != NULL) {
  48. tree_delitem(item->right);
  49. }
  50. if (item->data != NULL) {
  51. gmem_free(item->root->hHeap, item->data, item->length);
  52. }
  53. gmem_free(item->root->hHeap, (LPSTR) item, sizeof(struct treeitem));
  54. }
  55. /* create a new treeitem, with a data block of length bytes.
  56. * if the value pointer is not NULL, initialise the data block with
  57. * the contents of value.
  58. */
  59. TREEITEM
  60. tree_newitem(TREE root, TREEKEY key, LPVOID value, UINT length)
  61. {
  62. TREEITEM item;
  63. item = (TREEITEM) gmem_get(root->hHeap, sizeof(struct treeitem));
  64. item->root = root;
  65. item->key = key;
  66. item->left = NULL;
  67. item->right = NULL;
  68. item->length = length;
  69. item->data = gmem_get(root->hHeap, length);
  70. if (value != NULL) {
  71. memcpy(item->data, value, length);
  72. }
  73. return(item);
  74. }
  75. /* find the item with the given key. if it does not exist, return
  76. * the parent item to which it would be attached. returns NULL if
  77. * no items in the tree
  78. */
  79. TREEITEM
  80. tree_getitem(TREE tree, TREEKEY key)
  81. {
  82. TREEITEM item, prev;
  83. prev = NULL;
  84. for (item = tree->first; item != NULL; ) {
  85. if (item->key == key) {
  86. return(item);
  87. }
  88. /* not this item - go on to the correct child item.
  89. * remember this item as if the child is NULL, this item
  90. * will be the correct insertion point for the new item
  91. */
  92. prev = item;
  93. if (key < item->key) {
  94. item = item->left;
  95. } else {
  96. item = item->right;
  97. }
  98. }
  99. /* prev is the parent - or null if nothing in tree */
  100. return(prev);
  101. }
  102. /* --- external functions ------------------------------------------ */
  103. /*
  104. * create an empty tree. hHeap is the handle to use for all
  105. * memory allocations for this tree.
  106. */
  107. TREE APIENTRY
  108. tree_create(HANDLE hHeap)
  109. {
  110. TREE tree;
  111. tree = (TREE) gmem_get(hHeap, sizeof(struct tree));
  112. tree->first = NULL;
  113. tree->hHeap = hHeap;
  114. return(tree);
  115. }
  116. /*
  117. * delete an entire tree, including all the user data
  118. */
  119. void APIENTRY
  120. tree_delete(TREE tree)
  121. {
  122. tree_delitem(tree->first);
  123. gmem_free(tree->hHeap, (LPSTR) tree, sizeof(struct tree));
  124. }
  125. /*
  126. * add a new element to the tree, mapping the key given to the value given.
  127. * The value is a block of storage: a copy of this is inserted into the tree.
  128. * we return a pointer to the copy of the data in the tree.
  129. *
  130. * the value pointer can be NULL: in this case, we insert a block of
  131. * length bytes, but don't initialise it. you get a pointer to it and
  132. * can initialise it yourself.
  133. *
  134. * if the key already exists, the value will be replaced with the new data.
  135. */
  136. LPVOID APIENTRY
  137. tree_update(TREE tree, TREEKEY key, LPVOID value, UINT length)
  138. {
  139. TREEITEM item;
  140. /* find the place in the tree for this key to go */
  141. item = tree_getitem(tree, key);
  142. if (item == NULL) {
  143. /* there is nothing in the tree: this item should
  144. * go at the top
  145. */
  146. tree->first = tree_newitem(tree, key, value, length);
  147. return(tree->first->data);
  148. }
  149. /* is this the same key ? */
  150. if (item->key == key) {
  151. /* this key already inserted. re-alloc the data */
  152. if (length != item->length) {
  153. gmem_free(tree->hHeap, item->data, item->length);
  154. item->data = gmem_get(tree->hHeap, length);
  155. }
  156. /* don't initialise block if no pointer passed */
  157. if (value != NULL) {
  158. memcpy(item->data, value, length);
  159. }
  160. return(item->data);
  161. }
  162. /* not the same key - getitem returned the parent for
  163. * the new tree. insert it as a child of item.
  164. */
  165. return(tree_addafter(tree, &item, key, value, length));
  166. }
  167. /*
  168. * return a pointer to the value (data block) for a given key. returns
  169. * null if not found.
  170. */
  171. LPVOID APIENTRY
  172. tree_find(TREE tree, TREEKEY key)
  173. {
  174. TREEITEM item;
  175. /* find the correct place in the tree */
  176. item = tree_getitem(tree, key);
  177. if (item == NULL) {
  178. /* nothing in the tree */
  179. return(NULL);
  180. }
  181. if (item->key != key) {
  182. /* this key not in. getitem has returned parent */
  183. return(NULL);
  184. }
  185. /* found the right element - return pointer to the
  186. * data block
  187. */
  188. return(item->data);
  189. }
  190. /*
  191. * next two routines are an optimisation for a common tree operation. in
  192. * this case, the user will want to insert a new element only if
  193. * the key is not there. if it is there, he will want to modify the
  194. * existing value (increment a reference count, for example).
  195. *
  196. * if tree_search fails to find the key, it will return a TREEITEM handle
  197. * for the parent. This can be passed to tree_addafter to insert the
  198. * new element without re-searching the tree.
  199. */
  200. /*
  201. * find an element. if not, find it's correct parent item
  202. */
  203. LPVOID APIENTRY
  204. tree_search(TREE tree, TREEKEY key, PTREEITEM pplace)
  205. {
  206. TREEITEM item;
  207. item = tree_getitem(tree, key);
  208. if (item == NULL) {
  209. /* no items in tree. set placeholder to NULL to
  210. * indicate insert at top of tree
  211. */
  212. *pplace = NULL;
  213. /* return NULL to indicate key not found */
  214. return(NULL);
  215. }
  216. if (item->key == key) {
  217. /* found the key already there -
  218. * set pplace to null just for safety
  219. */
  220. *pplace = NULL;
  221. /* give the user a pointer to his data */
  222. return(item->data);
  223. }
  224. /* key was not found - getitem has returned the parent
  225. * - set this as the place for new insertions
  226. */
  227. *pplace = item;
  228. /* return NULL to indicate that the key was not found */
  229. return(NULL);
  230. }
  231. /*
  232. * insert a key in the position already found by tree_search.
  233. *
  234. * return a pointer to the user's data in the tree. if the value
  235. * pointer passed in is null, then we allocate the block, but don't
  236. * initialise it to anything.
  237. */
  238. LPVOID APIENTRY
  239. tree_addafter(TREE tree, PTREEITEM place, TREEKEY key, LPVOID value, UINT length)
  240. {
  241. TREEITEM item, child;
  242. item = *place;
  243. if (item == NULL) {
  244. tree->first = tree_newitem(tree, key, value, length);
  245. return (tree->first->data);
  246. }
  247. child = tree_newitem(tree, key, value, length);
  248. if (child->key < item->key ) {
  249. /* should go on left leg */
  250. if (item->left != NULL) {
  251. Trace_Error(NULL, "TREE: left leaf leg not free", FALSE);
  252. }
  253. item->left = child;
  254. } else {
  255. if (item->right != NULL) {
  256. Trace_Error(NULL, "TREE: right leaf leg not free", FALSE);
  257. }
  258. item->right = child;
  259. }
  260. return(child->data);
  261. }
  262. /* --- ctree ------------------------------------------------------*/
  263. /*
  264. * ctree is a class of tree built on top of the tree interface. a
  265. * ctree keeps count of the number of insertions of identical keys.
  266. *
  267. * we do this be adding a long counter to the beginning of the user
  268. * data before inserting into the tree. if the key is not found, we set
  269. * this to one. If the key was already there, we *do not* insert the
  270. * data (data is always from the first insertion) - we simply increment
  271. * the count.
  272. */
  273. /*
  274. * create a tree for use by CTREE - same as an ordinary tree
  275. */
  276. TREE APIENTRY
  277. ctree_create(HANDLE hHeap)
  278. {
  279. return(tree_create(hHeap));
  280. }
  281. /*
  282. * delete a ctree - same as for TREE
  283. */
  284. void APIENTRY
  285. ctree_delete(TREE tree)
  286. {
  287. tree_delete(tree);
  288. }
  289. /* insert an element in the tree. if the element is not there,
  290. * insert the data and set the reference count for this key to 1.
  291. * if the key was there already, don't change the data, just increment
  292. * the reference count
  293. *
  294. * if the value pointer is not null, we initialise the value block
  295. * in the tree to contain this.
  296. *
  297. * we return a pointer to the users data in the tree
  298. */
  299. LPVOID APIENTRY
  300. ctree_update(TREE tree, TREEKEY key, LPVOID value, UINT length)
  301. {
  302. TREEITEM item;
  303. LONG_PTR FAR * pcounter;
  304. LPVOID datacopy;
  305. pcounter = tree_search(tree, key, &item);
  306. if (pcounter == NULL) {
  307. /* element not found - insert a new one
  308. * the data block for this element should be
  309. * the user's block with our reference count at
  310. * the beginning
  311. */
  312. pcounter = tree_addafter(tree, &item, key, NULL,
  313. length + sizeof(LONG_PTR));
  314. *pcounter = 1;
  315. /* add on size of one long to get the start of the user
  316. * data
  317. */
  318. datacopy = pcounter + 1;
  319. if (value != NULL) {
  320. memcpy(datacopy, value, length);
  321. }
  322. return(datacopy);
  323. }
  324. /* key was already there - increment reference count and
  325. * return pointer to data
  326. */
  327. (*pcounter)++;
  328. /* add on size of one long to get the start of the user
  329. * data
  330. */
  331. datacopy = pcounter + 1;
  332. return(datacopy);
  333. }
  334. /* return the reference count for this key */
  335. long APIENTRY
  336. ctree_getcount(TREE tree, TREEKEY key)
  337. {
  338. LONG_PTR FAR * pcounter;
  339. pcounter = tree_find(tree, key);
  340. if (pcounter == NULL) {
  341. return(0);
  342. }
  343. return((long)*pcounter);
  344. }
  345. /* return a pointer to the user's data block for this key,
  346. * or NULL if key not present
  347. */
  348. LPVOID APIENTRY
  349. ctree_find(TREE tree, TREEKEY key)
  350. {
  351. LONG_PTR FAR * pcounter;
  352. pcounter = tree_find(tree, key);
  353. if (pcounter == NULL) {
  354. return(0);
  355. }
  356. /* increment pointer by size of 1 long to point to
  357. * user's datablock
  358. */
  359. return(pcounter+1);
  360. }