Annotation of mstools/samples/sdktools/windiff/tree.c, revision 1.1.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.