Annotation of mstools/samples/sdktools/windiff/tree.c, revision 1.1

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: 

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.