|
|
1.1 ! root 1: ! 2: /******************************************************************************\ ! 3: * This is a part of the Microsoft Source Code Samples. ! 4: * Copyright (C) 1993 Microsoft Corporation. ! 5: * All rights reserved. ! 6: * This source code is only intended as a supplement to ! 7: * Microsoft Development Tools and/or WinHelp documentation. ! 8: * See these sources for detailed information regarding the ! 9: * Microsoft samples programs. ! 10: \******************************************************************************/ ! 11: ! 12: /****************************** Module Header ******************************* ! 13: * Module Name: TREE.C ! 14: * ! 15: * Functions supporting an unbalanced binary tree. ! 16: * ! 17: * Functions: ! 18: * ! 19: * tree_delitem() ! 20: * tree_newitem() ! 21: * tree_getitem() ! 22: * tree_create() ! 23: * tree_delete() ! 24: * tree_update() ! 25: * tree_find() ! 26: * tree_search() ! 27: * tree_addafter() ! 28: * ctree_create() ! 29: * ctree_delete() ! 30: * ctree_update() ! 31: * ctree_getcount() ! 32: * ctree_find() ! 33: * ! 34: * Comments: ! 35: * ! 36: * TREE is a data type providing a map between a KEY and a VALUE. The KEY is a ! 37: * 32-bit DWORD, and the VALUE is any arbitrary area of storage. ! 38: * ! 39: * Mmemory is allocated from gmem_get, using hHeap as the heap handle. ! 40: * hHeap must be declared and initialised elsewhere. ! 41: * ! 42: * Currently implemented as a unbalanced binary tree. ! 43: * ! 44: ****************************************************************************/ ! 45: ! 46: #include <windows.h> ! 47: #include <stdlib.h> ! 48: #include <memory.h> ! 49: ! 50: #include "gutils.h" ! 51: #include "tree.h" ! 52: ! 53: ! 54: /* -- data types ----------------------------------------------- */ ! 55: ! 56: /* on creating a tree, we return a TREE handle. This is in fact a pointer ! 57: * to a struct tree, defined here. ! 58: */ ! 59: struct tree { ! 60: HANDLE hHeap; ! 61: TREEITEM first; ! 62: }; ! 63: ! 64: /* each element in the tree is stored in a TREEITEM. a TREEITEM handle ! 65: * is a pointer to a struct treeitem, defined here ! 66: */ ! 67: struct treeitem { ! 68: TREE root; ! 69: ! 70: TREEKEY key; ! 71: ! 72: TREEITEM left, right; ! 73: ! 74: UINT length; /* length of the user's data */ ! 75: ! 76: LPVOID data; /* pointer to our copy of the users data */ ! 77: ! 78: }; ! 79: ! 80: /*************************************************************************** ! 81: * Function: tree_delitems ! 82: * ! 83: * Purpose: ! 84: * ! 85: * Free up an element of the tree. Recursively calls itself to ! 86: * free left and right children ! 87: */ ! 88: void ! 89: tree_delitem(TREEITEM item) ! 90: { ! 91: if (item == NULL) { ! 92: return; ! 93: } ! 94: if (item->left != NULL) { ! 95: tree_delitem(item->left); ! 96: } ! 97: if (item->right != NULL) { ! 98: tree_delitem(item->right); ! 99: } ! 100: if (item->data != NULL) { ! 101: gmem_free(item->root->hHeap, item->data, item->length); ! 102: } ! 103: ! 104: gmem_free(item->root->hHeap, (LPSTR) item, sizeof(struct treeitem)); ! 105: } ! 106: ! 107: /*************************************************************************** ! 108: * Function: tree_newitem ! 109: * ! 110: * Purpose: ! 111: * ! 112: * Creates a new treeitem, with a data block of length bytes. ! 113: * If the value pointer is not NULL, initialise the data block with ! 114: * the contents of value. ! 115: */ ! 116: TREEITEM ! 117: tree_newitem(TREE root, TREEKEY key, LPVOID value, UINT length) ! 118: { ! 119: TREEITEM item; ! 120: ! 121: item = (TREEITEM) gmem_get(root->hHeap, sizeof(struct treeitem)); ! 122: ! 123: item->root = root; ! 124: item->key = key; ! 125: item->left = NULL; ! 126: item->right = NULL; ! 127: item->length = length; ! 128: item->data = gmem_get(root->hHeap, length); ! 129: if (value != NULL) { ! 130: memcpy(item->data, value, length); ! 131: } ! 132: ! 133: return(item); ! 134: } ! 135: ! 136: ! 137: /*************************************************************************** ! 138: * Function: tree_getitem ! 139: * ! 140: * Purpose: ! 141: * ! 142: * Finds the item with the given key. If it does not exist, return ! 143: * the parent item to which it would be attached. Returns NULL if ! 144: * no items in the tree ! 145: */ ! 146: TREEITEM ! 147: tree_getitem(TREE tree, TREEKEY key) ! 148: { ! 149: TREEITEM item, prev; ! 150: ! 151: ! 152: prev = NULL; ! 153: for (item = tree->first; item != NULL; ) { ! 154: ! 155: if (item->key == key) { ! 156: return(item); ! 157: } ! 158: ! 159: /* not this item - go on to the correct child item. ! 160: * remember this item as if the child is NULL, this item ! 161: * will be the correct insertion point for the new item ! 162: */ ! 163: prev = item; ! 164: ! 165: if (key < item->key) { ! 166: item = item->left; ! 167: } else { ! 168: item = item->right; ! 169: } ! 170: } ! 171: /* prev is the parent - or null if nothing in tree */ ! 172: return(prev); ! 173: } ! 174: ! 175: /*************************************************************************** ! 176: * Function: tree_create ! 177: * ! 178: * Purpose: ! 179: * ! 180: * Creates an empty tree. hHeap is the handle to use for all ! 181: * memory allocations for this tree. ! 182: */ ! 183: TREE APIENTRY ! 184: tree_create(HANDLE hHeap) ! 185: { ! 186: TREE tree; ! 187: ! 188: tree = (TREE) gmem_get(hHeap, sizeof(struct tree)); ! 189: tree->first = NULL; ! 190: tree->hHeap = hHeap; ! 191: return(tree); ! 192: } ! 193: ! 194: ! 195: /*************************************************************************** ! 196: * Function: tree_delete ! 197: * ! 198: * Purpose: ! 199: * ! 200: * Deletes an entire tree, including all the user data ! 201: */ ! 202: void APIENTRY ! 203: tree_delete(TREE tree) ! 204: { ! 205: ! 206: tree_delitem(tree->first); ! 207: ! 208: gmem_free(tree->hHeap, (LPSTR) tree, sizeof(struct tree)); ! 209: } ! 210: ! 211: /*************************************************************************** ! 212: * Function: tree_update ! 213: * ! 214: * Purpose: ! 215: * ! 216: * Adds a new element to the tree, mapping the key given to the value given. ! 217: * The value is a block of storage: a copy of this is inserted into the tree. ! 218: * We return a pointer to the copy of the data in the tree. ! 219: * ! 220: * The value pointer can be NULL: in this case, we insert a block of ! 221: * length bytes, but don't initialise it. You get a pointer to it and ! 222: * can initialise it yourself. ! 223: * ! 224: * If the key already exists, the value will be replaced with the new data. ! 225: */ ! 226: LPVOID APIENTRY ! 227: tree_update(TREE tree, TREEKEY key, LPVOID value, UINT length) ! 228: { ! 229: TREEITEM item; ! 230: ! 231: /* find the place in the tree for this key to go */ ! 232: item = tree_getitem(tree, key); ! 233: ! 234: if (item == NULL) { ! 235: /* there is nothing in the tree: this item should ! 236: * go at the top ! 237: */ ! 238: tree->first = tree_newitem(tree, key, value, length); ! 239: return(tree->first->data); ! 240: } ! 241: ! 242: /* is this the same key ? */ ! 243: if (item->key == key) { ! 244: ! 245: /* this key already inserted. re-alloc the data */ ! 246: if (length != item->length) { ! 247: gmem_free(tree->hHeap, item->data, item->length); ! 248: item->data = gmem_get(tree->hHeap, length); ! 249: } ! 250: /* don't initialise block if no pointer passed */ ! 251: if (value != NULL) { ! 252: memcpy(item->data, value, length); ! 253: } ! 254: return(item->data); ! 255: } ! 256: ! 257: /* not the same key - getitem returned the parent for ! 258: * the new tree. insert it as a child of item. ! 259: */ ! 260: return(tree_addafter(tree, &item, key, value, length)); ! 261: } ! 262: ! 263: /*************************************************************************** ! 264: * Function: tree_find ! 265: * ! 266: * Purpose: ! 267: * ! 268: * Returns a pointer to the value (data block) for a given key. Returns ! 269: * null if not found. ! 270: */ ! 271: LPVOID APIENTRY ! 272: tree_find(TREE tree, TREEKEY key) ! 273: { ! 274: TREEITEM item; ! 275: ! 276: /* find the correct place in the tree */ ! 277: item = tree_getitem(tree, key); ! 278: ! 279: if (item == NULL) { ! 280: /* nothing in the tree */ ! 281: return(NULL); ! 282: } ! 283: ! 284: if (item->key != key) { ! 285: /* this key not in. getitem has returned parent */ ! 286: return(NULL); ! 287: } ! 288: ! 289: /* found the right element - return pointer to the ! 290: * data block ! 291: */ ! 292: return(item->data); ! 293: } ! 294: ! 295: /* The next two routines are an optimisation for a common tree operation. In ! 296: * this case, the user will want to insert a new element only if ! 297: * the key is not there. If it is there, he will want to modify the ! 298: * existing value (increment a reference count, for example). ! 299: * ! 300: * If tree_search fails to find the key, it will return a TREEITEM handle ! 301: * for the parent. This can be passed to tree_addafter to insert the ! 302: * new element without re-searching the tree. ! 303: */ ! 304: ! 305: /*************************************************************************** ! 306: * Function: tree_search ! 307: * ! 308: * Purpose: ! 309: * ! 310: * Find an element. If not, find it's correct parent item ! 311: */ ! 312: LPVOID APIENTRY ! 313: tree_search(TREE tree, TREEKEY key, PTREEITEM pplace) ! 314: { ! 315: TREEITEM item; ! 316: ! 317: item = tree_getitem(tree, key); ! 318: ! 319: if (item == NULL) { ! 320: /* no items in tree. set placeholder to NULL to ! 321: * indicate insert at top of tree ! 322: */ ! 323: *pplace = NULL; ! 324: ! 325: /* return NULL to indicate key not found */ ! 326: return(NULL); ! 327: } ! 328: ! 329: if (item->key == key) { ! 330: /* found the key already there - ! 331: * set pplace to null just for safety ! 332: */ ! 333: *pplace = NULL; ! 334: ! 335: /* give the user a pointer to his data */ ! 336: return(item->data); ! 337: } ! 338: ! 339: ! 340: /* key was not found - getitem has returned the parent ! 341: * - set this as the place for new insertions ! 342: */ ! 343: *pplace = item; ! 344: ! 345: /* return NULL to indicate that the key was not found */ ! 346: return(NULL); ! 347: } ! 348: ! 349: /*************************************************************************** ! 350: * Function: tree_addafter ! 351: * ! 352: * Purpose: ! 353: * ! 354: * Insert a key in the position already found by tree_search. ! 355: * ! 356: * Return a pointer to the user's data in the tree. If the value ! 357: * pointer passed in is null, then we allocate the block, but don't ! 358: * initialise it to anything. ! 359: */ ! 360: LPVOID APIENTRY ! 361: tree_addafter(TREE tree, PTREEITEM place, TREEKEY key, LPVOID value, UINT length) ! 362: { ! 363: TREEITEM item, child; ! 364: ! 365: item = *place; ! 366: if (item == NULL) { ! 367: tree->first = tree_newitem(tree, key, value, length); ! 368: return (tree->first->data); ! 369: } ! 370: ! 371: child = tree_newitem(tree, key, value, length); ! 372: if (child->key < item->key ) { ! 373: /* should go on left leg */ ! 374: item->left = child; ! 375: } else { ! 376: item->right = child; ! 377: } ! 378: return(child->data); ! 379: } ! 380: ! 381: ! 382: /* --- ctree ------------------------------------------------------*/ ! 383: ! 384: /* ! 385: * ctree is a class of tree built on top of the tree interface. a ! 386: * ctree keeps count of the number of insertions of identical keys. ! 387: * ! 388: * We do this be adding a long counter to the beginning of the user ! 389: * data before inserting into the tree. If the key is not found, we set ! 390: * this to one. If the key was already there, we *do not* insert the ! 391: * data (data is always from the first insertion) - we simply increment ! 392: * the count. ! 393: */ ! 394: ! 395: /* Create a tree for use by CTREE - same as an ordinary tree ! 396: */ ! 397: TREE APIENTRY ! 398: ctree_create(HANDLE hHeap) ! 399: { ! 400: return(tree_create(hHeap)); ! 401: } ! 402: ! 403: /* ! 404: * Delete a ctree - same as for TREE ! 405: */ ! 406: void APIENTRY ! 407: ctree_delete(TREE tree) ! 408: { ! 409: tree_delete(tree); ! 410: } ! 411: ! 412: ! 413: /*************************************************************************** ! 414: * Function: ctree_update ! 415: * ! 416: * Purpose: ! 417: * ! 418: * Insert an element in the tree. If the element is not there, ! 419: * insert the data and set the reference count for this key to 1. ! 420: * If the key was there already, don't change the data, just increment ! 421: * the reference count ! 422: * ! 423: * If the value pointer is not null, we initialise the value block ! 424: * in the tree to contain this. ! 425: * ! 426: * We return a pointer to the users data in the tree ! 427: */ ! 428: LPVOID APIENTRY ! 429: ctree_update(TREE tree, TREEKEY key, LPVOID value, UINT length) ! 430: { ! 431: TREEITEM item; ! 432: long FAR * pcounter; ! 433: LPVOID datacopy; ! 434: ! 435: pcounter = tree_search(tree, key, &item); ! 436: ! 437: if (pcounter == NULL) { ! 438: /* element not found - insert a new one ! 439: * the data block for this element should be ! 440: * the user's block with our reference count at ! 441: * the beginning ! 442: */ ! 443: pcounter = tree_addafter(tree, &item, key, NULL, ! 444: length + sizeof(long)); ! 445: *pcounter = 1; ! 446: /* add on size of one long to get the start of the user ! 447: * data ! 448: */ ! 449: datacopy = pcounter + 1; ! 450: if (value != NULL) { ! 451: memcpy(datacopy, value, length); ! 452: } ! 453: return(datacopy); ! 454: } ! 455: ! 456: /* key was already there - increment reference count and ! 457: * return pointer to data ! 458: */ ! 459: ! 460: (*pcounter)++; ! 461: ! 462: /* add on size of one long to get the start of the user ! 463: * data ! 464: */ ! 465: datacopy = pcounter + 1; ! 466: return(datacopy); ! 467: } ! 468: ! 469: /*************************************************************************** ! 470: * Function: ctree_getcount ! 471: * ! 472: * Purpose: ! 473: * ! 474: * Return the reference count for this key ! 475: */ ! 476: long APIENTRY ! 477: ctree_getcount(TREE tree, TREEKEY key) ! 478: { ! 479: long FAR * pcounter; ! 480: ! 481: pcounter = tree_find(tree, key); ! 482: if (pcounter == NULL) { ! 483: return(0); ! 484: } ! 485: return(*pcounter); ! 486: } ! 487: ! 488: /*************************************************************************** ! 489: * Function: ctree_find ! 490: * ! 491: * Purpose: ! 492: * ! 493: * Return a pointer to the user's data block for this key, ! 494: * or NULL if key not present ! 495: */ ! 496: LPVOID APIENTRY ! 497: ctree_find(TREE tree, TREEKEY key) ! 498: { ! 499: long FAR * pcounter; ! 500: ! 501: ! 502: pcounter = tree_find(tree, key); ! 503: if (pcounter == NULL) { ! 504: return(0); ! 505: } ! 506: ! 507: /* increment pointer by size of 1 long to point to ! 508: * user's datablock ! 509: */ ! 510: return(pcounter+1); ! 511: } ! 512: ! 513: ! 514: ! 515: ! 516: ! 517: ! 518: ! 519: ! 520: ! 521: ! 522:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.