Changeset 83
- Timestamp:
- Jun 28, 2001, 7:13:56 PM (24 years ago)
- Location:
- trunk/src/helpers
- Files:
-
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/helpers/dialog.c
r82 r83 6 6 * 7 7 * See dlghCreateDlg for details. 8 * 9 * In addition, this has dlghMessageBox (a WinMessageBox 10 * replacement) and some helper functions for simulating 11 * dialog behavior in regular window procs (see 12 * dlghSetPrevFocus and others). 8 13 * 9 14 * Usage: All PM programs. … … 82 87 * used, even though the prototype only 83 88 * declares DIALOGDATA. 89 * 90 * This only exists while the dialog is being 91 * created and is not stored with the new dialog. 84 92 */ 85 93 -
trunk/src/helpers/semaphores.c
r78 r83 396 396 397 397 // check if this thread has a reader entry already 398 if (pReader = (PREADERTREENODE)treeFindEQID(&pMutex->ReaderThreadsTree, 399 tidMyself)) // ID to look for 398 if (pReader = (PREADERTREENODE)treeFind(pMutex->ReaderThreadsTree, 399 tidMyself, // ID to look for 400 treeCompareKeys)) 400 401 { 401 402 // yes: … … 418 419 // store the thread ID as the tree ID to 419 420 // sort by (so we can find by TID) 420 pReader->Tree. id= tidMyself;421 pReader->Tree.ulKey = tidMyself; 421 422 // set requests count to 1 422 423 pReader->cRequests = 1; 423 424 424 treeInsert ID(&pMutex->ReaderThreadsTree,425 426 FALSE);425 treeInsert(&pMutex->ReaderThreadsTree, 426 (TREE*)pReader, 427 treeCompareKeys); 427 428 (pMutex->cReaderThreads)++; 428 429 } … … 466 467 467 468 // find the READERTREENODE for our TID 468 if ( (pReader = (PREADERTREENODE)treeFindEQID(&pMutex->ReaderThreadsTree, 469 tidMyself)) // ID to look for 469 if ( (pReader = (PREADERTREENODE)treeFind(pMutex->ReaderThreadsTree, 470 tidMyself, // ID to look for 471 treeCompareKeys)) 470 472 && (pReader->cRequests) 471 473 ) … … 535 537 536 538 // find the READERTREENODE for our TID 537 if ( (!(pReader = (PREADERTREENODE)treeFindEQID(&pMutex->ReaderThreadsTree, 538 tidMyself))) // ID to look for 539 if ( (!(pReader = (PREADERTREENODE)treeFind(pMutex->ReaderThreadsTree, 540 tidMyself, // ID to look for 541 treeCompareKeys))) 539 542 || (pReader->cRequests == 0) 540 543 ) … … 603 606 // check if current TID holds read request also 604 607 PREADERTREENODE pReader 605 = (PREADERTREENODE)treeFindEQID(&pMutex->ReaderThreadsTree, 606 tidMyself); 608 = (PREADERTREENODE)treeFind(pMutex->ReaderThreadsTree, 609 tidMyself, 610 treeCompareKeys); 607 611 // != NULL if this TID has a reader already 608 612 -
trunk/src/helpers/tree.c
r56 r83 4 4 * contains helper functions for maintaining 'Red-Black' balanced 5 5 * binary trees. 6 * See explanations below.7 *8 * This file is all new with V0.9.5 (2000-09-29) [umoeller].9 6 * 10 7 * Usage: All C programs; not OS/2-specific. … … 13 10 * -- tree* tree helper functions 14 11 * 15 * This has been taken from the Standard Function Library (SFL)16 * by iMatix Corporation and changed to user the "id" member for17 * tree sorting/comparison. This implementation is released18 * under the GPL.19 *20 12 * <B>Introduction</B> 21 13 * 22 * Binary trees are different from linked lists in that items 23 * are not simply linked sequentially, but instead put into 24 * a tree-like structure. 25 * 26 * While lists have "next" and "previous" pointers, trees have 27 * "left" and "right" pointers which keep the tree sorted at 28 * all times. 29 * 30 * Per definition, in our trees, if you follow the "left" pointer, 31 * you will reach an item which is "greater than" the current node. 32 * Reversely, following the "right" pointer will lead you to a 33 * node which is "less than" the current node. 34 * 35 * What is considered "less" or "greater" is determined by a 36 * comparison callback to be supplied by the caller. 37 * 38 * For this, the functions here use the TREE structure. You can 39 * easily see that this has the "left" and "right" members, 40 * which make up the tree. 41 * 42 * In addition, each tree has a "tree root" item, from which all 43 * other tree nodes can be reached by following the "left" and 44 * "right" pointers. 45 * 46 * The implementation here has the following characteristics: 47 * 48 * -- We have "binary" trees. That is, there are only "left" and 49 * "right" pointers. 50 * 51 * -- The tree is always "balanced". The tree gets completely 52 * reordered when items are added/removed to ensure that 53 * all paths through the tree are approximately the same 54 * length. This avoids the "worst case" scenario that some 55 * paths grow terribly long while others remain short, which 56 * can make searching very inefficient. 57 * 58 * -- The tree nodes are marked as either "red" or "black", which 59 * is an algorithm to allow the implementation of 2-3-4 trees 60 * using a binary tree only. I don't fully understand how this 61 * works, but essentially, "red" nodes represent a 3 or 4 node, 62 * while "black" nodes are plain binary nodes. 63 * 64 * As much as I understand about all this, red-black balanced 65 * binary trees are the most efficient tree algorithm known to 66 * mankind. As long as you are sure that trees are more efficient 67 * in your situation than a linked list in the first place (see 68 * below for comparisons), use the functions in here. 69 * 70 * <B>Using binary trees</B> 71 * 72 * You can use any structure as elements in a tree, provided 73 * that the first member in the structure is a TREE structure 74 * (i.e. it has the left, right, parent, id, and colour members). 75 * The tree functions don't care what follows, since they do 76 * not manage any memory themselves. 77 * 78 * So the implementation here is slightly different from the 79 * linked lists in linklist.c, because the LISTNODE structs 80 * only have pointers to the data. By contrast, the TREE structs 81 * are expected to contain the data themselves. See treeInsertID() 82 * for a sample. 83 * 84 * Initialize the root of the tree with treeInit(). Then 85 * add nodes to the tree with treeInsertID() and remove nodes 86 * with treeDelete(). 87 * 88 * You can test whether a tree is empty by comparing its 89 * root with TREE_NULL. 90 * 91 * Most functions in here come in two flavors. 92 * 93 * -- You can provide a comparison function and use the "Node" 94 * flavors of these functions. This is useful, for example, 95 * if you are storing strings. You can then write a short 96 * comparison function which does a strcmp() on the data 97 * of tree nodes. 98 * 99 * The order of nodes in the tree is determined by calling a 100 * node comparison function provided by the caller 101 * (which you must write). This must be declared as: 102 * 103 + int TREEENTRY fnMyCompareNodes(TREE *t1, TREE *t2); 104 * 105 * It obviously receives two TREE pointers, which it must 106 * compare and return: 107 * 108 + 0: tree1 == tree2 109 + -1: tree1 < tree2 110 + +1: tree1 > tree2 111 * 112 * -- The "ID" functions (e.g. treeInsertID) do not require 113 * a comparison function, but will use the "id" member of 114 * the TREE structure instead. If this flavor is used, an 115 * internal comparison function is used for comparing the 116 * "id" fields, which are assumed to be plain ULONGs. 14 * While linked lists have "next" and "previous" pointers (which 15 * makes them one-dimensional), trees have a two-dimensional layout: 16 * each tree node has one "parent" and two "children" which are 17 * called "left" and "right". The "left" pointer will always lead 18 * to a tree node that is "less than" its parent node, while the 19 * "right" pointer will lead to a node that is "greater than" 20 * its parent. What is considered "less" or "greater" for sorting 21 * is determined by a comparison callback to be supplied by the 22 * tree functions' caller. The "leafs" of the tree will have 23 * null left and right pointers. 24 * 25 * For this, the functions here use the TREE structure. The most 26 * important member here is the "ulKey" field which is used for 27 * sorting (passed to the compare callbacks). Since the tree 28 * functions do no memory allocation, the caller can easily 29 * use an extended TREE structure with additional fields as 30 * long as the first member is the TREE structure. See below. 31 * 32 * Each tree must have a "root" item, from which all other tree 33 * nodes can eventually be reached by following the "left" and 34 * "right" pointers. The root node is the only node whose 35 * parent is null. 117 36 * 118 37 * <B>Trees vs. linked lists</B> 119 38 * 120 39 * Compared to linked lists (as implemented by linklist.c), 121 * trees allow for much faster searching. 40 * trees allow for much faster searching, since they are 41 * always sorted. 42 * 43 * Take an array of numbers, and assume you'd need to find 44 * the array node with the specified number. 45 * 46 * With a (sorted) linked list, this would look like: 47 * 48 + 4 --> 7 --> 16 --> 20 --> 37 --> 38 --> 43 49 * 50 * Searching for "43" would need 6 iterations. 51 * 52 * With a binary tree, this would instead look like: 53 * 54 + 20 55 + / \ 56 + 7 38 57 + / \ / \ 58 + 4 16 37 43 59 + / \ / \ / \ / \ 60 * 61 * Searching for "43" would need 2 iterations only. 122 62 * 123 63 * Assuming a linked list contains N items, then searching a … … 131 71 * average. 132 72 * 133 * Example: You need to build a list of files, and you134 * will search the list frequently according to the file135 * handles. This would make the handle an ideal "id" field.136 *137 73 * Differences compared to linklist.c: 74 * 75 * -- A tree is always sorted. 138 76 * 139 77 * -- Trees are considerably slower when inserting and removing … … 142 80 * nodes because the tree is always sorted. 143 81 * 144 * -- If you are not using the "ID" flavors, you must supply a145 * comparison function to allow the tree functions to sort the tree.146 *147 82 * -- As opposed to a LISTNODE, the TREE structure (which 148 83 * represents a tree node) does not contain a data pointer, 149 84 * as said above. The caller must do all memory management. 150 85 * 86 * <B>Background</B> 87 * 88 * Now, a "red-black balanced binary tree" means the following: 89 * 90 * -- We have "binary" trees. That is, there are only "left" and 91 * "right" pointers. (Other algorithms allow tree nodes to 92 * have more than two children, but binary trees are usually 93 * more efficient.) 94 * 95 * -- The tree is always "balanced". The tree gets reordered 96 * when items are added/removed to ensure that all paths 97 * through the tree are approximately the same length. 98 * This avoids the "worst case" scenario that some paths 99 * grow terribly long while others remain short ("degenerated" 100 * trees), which can make searching very inefficient: 101 * 102 + 4 103 + / \ 104 + 7 105 + / \ 106 + 16 107 + / \ 108 + 20 109 + / \ 110 + 37 111 + / \ 112 + 43 113 + / \ 114 * 115 * -- Fully balanced trees can be quite expensive because on 116 * every insertion or deletion, the tree nodes must be reordered. 117 * By contrast, "Red-black" binary balanced trees contain 118 * an additional bit in each node which marks the node as 119 * either red or black. This bit is used only for efficient 120 * rebalancing when inserting or deleting nodes. 121 * 122 * The color of each node is instrumental in determining the 123 * balance of the tree. During insert and delete operations, 124 * nodes may be rotated to maintain tree balance. 125 * 126 * I don't fully understand why this works, but if you really 127 * care, this is explained at 128 * "http://www.eli.sdsu.edu/courses/fall96/cs660/notes/redBlack/redBlack.html". 129 * 130 * In other words, as opposed to regular binary trees, RB trees 131 * are not _fully_ balanced, but they are _mostly_ balanced. With 132 * respect to efficiency, RB trees are thus a good compromise: 133 * 134 * -- Completely unbalanced trees are efficient when inserting, 135 * but can have a terrible worst case when searching. 136 * 137 * -- RB trees are still acceptably efficient when inserting 138 * and quite efficient when searching. 139 * A RB tree with n internal nodes has a height of at most 140 * 2lg(n+1). Both average and worst-case search time is O(lg n). 141 * 142 * -- Fully balanced binary trees are inefficient when inserting 143 * but most efficient when searching. 144 * 145 * So as long as you are sure that trees are more efficient 146 * in your situation than a linked list in the first place, use 147 * these RB trees instead of linked lists. 148 * 149 * <B>Using binary trees</B> 150 * 151 * You can use any structure as elements in a tree, provided 152 * that the first member in the structure is a TREE structure 153 * (i.e. it has the left, right, parent, and color members). 154 * Each TREE node has a ulKey field which is used for 155 * comparing tree nodes and thus determines the location of 156 * the node in the tree. 157 * 158 * The tree functions don't care what follows in each TREE 159 * node since they do not manage any memory themselves. 160 * So the implementation here is slightly different from the 161 * linked lists in linklist.c, because the LISTNODE structs 162 * only have pointers to the data. By contrast, the TREE structs 163 * are expected to contain the data themselves. 164 * 165 * Initialize the root of the tree with treeInit(). Then 166 * add nodes to the tree with treeInsert() and remove nodes 167 * with treeDelete(). See below for a sample. 168 * 169 * You can test whether a tree is empty by comparing its 170 * root with LEAF. 171 * 172 * For most tree* functions, you must specify a comparison 173 * function which will always receive two "key" parameters 174 * to compare. This must be declared as 175 + 176 + int TREEENTRY fnCompare(ULONG ul1, ULONG ul2); 177 * 178 * This will receive two TREE.ulKey members (whose meaning 179 * is defined by your implementation) and must return 180 * 181 * -- something < 0: ul1 < ul2 182 * -- 0: ul1 == ul2 183 * -- something > 1: ul1 > ul2 184 * 185 * <B>Example</B> 186 * 187 * A good example where trees are efficient would be the 188 * case where you have "keyword=value" string pairs and 189 * you frequently need to search for "keyword" to find 190 * a "value". So "keyword" would be an ideal candidate for 191 * the TREE.key field. 192 * 193 * You'd then define your own tree nodes like this: 194 * 195 + typedef struct _MYTREENODE 196 + { 197 + TREE Tree; // regular tree node, which has 198 + // the ULONG "key" field; we'd 199 + // use this as a const char* 200 + // pointer to the keyword string 201 + // here come the additional fields 202 + // (whatever you need for your data) 203 + const char *pcszValue; 204 + 205 + } MYTREENODE, *PMYTREENODE; 206 * 207 * Initialize the tree root: 208 * 209 + TREE *root; 210 + treeInit(&root); 211 * 212 * To add a new "keyword=value" pair, do this: 213 * 214 + PMYTREENODE AddNode(TREE **root, 215 + const char *pcszKeyword, 216 + const char *pcszValue) 217 + { 218 + PMYTREENODE p = (PMYTREENODE)malloc(sizeof(MYTREENODE)); 219 + p.Tree.ulKey = (ULONG)pcszKeyword; 220 + p.pcszValue = pcszValue; 221 + treeInsert(root, // tree's root 222 + p, // new tree node 223 + fnCompare); // comparison func 224 + return (p); 225 + } 226 * 227 * Your comparison func receives two ulKey values to compare, 228 * which in this case would be the typecast string pointers: 229 * 230 + int TREEENTRY fnCompare(ULONG ul1, ULONG ul2) 231 + { 232 + return (strcmp((const char*)ul1, 233 + (const char*)ul2)); 234 + } 235 * 236 * You can then use treeFind to very quickly find a node 237 * with a specified ulKey member. 238 * 239 * This file was new with V0.9.5 (2000-09-29) [umoeller]. 240 * With V0.9.13, all the code has been replaced with the public 241 * domain code found at http://epaperpress.com/sortsearch/index.html 242 * ("A compact guide to searching and sorting") by Thomas Niemann. 243 * The old implementation from the Standard Function Library (SFL) 244 * turned out to be buggy for large trees (more than 100 nodes). 245 * 151 246 *@@added V0.9.5 (2000-09-29) [umoeller] 152 247 *@@header "helpers\tree.h" … … 154 249 155 250 /* 156 * Written: 97/11/18 Jonathan Schultz <jonathan@imatix.com> 157 * Revised: 98/12/08 Jonathan Schultz <jonathan@imatix.com> 158 * 159 * Copyright (C) 1991-99 iMatix Corporation. 160 * Copyright (C) 2000 Ulrich Mller. 251 * Original coding by Thomas Niemann, placed in the public domain 252 * (see http://epaperpress.com/sortsearch/index.html). 253 * 254 * This implementation Copyright (C) 2001 Ulrich Mller. 161 255 * This file is part of the "XWorkplace helpers" source package. 162 256 * This is free software; you can redistribute it and/or modify … … 178 272 #include "helpers\tree.h" 179 273 180 // Constants 181 TREE TREE_EMPTY = {TREE_NULL, TREE_NULL, NULL, BLACK}; 182 183 // Internal function prototypes 184 static void insert_fixup(TREE **root, TREE *tree); 185 static void rotate_left(TREE **root, TREE *tree); 186 static void rotate_right(TREE **root, TREE *tree); 187 static void delete_fixup(TREE **root, TREE *tree); 274 #define LEAF &sentinel // all leafs are sentinels 275 static TREE sentinel = { LEAF, LEAF, 0, BLACK}; 276 277 /* 278 A binary search tree is a red-black tree if: 279 280 1. Every node is either red or black. 281 2. Every leaf (nil) is black. 282 3. If a node is red, then both its children are black. 283 4. Every simple path from a node to a descendant leaf contains the same 284 number of black nodes. 285 */ 188 286 189 287 /* 190 288 *@@ treeInit: 191 * initializes an empty tree. The data on the 192 * tree will be invalid, and no memory will be 193 * freed. 194 * 195 * Usage: 196 + TREE *TreeRoot; 197 + treeInit(&TreeRoot); 289 * initializes the root of a tree. 290 * 198 291 */ 199 292 200 293 void treeInit(TREE **root) 201 294 { 202 *root = TREE_NULL;203 } 204 205 /* 206 * fnCompareIDs:207 * 208 * added V0.9.9 (2001-02-06) [umoeller]209 */ 210 211 int TREEENTRY fnCompareIDs(unsigned long id1, unsigned long id2)212 { 213 if ( id1 < id2)295 *root = LEAF; 296 } 297 298 /* 299 *@@ treeCompareKeys: 300 * standard comparison func if the TREE.ulKey 301 * field really is a ULONG. 302 */ 303 304 int TREEENTRY treeCompareKeys(unsigned long ul1, unsigned long ul2) 305 { 306 if (ul1 < ul2) 214 307 return -1; 215 if ( id1 > id2)308 if (ul1 > ul2) 216 309 return +1; 217 310 return (0); … … 219 312 220 313 /* 221 *@@ treeInsertID: 222 * inserts a node into an existing tree. 223 * 224 * Note: A tree node MUST contain a TREE structure 225 * at the beginning for the tree functions to work. 226 * So to create a tree node with usable data, do this: 227 * 228 + typedef _MYTREENODE 229 + { 230 + // TREE must be at beginning 231 + TREE Tree; 232 + // now use whatever you want 233 + CHAR szMyExtraData[100]; 234 + } MYTREENODE, *PMYTREENODE; 235 * 236 * When calling the tree functions, manually cast your 237 * MYTREENODE pointers to (TREE*). 238 * 239 * This function initialises the node pointers and colour 240 * in the TREE structure to correct values, so the caller 241 * does not have to worry about those. 242 * 243 * However you must initialize the TREE.id member correctly 244 * so that your comparison function can compare on that 245 * to find the correct place in the tree to insert the node. 246 * 247 * Usage: 248 + TREE *TreeRoot; 249 + treeInit(&TreeRoot); 250 + 251 + PMYTREENODE pTreeItem = malloc(sizeof(MYTREENODE)); 252 + pTreeItem->Tree.id = 1; 253 + 254 + treeInsertID(&TreeRoot, 255 + (TREE*)pTreeItem, 256 + FALSE); 257 * 258 * Returns: 259 * 260 * -- TREE_OK: OK, item inserted. 261 * 262 * -- TREE_DUPLICATE: if (fAllowDuplicates == FALSE), this is 263 * returned if a tree item with the specified ID already 264 * exists. 265 * 266 *@@changed V0.9.9 (2001-02-06) [umoeller]: removed comparison func 267 */ 268 269 int treeInsertID(TREE **root, // in: root of tree 270 TREE *tree, // in: new tree node 271 BOOL fAllowDuplicates) // in: whether duplicates with the same ID are allowed 314 *@@ rotateLeft: 315 * private function during rebalancing. 316 */ 317 318 static void rotateLeft(TREE **root, 319 TREE *x) 320 { 321 /************************** 322 * rotate node x to left * 323 **************************/ 324 325 TREE *y = x->right; 326 327 // establish x->right link 328 x->right = y->left; 329 if (y->left != LEAF) 330 y->left->parent = x; 331 332 // establish y->parent link 333 if (y != LEAF) 334 y->parent = x->parent; 335 if (x->parent) 336 { 337 if (x == x->parent->left) 338 x->parent->left = y; 339 else 340 x->parent->right = y; 341 } 342 else 343 *root = y; 344 345 // link x and y 346 y->left = x; 347 if (x != LEAF) 348 x->parent = y; 349 } 350 351 /* 352 *@@ rotateRight: 353 * private function during rebalancing. 354 */ 355 356 static void rotateRight(TREE **root, 357 TREE *x) 358 { 359 360 /**************************** 361 * rotate node x to right * 362 ****************************/ 363 364 TREE *y = x->left; 365 366 // establish x->left link 367 x->left = y->right; 368 if (y->right != LEAF) 369 y->right->parent = x; 370 371 // establish y->parent link 372 if (y != LEAF) 373 y->parent = x->parent; 374 if (x->parent) 375 { 376 if (x == x->parent->right) 377 x->parent->right = y; 378 else 379 x->parent->left = y; 380 } 381 else 382 *root = y; 383 384 // link x and y 385 y->right = x; 386 if (x != LEAF) 387 x->parent = y; 388 } 389 390 /* 391 *@@ insertFixup: 392 * private function during rebalancing. 393 */ 394 395 static void insertFixup(TREE **root, 396 TREE *x) 397 { 398 /************************************* 399 * maintain Red-Black tree balance * 400 * after inserting node x * 401 *************************************/ 402 403 // check Red-Black properties 404 while ( x != *root 405 && x->parent->color == RED 406 ) 407 { 408 // we have a violation 409 if (x->parent == x->parent->parent->left) 410 { 411 TREE *y = x->parent->parent->right; 412 if (y->color == RED) 413 { 414 // uncle is RED 415 x->parent->color = BLACK; 416 y->color = BLACK; 417 x->parent->parent->color = RED; 418 x = x->parent->parent; 419 } 420 else 421 { 422 // uncle is BLACK 423 if (x == x->parent->right) 424 { 425 // make x a left child 426 x = x->parent; 427 rotateLeft(root, 428 x); 429 } 430 431 // recolor and rotate 432 x->parent->color = BLACK; 433 x->parent->parent->color = RED; 434 rotateRight(root, 435 x->parent->parent); 436 } 437 } 438 else 439 { 440 // mirror image of above code 441 TREE *y = x->parent->parent->left; 442 if (y->color == RED) 443 { 444 // uncle is RED 445 x->parent->color = BLACK; 446 y->color = BLACK; 447 x->parent->parent->color = RED; 448 x = x->parent->parent; 449 } 450 else 451 { 452 // uncle is BLACK 453 if (x == x->parent->left) 454 { 455 x = x->parent; 456 rotateRight(root, 457 x); 458 } 459 x->parent->color = BLACK; 460 x->parent->parent->color = RED; 461 rotateLeft(root, 462 x->parent->parent); 463 } 464 } 465 } 466 (*root)->color = BLACK; 467 } 468 469 /* 470 *@@ treeInsert: 471 * inserts a new tree node into the specified 472 * tree, using the specified comparison function 473 * for sorting. 474 * 475 * "x" specifies the new tree node which must 476 * have been allocated by the caller. x->ulKey 477 * must already contain the node's key (data). 478 * This function will then set the parent, 479 * left, right, and color members. 480 * 481 * Returns 0 if no error. Might return 482 * STATUS_DUPLICATE_KEY if a node with the 483 * same ulKey already exists. 484 */ 485 486 int treeInsert(TREE **root, // in: root of the tree 487 TREE *x, // in: new node to insert 488 FNTREE_COMPARE *pfnCompare) // in: comparison func 272 489 { 273 490 TREE *current, 274 491 *parent; 275 int last_comp = 0; 276 277 // find where node belongs 492 493 unsigned long key = x->ulKey; 494 495 // find future parent 278 496 current = *root; 279 parent = NULL; 280 while (current != TREE_NULL) 281 { 282 parent = current; 283 last_comp = fnCompareIDs(tree->id, current->id); 284 switch (last_comp) 285 { 286 case -1: current = current->left; break; 287 case 1: current = current->right; break; 288 default: 289 if (fAllowDuplicates) 290 current = current->left; 291 else 292 return TREE_DUPLICATE; 293 } 497 parent = 0; 498 499 while (current != LEAF) 500 { 501 int iResult; 502 if (0 == (iResult = pfnCompare(key, current->ulKey))) // if (compEQ(key, current->key)) 503 return STATUS_DUPLICATE_KEY; 504 parent = current; 505 current = (iResult < 0) // compLT(key, current->key) 506 ? current->left 507 : current->right; 294 508 } 295 509 296 510 // set up new node 297 ((TREE*)tree)->parent = parent; 298 ((TREE*)tree)->left = TREE_NULL; 299 ((TREE*)tree)->right = TREE_NULL; 300 ((TREE*)tree)->colour = RED; 511 /* if ((x = malloc (sizeof(*x))) == 0) 512 return STATUS_MEM_EXHAUSTED; */ 513 x->parent = parent; 514 x->left = LEAF; 515 x->right = LEAF; 516 x->color = RED; 517 // x->key = key; 518 // x->rec = *rec; 301 519 302 520 // insert node in tree 303 521 if (parent) 304 switch (last_comp) 305 { 306 case 1: parent->right = tree; break; 307 default: parent->left = tree; 308 } 522 { 523 if (pfnCompare(key, parent->ulKey) < 0) // (compLT(key, parent->key)) 524 parent->left = x; 525 else 526 parent->right = x; 527 } 309 528 else 310 *root = tree; 311 312 insert_fixup(root, tree); 313 return(TREE_OK); 314 } 315 316 /* 317 *@@ treeInsertNode: 318 * similar to treeInsertID, but this uses 319 * a comparision function which compares 320 * nodes. 321 */ 322 323 int treeInsertNode(TREE **root, // in: root of tree 324 TREE *tree, // in: new tree node 325 FNTREE_COMPARE_NODES *comp, // in: comparison function 326 BOOL fAllowDuplicates) // in: whether duplicates with the same ID are allowed 327 { 328 TREE 329 *current, 330 *parent; 331 int 332 last_comp = 0; 333 334 // find where node belongs 335 current = *root; 336 parent = NULL; 337 while (current != TREE_NULL) 338 { 339 parent = current; 340 last_comp = comp(tree, current); 341 switch (last_comp) 342 { 343 case -1: current = current->left; break; 344 case 1: current = current->right; break; 345 default: if (fAllowDuplicates) 346 current = current->left; 347 else 348 return TREE_DUPLICATE; 349 350 } 351 } 352 353 // set up new node 354 ((TREE*)tree)->parent = parent; 355 ((TREE*)tree)->left = TREE_NULL; 356 ((TREE*)tree)->right = TREE_NULL; 357 ((TREE*)tree)->colour = RED; 358 359 // insert node in tree 360 if (parent) 361 switch (last_comp) 362 { 363 case 1: parent->right = tree; break; 364 default: parent->left = tree; 365 } 529 *root = x; 530 531 insertFixup(root, 532 x); 533 // lastFind = NULL; 534 535 return STATUS_OK; 536 } 537 538 /* 539 *@@ deleteFixup: 540 * 541 */ 542 543 static void deleteFixup(TREE **root, 544 TREE *tree) 545 { 546 TREE *s; 547 548 while ( tree != *root 549 && tree->color == BLACK 550 ) 551 { 552 if (tree == tree->parent->left) 553 { 554 s = tree->parent->right; 555 if (s->color == RED) 556 { 557 s->color = BLACK; 558 tree->parent->color = RED; 559 rotateLeft(root, tree->parent); 560 s = tree->parent->right; 561 } 562 if ( (s->left->color == BLACK) 563 && (s->right->color == BLACK) 564 ) 565 { 566 s->color = RED; 567 tree = tree->parent; 568 } 569 else 570 { 571 if (s->right->color == BLACK) 572 { 573 s->left->color = BLACK; 574 s->color = RED; 575 rotateRight(root, s); 576 s = tree->parent->right; 577 } 578 s->color = tree->parent->color; 579 tree->parent->color = BLACK; 580 s->right->color = BLACK; 581 rotateLeft(root, tree->parent); 582 tree = *root; 583 } 584 } 585 else 586 { 587 s = tree->parent->left; 588 if (s->color == RED) 589 { 590 s->color = BLACK; 591 tree->parent->color = RED; 592 rotateRight(root, tree->parent); 593 s = tree->parent->left; 594 } 595 if ( (s->right->color == BLACK) 596 && (s->left->color == BLACK) 597 ) 598 { 599 s->color = RED; 600 tree = tree->parent; 601 } 602 else 603 { 604 if (s->left->color == BLACK) 605 { 606 s->right->color = BLACK; 607 s->color = RED; 608 rotateLeft(root, s); 609 s = tree->parent->left; 610 } 611 s->color = tree->parent->color; 612 tree->parent->color = BLACK; 613 s->left->color = BLACK; 614 rotateRight (root, tree->parent); 615 tree = *root; 616 } 617 } 618 } 619 tree->color = BLACK; 620 621 /************************************* 622 * maintain Red-Black tree balance * 623 * after deleting node x * 624 *************************************/ 625 626 /* while ( x != *root 627 && x->color == BLACK 628 ) 629 { 630 if (x == x->parent->left) 631 { 632 TREE *w = x->parent->right; 633 if (w->color == RED) 634 { 635 w->color = BLACK; 636 x->parent->color = RED; 637 rotateLeft(root, 638 x->parent); 639 w = x->parent->right; 640 } 641 if ( w->left->color == BLACK 642 && w->right->color == BLACK 643 ) 644 { 645 w->color = RED; 646 x = x->parent; 647 } 648 else 649 { 650 if (w->right->color == BLACK) 651 { 652 w->left->color = BLACK; 653 w->color = RED; 654 rotateRight(root, 655 w); 656 w = x->parent->right; 657 } 658 w->color = x->parent->color; 659 x->parent->color = BLACK; 660 w->right->color = BLACK; 661 rotateLeft(root, 662 x->parent); 663 x = *root; 664 } 665 } 666 else 667 { 668 TREE *w = x->parent->left; 669 if (w->color == RED) 670 { 671 w->color = BLACK; 672 x->parent->color = RED; 673 rotateRight(root, 674 x->parent); 675 w = x->parent->left; 676 } 677 if ( w->right->color == BLACK 678 && w->left->color == BLACK 679 ) 680 { 681 w->color = RED; 682 x = x->parent; 683 } 684 else 685 { 686 if (w->left->color == BLACK) 687 { 688 w->right->color = BLACK; 689 w->color = RED; 690 rotateLeft(root, 691 w); 692 w = x->parent->left; 693 } 694 w->color = x->parent->color; 695 x->parent->color = BLACK; 696 w->left->color = BLACK; 697 rotateRight(root, 698 x->parent); 699 x = *root; 700 } 701 } 702 } 703 x->color = BLACK; */ 704 } 705 706 /* 707 *@@ treeDelete: 708 * removes the specified node from the tree. 709 * Does not free() the node though. 710 * 711 * Returns 0 if the node was deleted or 712 * STATUS_INVALID_NODE if not. 713 */ 714 715 int treeDelete(TREE **root, // in: root of the tree 716 TREE *tree) // in: tree node to delete 717 { 718 TREE *y, 719 *d; 720 nodeColor color; 721 722 if ( (!tree) 723 || (tree == LEAF) 724 ) 725 return STATUS_INVALID_NODE; 726 727 if ( (tree->left == LEAF) 728 || (tree->right == LEAF) 729 ) 730 // d has a TREE_NULL node as a child 731 d = tree; 366 732 else 367 *root = tree; 368 369 insert_fixup(root, tree); 370 return(TREE_OK); 371 } 372 373 /* 374 * insert_fixup: 375 * maintains the Red-Black tree balance after a node has been inserted. 376 * 377 * Private function. 378 */ 379 380 static void insert_fixup(TREE **root, 381 TREE *tree) 382 { 383 TREE *uncle; 384 385 // check red-black properties 386 while ((tree != *root) 387 && (tree->parent->colour == RED)) 388 { 389 // we have a violation 390 if (tree->parent == tree->parent->parent->left) 391 { 392 uncle = tree->parent->parent->right; 393 if (uncle->colour == RED) 394 { 395 // uncle is RED 396 tree ->parent->colour = BLACK; 397 uncle->colour = BLACK; 398 tree ->parent->parent->colour = RED; 399 400 tree = tree->parent->parent; 401 } 733 { 734 // find tree successor with a TREE_NULL node as a child 735 d = tree->right; 736 while (d->left != LEAF) 737 d = d->left; 738 } 739 740 // y is d's only child, if there is one, else TREE_NULL 741 if (d->left != LEAF) 742 y = d->left; 743 else 744 y = d->right; 745 746 // remove d from the parent chain 747 if (y != LEAF) 748 y->parent = d->parent; 749 if (d->parent) 750 { 751 if (d == d->parent->left) 752 d->parent->left = y; 753 else 754 d->parent->right = y; 755 } 756 else 757 *root = y; 758 759 color = d->color; 760 761 if (d != tree) 762 { 763 // move the data from d to tree; we do this by 764 // linking d into the structure in the place of tree 765 d->left = tree->left; 766 d->right = tree->right; 767 d->parent = tree->parent; 768 d->color = tree->color; 769 770 if (d->parent) 771 { 772 if (tree == d->parent->left) 773 d->parent->left = d; 402 774 else 403 { 404 // uncle is BLACK 405 if (tree == tree->parent->right) 406 { 407 // make tree a left child 408 tree = tree->parent; 409 rotate_left (root, tree); 410 } 411 412 // recolor and rotate 413 tree->parent->colour = BLACK; 414 tree->parent->parent->colour = RED; 415 rotate_right (root, tree->parent->parent); 416 } 775 d->parent->right = d; 417 776 } 418 777 else 419 { 420 // mirror image of above code 421 uncle = tree->parent->parent->left; 422 if (uncle->colour == RED) 423 { 424 // uncle is RED 425 tree ->parent->colour = BLACK; 426 uncle->colour = BLACK; 427 tree ->parent->parent->colour = RED; 428 429 tree = tree->parent->parent; 430 } 778 *root = d; 779 780 if (d->left != LEAF) 781 d->left->parent = d; 782 783 if (d->right != LEAF) 784 d->right->parent = d; 785 } 786 787 if ( (y != LEAF) 788 && (color == BLACK) 789 ) 790 deleteFixup(root, 791 y); 792 793 return (STATUS_OK); 794 795 /* TREE *x, 796 *y; */ 797 // *z; 798 799 /***************************** 800 * delete node z from tree * 801 *****************************/ 802 803 // find node in tree 804 /* if (lastFind && compEQ(lastFind->key, key)) 805 // if we just found node, use pointer 806 z = lastFind; 807 else { 808 z = *root; 809 while(z != LEAF) 810 { 811 int iResult = pfnCompare(key, z->key); 812 if (iResult == 0) 813 // if(compEQ(key, z->key)) 814 break; 431 815 else 432 { 433 // uncle is BLACK 434 if (tree == tree->parent->left) 435 { 436 tree = tree->parent; 437 rotate_right (root, tree); 438 } 439 tree->parent->colour = BLACK; 440 tree->parent->parent->colour = RED; 441 rotate_left (root, tree->parent->parent); 442 } 443 } 444 } 445 (*root)->colour = BLACK; 446 } 447 448 /* 449 * rotate_left: 450 * rotates tree to left. 451 * 452 * Private function. 453 */ 454 455 static void rotate_left(TREE **root, 456 TREE *tree) 457 { 458 TREE *other = tree->right; 459 460 // establish tree->right link 461 tree->right = other->left; 462 if (other->left != TREE_NULL) 463 other->left->parent = tree; 464 465 // establish other->parent link 466 if (other != TREE_NULL) 467 other->parent = tree->parent; 468 469 if (tree->parent) 470 { 471 if (tree == tree->parent->left) 472 tree->parent->left = other; 816 z = (iResult < 0) // compLT(key, z->key) 817 ? z->left 818 : z->right; 819 } 820 if (z == LEAF) 821 return STATUS_KEY_NOT_FOUND; 822 } 823 824 if ( z->left == LEAF 825 || z->right == LEAF 826 ) 827 { 828 // y has a LEAF node as a child 829 y = z; 830 } 831 else 832 { 833 // find tree successor with a LEAF node as a child 834 y = z->right; 835 while (y->left != LEAF) 836 y = y->left; 837 } 838 839 // x is y's only child 840 if (y->left != LEAF) 841 x = y->left; 842 else 843 x = y->right; 844 845 // remove y from the parent chain 846 x->parent = y->parent; 847 if (y->parent) 848 if (y == y->parent->left) 849 y->parent->left = x; 473 850 else 474 tree->parent->right = other; 475 } 851 y->parent->right = x; 476 852 else 477 *root = other; 478 479 // link tree and other 480 other->left = tree; 481 if (tree != TREE_NULL) 482 tree->parent = other; 483 } 484 485 /* 486 * rotate_right: 487 * rotates tree to right. 488 * 489 * Private function. 490 */ 491 492 static void rotate_right(TREE **root, 493 TREE *tree) 494 { 495 TREE *other; 496 497 other = tree->left; 498 499 // establish tree->left link 500 tree->left = other->right; 501 if (other->right != TREE_NULL) 502 other->right->parent = tree; 503 504 // establish other->parent link 505 if (other != TREE_NULL) 506 other->parent = tree->parent; 507 508 if (tree->parent) 509 { 510 if (tree == tree->parent->right) 511 tree->parent->right = other; 853 *root = x; 854 855 // y is about to be deleted... 856 857 if (y != z) 858 { 859 // now, the original code simply copied the data 860 // from y to z... we can't safely do that since 861 // we don't know about the real data in the 862 // caller's TREE structure 863 z->ulKey = y->ulKey; 864 // z->rec = y->rec; // hope this works... 865 // the original implementation used rec 866 // for the node's data 867 868 if (cbStruct > sizeof(TREE)) 869 { 870 memcpy(((char*)&z) + sizeof(TREE), 871 ((char*)&y) + sizeof(TREE), 872 cbStruct - sizeof(TREE)); 873 } 874 } 875 876 if (y->color == BLACK) 877 deleteFixup(root, 878 x); 879 880 // free(y); 881 // lastFind = NULL; 882 883 return STATUS_OK; */ 884 } 885 886 /* 887 *@@ treeFind: 888 * finds the tree node with the specified key. 889 */ 890 891 TREE* treeFind(TREE *root, // in: root of the tree 892 unsigned long key, // in: key to find 893 FNTREE_COMPARE *pfnCompare) // in: comparison func 894 { 895 /******************************* 896 * find node containing data * 897 *******************************/ 898 899 TREE *current = root; 900 while (current != LEAF) 901 { 902 int iResult; 903 if (0 == (iResult = pfnCompare(key, current->ulKey))) 904 return (current); 512 905 else 513 tree->parent->left = other; 514 } 515 else 516 *root = other; 517 518 // link tree and other 519 other->right = tree; 520 if (tree != TREE_NULL) 521 tree->parent = other; 522 } 523 524 /* 525 *@@ treeDelete: 526 * deletes a node from a tree. Does not deallocate any memory. 527 * 528 * Returns: 529 * 530 * -- TREE_OK: node deleted. 531 * -- TREE_INVALID_NODE: tree node not found. 532 */ 533 534 int treeDelete(TREE **root, // in: root of tree 535 TREE *tree) // in: tree node to delete 536 { 537 int irc = TREE_OK; 538 539 TREE 540 *youngest, *descendent; 541 TREE_COLOUR 542 colour; 543 544 if ( (!tree) 545 || (tree == TREE_NULL) 546 ) 547 return TREE_INVALID_NODE; 548 549 if ( (((TREE*)tree)->left == TREE_NULL) 550 || (((TREE*)tree)->right == TREE_NULL) 551 ) 552 // descendent has a TREE_NULL node as a child 553 descendent = tree; 554 else 555 { 556 // find tree successor with a TREE_NULL node as a child 557 descendent = ((TREE*)tree)->right; 558 while (descendent->left != TREE_NULL) 559 descendent = descendent->left; 560 } 561 562 // youngest is descendent's only child, if there is one, else TREE_NULL 563 if (descendent->left != TREE_NULL) 564 youngest = descendent->left; 565 else 566 youngest = descendent->right; 567 568 // remove descendent from the parent chain 569 if (youngest != TREE_NULL) 570 youngest->parent = descendent->parent; 571 if (descendent->parent) 572 { 573 if (descendent == descendent->parent->left) 574 descendent->parent->left = youngest; 575 else 576 descendent->parent->right = youngest; 577 } 578 else 579 *root = youngest; 580 581 colour = descendent->colour; 582 583 if (descendent != (TREE *) tree) 584 { 585 // Conceptually what we are doing here is moving the data from 586 // descendent to tree. In fact we do this by linking descendent 587 // into the structure in the place of tree. 588 descendent->left = ((TREE*)tree)->left; 589 descendent->right = ((TREE*)tree)->right; 590 descendent->parent = ((TREE*)tree)->parent; 591 descendent->colour = ((TREE*)tree)->colour; 592 593 if (descendent->parent) 594 { 595 if (tree == descendent->parent->left) 596 descendent->parent->left = descendent; 597 else 598 descendent->parent->right = descendent; 599 } 600 else 601 *root = descendent; 602 603 if (descendent->left != TREE_NULL) 604 descendent->left->parent = descendent; 605 606 if (descendent->right != TREE_NULL) 607 descendent->right->parent = descendent; 608 } 609 610 if ( (youngest != TREE_NULL) 611 && (colour == BLACK)) 612 delete_fixup (root, youngest); 613 614 return (irc); 615 } 616 617 /* 618 *@@ delete_fixup: 619 * maintains Red-Black tree balance after deleting a node. 620 * 621 * Private function. 622 */ 623 624 static void delete_fixup(TREE **root, 625 TREE *tree) 626 { 627 TREE 628 *sibling; 629 630 while (tree != *root && tree->colour == BLACK) 631 { 632 if (tree == tree->parent->left) 633 { 634 sibling = tree->parent->right; 635 if (sibling->colour == RED) 636 { 637 sibling->colour = BLACK; 638 tree->parent->colour = RED; 639 rotate_left (root, tree->parent); 640 sibling = tree->parent->right; 641 } 642 if ((sibling->left->colour == BLACK) 643 && (sibling->right->colour == BLACK)) 644 { 645 sibling->colour = RED; 646 tree = tree->parent; 647 } 648 else 649 { 650 if (sibling->right->colour == BLACK) 651 { 652 sibling->left->colour = BLACK; 653 sibling->colour = RED; 654 rotate_right (root, sibling); 655 sibling = tree->parent->right; 656 } 657 sibling->colour = tree->parent->colour; 658 tree->parent->colour = BLACK; 659 sibling->right->colour = BLACK; 660 rotate_left (root, tree->parent); 661 tree = *root; 662 } 663 } 664 else 665 { 666 sibling = tree->parent->left; 667 if (sibling->colour == RED) 668 { 669 sibling->colour = BLACK; 670 tree->parent->colour = RED; 671 rotate_right (root, tree->parent); 672 sibling = tree->parent->left; 673 } 674 if ((sibling->right->colour == BLACK) 675 && (sibling->left->colour == BLACK)) 676 { 677 sibling->colour = RED; 678 tree = tree->parent; 679 } 680 else 681 { 682 if (sibling->left->colour == BLACK) 683 { 684 sibling->right->colour = BLACK; 685 sibling->colour = RED; 686 rotate_left (root, sibling); 687 sibling = tree->parent->left; 688 } 689 sibling->colour = tree->parent->colour; 690 tree->parent->colour = BLACK; 691 sibling->left->colour = BLACK; 692 rotate_right (root, tree->parent); 693 tree = *root; 694 } 695 } 696 } 697 tree->colour = BLACK; 698 } 699 700 /* 701 *@@ treeFindEQID: 702 * finds a node with ID exactly matching that provided. 703 * Returns NULL if not found. 704 */ 705 706 void* treeFindEQID(TREE **root, 707 unsigned long id) 708 { 709 TREE *current = *root, 710 *found = NULL; 711 712 while (current != TREE_NULL) 713 switch (fnCompareIDs(current->id, id)) 714 { 715 case -1: current = current->right; break; 716 case 1: current = current->left; break; 717 default: found = current; // In case of duplicates, 718 current = current->left; // get the first one. 719 } 720 721 return found; 722 } 723 724 /* 725 *@@ treeFindGEID: 726 * finds a node with ID greater than or equal to provided. 727 * To find a tree node, your comparison function must 728 * compare the tree node IDs. 729 */ 730 731 void* treeFindGEID(TREE **root, 732 unsigned long idFind) 733 { 734 TREE *current = *root, 735 *found; 736 737 found = NULL; 738 while (current != TREE_NULL) 739 switch (fnCompareIDs(current->id, idFind)) 740 { 741 case -1: current = current->right; break; 742 default: found = current; 743 current = current->left; 744 } 745 746 return found; 747 } 748 749 /* 750 *@@ treeFindEQNode: 751 * finds a node with ID exactly matching that provided. 752 * To find a tree node, your comparison function must 753 * compare the tree nodes. 754 */ 755 756 void* treeFindEQNode(TREE **root, 757 TREE *nodeFind, 758 FNTREE_COMPARE_NODES *comp) 759 { 760 TREE *current = *root, 761 *found; 762 763 found = NULL; 764 while (current != TREE_NULL) 765 switch (comp(current, nodeFind)) 766 { 767 case -1: current = current->right; break; 768 case 1: current = current->left; break; 769 default: found = current; // In case of duplicates, 770 current = current->left; // get the first one. 771 } 772 773 return found; 774 } 775 776 /* 777 *@@ treeFindGENode: 778 * finds a node with ID greater than or equal to provided. 779 * To find a tree node, your comparison function must 780 * compare the tree nodes. 781 */ 782 783 void* treeFindGENode(TREE **root, 784 TREE *nodeFind, 785 FNTREE_COMPARE_NODES *comp) 786 { 787 TREE *current = *root, 788 *found; 789 790 found = NULL; 791 while (current != TREE_NULL) 792 switch (comp(current, nodeFind)) 793 { 794 case -1: current = current->right; break; 795 default: found = current; 796 current = current->left; 797 } 798 799 return found; 800 } 801 802 /* 803 *@@ treeFindLTNode: 804 * finds a node with Node less than provided. 805 * To find a tree node, your comparison function must 806 * compare the tree nodes. 807 */ 808 809 void* treeFindLTNode(TREE **root, 810 TREE *nodeFind, 811 FNTREE_COMPARE_NODES *comp) 812 { 813 TREE *current = *root, 814 *found; 815 816 found = NULL; 817 while (current != TREE_NULL) 818 switch (comp(current, nodeFind)) 819 { 820 case -1: found = current; 821 current = current->right; break; 822 default: current = current->left; 823 } 824 825 return found; 826 } 827 828 /* 829 *@@ treeFindLENode: 830 * finds a node with Node less than or equal to provided. 831 * To find a tree node, your comparison function must 832 * compare the tree nodes. 833 */ 834 835 void* treeFindLENode(TREE **root, 836 TREE *nodeFind, 837 FNTREE_COMPARE_NODES *comp) 838 { 839 TREE *current = *root, 840 *found; 841 842 found = NULL; 843 while (current != TREE_NULL) 844 switch (comp(current, nodeFind)) 845 { 846 case 1 : current = current->left; break; 847 default: found = current; 848 current = current->right; 849 } 850 851 return found; 852 } 853 854 /* 855 *@@ treeFindGTNode: 856 * finds a node with Node greater than provided. 857 * To find a tree node, your comparison function must 858 * compare the tree nodes. 859 */ 860 861 void* treeFindGTNode(TREE **root, 862 TREE *nodeFind, 863 FNTREE_COMPARE_NODES *comp) 864 { 865 TREE *current = *root, 866 *found; 867 868 found = NULL; 869 while (current != TREE_NULL) 870 switch (comp(current, nodeFind)) 871 { 872 case 1 : found = current; 873 current = current->left; break; 874 default: current = current->right; 875 } 876 877 return found; 878 } 879 880 /* 881 *@@ treeFindEQID: 882 * finds a node with data exactly matching that provided. 883 * To find a tree node, your comparison function must 884 * compare a tree member with external data. 885 * 886 * This is useful for finding a tree item from a string ID. 887 * 888 * Make sure to use treeInsertNode and compare according 889 * to a string member, and then write a second compare 890 * function for this function which compares the string 891 * member to an external string. 892 */ 893 894 void* treeFindEQData(TREE **root, 895 void *pData, 896 FNTREE_COMPARE_DATA *comp) 897 { 898 TREE *current = *root, 899 *found = NULL; 900 901 while (current != TREE_NULL) 902 switch (comp(current, pData)) 903 { 904 case -1: current = current->right; break; 905 case 1: current = current->left; break; 906 default: found = current; // In case of duplicates, 907 current = current->left; // get the first one. 908 } 909 910 return found; 911 } 912 913 /* 914 *@@ treeTraverse: 915 * traverses the specified tree, calling a processing function 916 * for each tree node. 917 * 918 * The processing function ("process") must be declared as 919 * follows: 920 * 921 + void fnProcess(TREE *t, // current tree node 922 + void *pUser); // user data 923 * 924 * and will receive the "pUser" parameter, which you can use 925 * as a data pointer to some structure for whatever you like. 926 * 927 * WARNING: This function recurses and can use up a lot of 928 * stack. For very deep trees, traverse the tree using 929 * treeFirst and treeNext instead. See treeNext for a sample. 930 * 931 * "method" specifies in which order the nodes are traversed. 932 * This can be: 933 * 934 * -- 1: current node first, then left node, then right node. 935 * -- 2: left node first, then right node, then current node. 936 * -- 0 or other: left node first, then current node, then right node. 937 * This is the sorted order. 938 */ 939 940 void treeTraverse(TREE *tree, // in: root of tree 941 TREE_PROCESS *process, // in: callback for each node 942 void *pUser, // in: user param for callback 943 int method) // in: traversal mode 944 { 945 if ( (!tree) 946 || (tree == TREE_NULL)) 947 return; 948 949 if (method == 1) 950 { 951 process(tree, pUser); 952 treeTraverse (((TREE*)tree)->left, process, pUser, method); 953 treeTraverse (((TREE*)tree)->right, process, pUser, method); 954 } 955 else if (method == 2) 956 { 957 treeTraverse (((TREE*)tree)->left, process, pUser, method); 958 treeTraverse (((TREE*)tree)->right, process, pUser, method); 959 process(tree, pUser); 960 } 961 else 962 { 963 treeTraverse (((TREE*)tree)->left, process, pUser, method); 964 process(tree, pUser); 965 treeTraverse (((TREE*)tree)->right, process, pUser, method); 966 } 906 { 907 current = (iResult < 0) // compLT (key, current->key) 908 ? current->left 909 : current->right; 910 } 911 } 912 913 return 0; 967 914 } 968 915 … … 974 921 */ 975 922 976 void* treeFirst(TREE *tree) 977 { 978 TREE 979 *current; 980 981 if ( (!tree) 982 || (tree == TREE_NULL) 923 TREE* treeFirst(TREE *r) 924 { 925 TREE *p; 926 927 if ( (!r) 928 || (r == LEAF) 983 929 ) 984 930 return NULL; 985 931 986 current = tree;987 while ( current->left != TREE_NULL)988 current = current->left;989 990 return current;932 p = r; 933 while (p->left != LEAF) 934 p = p->left; 935 936 return p; 991 937 } 992 938 … … 996 942 */ 997 943 998 void* treeLast(TREE *tree) 999 { 1000 TREE 1001 *current; 1002 1003 if ( (!tree) 1004 || (tree == TREE_NULL)) 944 TREE* treeLast(TREE *r) 945 { 946 TREE *p; 947 948 if ( (!r) 949 || (r == LEAF)) 1005 950 return NULL; 1006 951 1007 current = tree;1008 while ( current->right != TREE_NULL)1009 current = current->right;1010 1011 return current;952 p = r; 953 while (p->right != LEAF) 954 p = p->right; 955 956 return p; 1012 957 } 1013 958 … … 1016 961 * finds and returns the next node in a tree. 1017 962 * 1018 * Example for traversing a whole tree if you don't 1019 * want to use treeTraverse: 963 * Example for traversing a whole tree: 1020 964 * 1021 965 + TREE *TreeRoot; … … 1031 975 */ 1032 976 1033 void* treeNext(TREE *tree) 1034 { 1035 TREE 1036 *current, 1037 *child; 1038 1039 if ( (!tree) 1040 || (tree == TREE_NULL) 977 TREE* treeNext(TREE *r) 978 { 979 TREE *p, 980 *child; 981 982 if ( (!r) 983 || (r == LEAF) 1041 984 ) 1042 985 return NULL; 1043 986 1044 current = tree;1045 if ( current->right != TREE_NULL)1046 return treeFirst ( current->right);987 p = r; 988 if (p->right != LEAF) 989 return treeFirst (p->right); 1047 990 else 1048 991 { 1049 current = tree;1050 child = TREE_NULL;1051 while ( ( current->parent)1052 && ( current->right == child)992 p = r; 993 child = LEAF; 994 while ( (p->parent) 995 && (p->right == child) 1053 996 ) 1054 997 { 1055 child = current;1056 current = current->parent;1057 } 1058 if ( current->right != child)1059 return current;998 child = p; 999 p = p->parent; 1000 } 1001 if (p->right != child) 1002 return p; 1060 1003 else 1061 1004 return NULL; … … 1068 1011 */ 1069 1012 1070 void* treePrev(TREE *tree) 1071 { 1072 TREE 1073 *current, 1074 *child; 1075 1076 if ( (!tree) 1077 || (tree == TREE_NULL)) 1013 TREE* treePrev(TREE *r) 1014 { 1015 TREE *p, 1016 *child; 1017 1018 if ( (!r) 1019 || (r == LEAF)) 1078 1020 return NULL; 1079 1021 1080 current = tree;1081 if ( current->left != TREE_NULL)1082 return treeLast ( current->left);1022 p = r; 1023 if (p->left != LEAF) 1024 return treeLast (p->left); 1083 1025 else 1084 1026 { 1085 current = tree;1086 child = TREE_NULL;1087 while (( current->parent)1088 && ( current->left == child))1089 { 1090 child = current;1091 current = current->parent;1092 } 1093 if ( current->left != child)1094 return current;1027 p = r; 1028 child = LEAF; 1029 while ((p->parent) 1030 && (p->left == child)) 1031 { 1032 child = p; 1033 p = p->parent; 1034 } 1035 if (p->left != child) 1036 return p; 1095 1037 else 1096 1038 return NULL; … … 1125 1067 + // add stuff to the tree 1126 1068 + TREE *pNewNode = malloc(...); 1127 + treeInsert ID(&G_TreeRoot, pNewNode, FALSE)1069 + treeInsert(&G_TreeRoot, pNewNode, fnCompare) 1128 1070 + 1129 1071 + // now delete all nodes … … 1186 1128 } 1187 1129 1188 1130 /* void main(int argc, char **argv) { 1131 int maxnum, ct; 1132 recType rec; 1133 keyType key; 1134 statusEnum status; 1135 1136 maxnum = atoi(argv[1]); 1137 1138 printf("maxnum = %d\n", maxnum); 1139 for (ct = maxnum; ct; ct--) { 1140 key = rand() % 9 + 1; 1141 if ((status = find(key, &rec)) == STATUS_OK) { 1142 status = delete(key); 1143 if (status) printf("fail: status = %d\n", status); 1144 } else { 1145 status = insert(key, &rec); 1146 if (status) printf("fail: status = %d\n", status); 1147 } 1148 } 1149 } */ -
trunk/src/helpers/winh.c
r81 r83 120 120 121 121 /* 122 *@@ winhSendDlgItemMsg: 123 * wrapper for WinSendDlgItemMsg. 124 * 125 * If WINH_STANDARDWRAPPERS is #defined before 126 * including win.h, all WinSendMsg calls are 127 * redefined to use this wrapper instead. This 128 * reduces the amount of external fixups required 129 * for loading the module. 130 * 131 *@@added V0.9.13 (2001-06-27) [umoeller] 132 */ 133 134 MRESULT winhSendDlgItemMsg(HWND hwnd, ULONG id, ULONG msg, MPARAM mp1, MPARAM mp2) 135 { 136 return ((WinSendDlgItemMsg)(hwnd, id, msg, mp1, mp2)); 137 } 138 139 /* 122 140 *@@ winhPostMsg: 123 141 * wrapper for WinPostMsg. … … 240 258 * 241 259 ********************************************************************/ 242 243 /*244 *@@ winhSetDlgItemChecked:245 * checks a check box.246 *247 * This has been turned into a real function248 * because this is used hundreds of times in249 * XWP, and each WinSendDlgItemMsg in each250 * macro produced a fixup relocation record.251 *252 *@@added V0.9.12 (2001-05-18) [umoeller]253 */254 255 BOOL winhSetDlgItemChecked(HWND hwnd, // in: dialog256 SHORT id, // in: dialog item ID257 SHORT bCheck) // in: 0, 1, or (for tri-state) 2258 {259 return ((BOOL)WinSendDlgItemMsg(hwnd,260 id,261 BM_SETCHECK,262 MPFROMSHORT(bCheck),263 MPNULL));264 }265 266 /*267 *@@ winhIsDlgItemChecked:268 * returns the current check state of the269 * specified check box, which can be 0, 1,270 * or (for tri-state checkboxes) 2.271 *272 *@@added V0.9.12 (2001-05-18) [umoeller]273 */274 275 SHORT winhIsDlgItemChecked(HWND hwnd, // in: dialog276 SHORT id) // in: dialog item ID277 {278 return (SHORT1FROMMR(WinSendDlgItemMsg(hwnd,279 id,280 BM_QUERYCHECK,281 MPNULL,282 MPNULL)));283 }284 260 285 261 /* -
trunk/src/helpers/xml.c
r74 r83 276 276 277 277 /* 278 *@@ Compare NodeBaseNodes:278 *@@ CompareXStrings: 279 279 * tree comparison func for NodeBases. 280 280 * This works for all trees which contain structures … … 293 293 */ 294 294 295 int TREEENTRY CompareNodeBaseNodes(TREE *t1, 296 TREE *t2) 297 { 298 PNODEBASE p1 = (PNODEBASE)t1, 299 p2 = (PNODEBASE)t2; 300 return (strhcmp(p1->strNodeName.psz, p2->strNodeName.psz)); 301 } 302 303 /* 304 *@@ CompareNodeBaseNodes: 305 * tree comparison func for element declarations. 306 * Used to find nodes in _DOMDOCTYPENODE.ElementDeclsTree. 307 * 308 *@@added V0.9.9 (2001-02-16) [umoeller] 309 */ 310 311 int TREEENTRY CompareNodeBaseData(TREE *t1, 312 void *pData) 313 { 314 PNODEBASE p1 = (PNODEBASE)t1; 315 return (strhcmp(p1->strNodeName.psz, (const char*)pData)); 295 int TREEENTRY CompareXStrings(ULONG ul1, 296 ULONG ul2) 297 { 298 return (strhcmp(((PXSTRING)ul1)->psz, 299 ((PXSTRING)ul1)->psz)); 316 300 } 317 301 … … 343 327 pNewNode->ulNodeType = ulNodeType; 344 328 329 pNewNode->Tree.ulKey = (ULONG)&pNewNode->strNodeName; 330 345 331 xstrInit(&pNewNode->strNodeName, 0); 346 332 if (pcszNodeName) 333 { 347 334 xstrcpy(&pNewNode->strNodeName, 348 335 pcszNodeName, 349 ulNodeNameLength); // if 0, xstrcpy will do strlen()350 336 ulNodeNameLength); 337 } 351 338 352 339 *ppNew = pNewNode; … … 514 501 lstClear(&llDeleteNodes); 515 502 516 xstr Clear(&pNode->strNodeName);503 xstrFree(((PXSTRING*)&pNode->Tree.ulKey)); 517 504 free(pNode); 518 505 } … … 587 574 // attribute: 588 575 // add to parent's attributes list 589 if (treeInsertNode(&pParentNode->AttributesMap, 590 &pNewNode->NodeBase.Tree, 591 CompareNodeBaseNodes, 592 FALSE) // no duplicates 593 == TREE_DUPLICATE) 576 if (treeInsert(&pParentNode->AttributesMap, 577 &pNewNode->NodeBase.Tree, 578 CompareXStrings)) 594 579 arc = ERROR_DOM_DUPLICATE_ATTRIBUTE; 595 580 // shouldn't happen, because expat takes care of this … … 837 822 PDOMDOCTYPENODE pNew = NULL; 838 823 arc = xmlCreateDomNode((PDOMNODE)pDocumentNode, 839 DOMNODE_DOCUMENT_TYPE,840 NULL,841 0,842 (PDOMNODE*)&pNew);824 DOMNODE_DOCUMENT_TYPE, 825 pcszDoctypeName, 826 0, 827 (PDOMNODE*)&pNew); 843 828 844 829 if (!arc) … … 854 839 pNew->fHasInternalSubset = fHasInternalSubset; 855 840 856 if (pcszDoctypeName)857 {858 ULONG ul = strlen(pcszDoctypeName);859 if (ul)860 {861 xstrcpy(&pDocumentNode->DomNode.NodeBase.strNodeName,862 pcszDoctypeName,863 ul);864 }865 }866 867 841 treeInit(&pNew->ElementDeclsTree); 868 842 treeInit(&pNew->AttribDeclBasesTree); … … 909 883 case XML_CTYPE_NAME: // that's easy 910 884 pParticle->NodeBase.ulNodeType = ELEMENTPARTICLE_NAME; 911 xstrInitCopy(&pParticle->NodeBase.strNodeName, pModel->name, 0); 912 treeInsertNode(ppElementNamesTree, 913 &pParticle->NodeBase.Tree, 914 CompareNodeBaseNodes, 915 TRUE); // allow duplicates here 885 xstrcpy(&pParticle->NodeBase.strNodeName, pModel->name, 0); 886 treeInsert(ppElementNamesTree, 887 &pParticle->NodeBase.Tree, 888 CompareXStrings); 916 889 break; 917 890 … … 1097 1070 case ELEMENTPARTICLE_SEQ: 1098 1071 { 1099 const char *pcszNewElementName1100 = pNewElement->NodeBase.strNodeName.psz;1072 PXSTRING pstrNewElementName 1073 = &pNewElement->NodeBase.strNodeName; 1101 1074 1102 1075 // for all these, we first need to check if 1103 1076 // the element is allowed at all 1104 1077 PCMELEMENTPARTICLE pParticle 1105 = (PCMELEMENTPARTICLE)treeFind EQData(1106 &pParentElementDecl->ParticleNamesTree,1107 ( void*)pcszNewElementName,1108 Compare NodeBaseData);1078 = (PCMELEMENTPARTICLE)treeFind( 1079 pParentElementDecl->ParticleNamesTree, 1080 (ULONG)pstrNewElementName, 1081 CompareXStrings); 1109 1082 if (!pParticle) 1110 1083 // not found: then this element is not allowed within this … … 1112 1085 xmlSetError(pDom, 1113 1086 ERROR_DOM_INVALID_SUBELEMENT, 1114 p cszNewElementName,1087 pstrNewElementName->psz, 1115 1088 TRUE); 1116 1089 else … … 1249 1222 // enumeration: then check if it has one of the 1250 1223 // allowed values 1251 PNODEBASE pValue = (PNODEBASE)treeFind EQData(1252 &pAttribDecl->ValuesTree,1253 ( void*)pAttrib->pstrNodeValue->psz,1254 Compare NodeBaseData);1224 PNODEBASE pValue = (PNODEBASE)treeFind( 1225 pAttribDecl->ValuesTree, 1226 (ULONG)pAttrib->pstrNodeValue, 1227 CompareXStrings); 1255 1228 if (!pValue) 1256 1229 xmlSetError(pDom, … … 1297 1270 { 1298 1271 // for all others , we need to find the attribute 1299 P SZ pszAttrNameThis = pDeclThis->NodeBase.strNodeName.psz;1300 PDOMNODE pAttrNode = (PDOMNODE)treeFind EQData(1301 &pNewElement->AttributesMap,1302 ( void*)pszAttrNameThis,1303 Compare NodeBaseData);1272 PXSTRING pstrAttrNameThis = &pDeclThis->NodeBase.strNodeName; 1273 PDOMNODE pAttrNode = (PDOMNODE)treeFind( 1274 pNewElement->AttributesMap, 1275 (ULONG)pstrAttrNameThis, 1276 CompareXStrings); 1304 1277 1305 1278 // now switch again … … 1311 1284 xmlSetError(pDom, 1312 1285 ERROR_DOM_REQUIRED_ATTRIBUTE_MISSING, 1313 ps zAttrNameThis,1286 pstrAttrNameThis->psz, 1314 1287 TRUE); 1315 1288 break; … … 1871 1844 { 1872 1845 // add this to the doctype's declarations tree 1873 if (treeInsertNode(&pDocType->ElementDeclsTree, 1874 (TREE*)pNew, 1875 CompareNodeBaseNodes, 1876 FALSE) 1877 == TREE_DUPLICATE) 1846 if (treeInsert(&pDocType->ElementDeclsTree, 1847 (TREE*)pNew, 1848 CompareXStrings)) 1878 1849 // element already declared: 1879 1850 // according to the XML specs, this is a validity … … 1906 1877 &pNew); 1907 1878 if (!arc) 1908 treeInsertNode(&pDecl->ValuesTree, 1909 (TREE*)pNew, 1910 CompareNodeBaseNodes, 1911 FALSE); 1879 treeInsert(&pDecl->ValuesTree, 1880 (TREE*)pNew, 1881 CompareXStrings); 1912 1882 1913 1883 return (arc); … … 1978 1948 if (!pThis) 1979 1949 { 1980 // cache didn't match: look up attributes tree then 1981 pThis = (PCMATTRIBUTEDECLBASE)treeFindEQData( 1982 &pDocType->AttribDeclBasesTree, 1983 (void*)pcszElementName, 1984 CompareNodeBaseData); 1950 // cache didn't match: look up attributes tree then... 1951 // note: cheap trick, we need an XSTRING for treeFind 1952 // but don't want malloc, so we use xstrInitSet 1953 XSTRING strElementName; 1954 xstrInitSet(&strElementName, (PSZ)pcszElementName); 1955 pThis = (PCMATTRIBUTEDECLBASE)treeFind( 1956 pDocType->AttribDeclBasesTree, 1957 (ULONG)&strElementName, 1958 CompareXStrings); 1985 1959 1986 1960 if (!pThis) … … 1990 1964 pDom->arcDOM = xmlCreateNodeBase(ATTRIBUTE_DECLARATION_BASE, 1991 1965 sizeof(CMATTRIBUTEDECLBASE), 1992 pcszElementName,1993 0,1966 strElementName.psz, 1967 strElementName.ulLength, 1994 1968 (PNODEBASE*)&pThis); 1995 1969 if (!pDom->arcDOM) … … 1998 1972 treeInit(&pThis->AttribDeclsTree); 1999 1973 2000 treeInsertNode(&pDocType->AttribDeclBasesTree, 2001 (TREE*)pThis, 2002 CompareNodeBaseNodes, 2003 FALSE); 1974 treeInsert(&pDocType->AttribDeclBasesTree, 1975 (TREE*)pThis, 1976 CompareXStrings); 2004 1977 } 2005 1978 } … … 2085 2058 pNew->ulConstraint = CMAT_IMPLIED; 2086 2059 2087 if (treeInsertNode(&pThis->AttribDeclsTree, 2088 (TREE*)pNew, 2089 CompareNodeBaseNodes, 2090 FALSE) 2091 == TREE_DUPLICATE) 2060 if (treeInsert(&pThis->AttribDeclsTree, 2061 (TREE*)pNew, 2062 CompareXStrings)) 2092 2063 xmlSetError(pDom, 2093 2064 ERROR_DOM_DUPLICATE_ATTRIBUTE_DECL, … … 2431 2402 2432 2403 PCMELEMENTDECLNODE xmlFindElementDecl(PXMLDOM pDom, 2433 const XSTRING *p strElementName)2404 const XSTRING *pcstrElementName) 2434 2405 { 2435 2406 PCMELEMENTDECLNODE pElementDecl = NULL; 2436 2407 2408 PDOMDOCTYPENODE pDocTypeNode = pDom->pDocTypeNode; 2409 if ( (pDocTypeNode) 2410 && (pcstrElementName) 2411 && (pcstrElementName->ulLength) 2412 ) 2413 { 2414 pElementDecl = (PCMELEMENTDECLNODE)treeFind( 2415 pDocTypeNode->ElementDeclsTree, 2416 (ULONG)pcstrElementName, 2417 CompareXStrings); 2418 } 2419 2420 return (pElementDecl); 2421 } 2422 2423 /* 2424 *@@ xmlFindAttribDeclBase: 2425 * returns the _CMATTRIBUTEDECLBASE for the specified 2426 * element name, or NULL if none exists. 2427 * 2428 * To find a specific attribute declaration from both 2429 * an element and an attribute name, use xmlFindAttribDecl 2430 * instead. 2431 * 2432 *@@added V0.9.9 (2001-02-16) [umoeller] 2433 */ 2434 2435 PCMATTRIBUTEDECLBASE xmlFindAttribDeclBase(PXMLDOM pDom, 2436 const XSTRING *pstrElementName) 2437 { 2437 2438 PDOMDOCTYPENODE pDocTypeNode = pDom->pDocTypeNode; 2438 2439 if ( (pDocTypeNode) … … 2441 2442 ) 2442 2443 { 2443 pElementDecl = (PCMELEMENTDECLNODE)treeFindEQData( 2444 &pDocTypeNode->ElementDeclsTree, 2445 (void*)pstrElementName->psz, 2446 CompareNodeBaseData); 2447 } 2448 2449 return (pElementDecl); 2450 } 2451 2452 /* 2453 *@@ xmlFindAttribDeclBase: 2454 * returns the _CMATTRIBUTEDECLBASE for the specified 2455 * element name, or NULL if none exists. 2456 * 2457 * To find a specific attribute declaration from both 2458 * an element and an attribute name, use xmlFindAttribDecl 2459 * instead. 2460 * 2461 *@@added V0.9.9 (2001-02-16) [umoeller] 2462 */ 2463 2464 PCMATTRIBUTEDECLBASE xmlFindAttribDeclBase(PXMLDOM pDom, 2465 const XSTRING *pstrElementName) 2466 { 2467 PCMATTRIBUTEDECLBASE pAttribDeclBase = NULL; 2468 2469 PDOMDOCTYPENODE pDocTypeNode = pDom->pDocTypeNode; 2470 if ( (pDocTypeNode) 2471 && (pstrElementName) 2472 && (pstrElementName->ulLength) 2473 ) 2474 { 2475 pAttribDeclBase = (PCMATTRIBUTEDECLBASE)treeFindEQData( 2476 &pDocTypeNode->AttribDeclBasesTree, 2477 (void*)pstrElementName->psz, 2478 CompareNodeBaseData); 2479 } 2480 2481 return (pAttribDeclBase); 2444 return ((PCMATTRIBUTEDECLBASE)treeFind( 2445 pDocTypeNode->AttribDeclBasesTree, 2446 (ULONG)pstrElementName, 2447 CompareXStrings)); 2448 } 2449 2450 return (NULL); 2482 2451 } 2483 2452 … … 2498 2467 // must be NULL on the first call 2499 2468 { 2500 PCMATTRIBUTEDECL pAttribDecl = NULL;2501 2469 if (pstrElementName && pstrAttribName) 2502 2470 { … … 2507 2475 if (*ppAttribDeclBase) 2508 2476 { 2509 pAttribDecl = (PCMATTRIBUTEDECL)treeFindEQData(2510 &((**ppAttribDeclBase).AttribDeclsTree),2511 ( void*)pstrAttribName->psz,2512 Compare NodeBaseData);2513 } 2514 } 2515 2516 return ( pAttribDecl);2477 return ((PCMATTRIBUTEDECL)treeFind( 2478 ((**ppAttribDeclBase).AttribDeclsTree), 2479 (ULONG)pstrAttribName, 2480 CompareXStrings)); 2481 } 2482 } 2483 2484 return (NULL); 2517 2485 } 2518 2486 … … 2671 2639 const char *pcszAttribName) 2672 2640 { 2673 PDOMNODE pAttrNode = (PDOMNODE)treeFindEQData(&pElement->AttributesMap, 2674 (void*)pcszAttribName, 2675 CompareNodeBaseData); 2641 XSTRING str; 2642 PDOMNODE pAttrNode; 2643 xstrInitSet(&str, (PSZ)pcszAttribName); 2644 // note, cheap trick: no malloc here, but we need 2645 // an XSTRING for treeFind 2646 pAttrNode = (PDOMNODE)treeFind(pElement->AttributesMap, 2647 (ULONG)&str, 2648 CompareXStrings); 2676 2649 if (pAttrNode) 2677 2650 return (pAttrNode->pstrNodeValue);
Note:
See TracChangeset
for help on using the changeset viewer.