Back to home page

Enduro/X

 
 

    


0001 /*-------------------------------------------------------------------------
0002  *
0003  * rbtree.c
0004  *      implementation for PostgreSQL generic Red-Black binary tree package
0005  *      Adopted from http://algolist.manual.ru/ds/rbtree.php
0006  *
0007  * This code comes from Thomas Niemann's "Sorting and Searching Algorithms:
0008  * a Cookbook".
0009  *
0010  * See http://www.cs.auckland.ac.nz/software/AlgAnim/niemann/s_man.htm for
0011  * license terms: "Source code, when part of a software project, may be used
0012  * freely without reference to the author."
0013  *
0014  * Red-black trees are a type of balanced binary tree wherein (1) any child of
0015  * a red node is always black, and (2) every path from root to leaf traverses
0016  * an equal number of black nodes.  From these properties, it follows that the
0017  * longest path from root to leaf is only about twice as long as the shortest,
0018  * so lookups are guaranteed to run in O(lg n) time.
0019  *
0020  * Copyright (c) 2009-2023, PostgreSQL Global Development Group
0021  *
0022  * IDENTIFICATION
0023  *      src/backend/lib/rbtree.c
0024  *
0025  *-------------------------------------------------------------------------
0026  */
0027 
0028 #include <rbtree.h>
0029 #include <ndebug.h>
0030 
0031 
0032 /*
0033  * Colors of nodes (values of RBTNode.color)
0034  */
0035 #define RBTBLACK      (0)
0036 #define RBTRED        (1)
0037 
0038 /*
0039  * all leafs are sentinels, use customized NIL name to prevent
0040  * collision with system-wide constant NIL which is actually NULL
0041  */
0042 #define RBTNIL (&sentinel)
0043 
0044 static ndrx_rbt_node_t sentinel =
0045 {
0046     .color  = RBTBLACK,
0047     .left   = RBTNIL,
0048     .right  = RBTNIL,
0049     .parent = NULL
0050 };
0051 
0052 /*
0053  * PointerIsValid
0054  *      True iff pointer is valid.
0055  */
0056 #define PointerIsValid(pointer) ((const void*)(pointer) != NULL)
0057 
0058 /*
0059  * Assert
0060  *        Generates a fatal exception if the given condition is false.
0061  */
0062 #define Assert(condition) \
0063     do { \
0064         if (!(condition)) \
0065             ExceptionalCondition(#condition, __FILE__, __LINE__); \
0066     } while (0)
0067 
0068 /*
0069  * Write errors to stderr (or by equal means when stderr is
0070  * not available). Used before ereport/elog can be used
0071  * safely (memory context, GUC load etc)
0072  */
0073 void write_stderr(const char *fmt,...)
0074 {
0075     va_list        ap;
0076 
0077 #ifdef WIN32
0078     char        errbuf[2048];    /* Arbitrary size? */
0079 #endif
0080 
0081     va_start(ap, fmt);
0082 
0083 #ifndef WIN32
0084     /* On Unix, we just fprintf to stderr */
0085     vfprintf(stderr, fmt, ap);
0086     fflush(stderr);
0087 #else
0088     vsnprintf(errbuf, sizeof(errbuf), fmt, ap);
0089 
0090     /*
0091      * On Win32, we print to stderr if running on a console, or write to
0092      * eventlog if running as a service
0093      */
0094     if (pgwin32_is_service())    /* Running as a service */
0095     {
0096         write_eventlog(ERROR, errbuf, strlen(errbuf));
0097     }
0098     else
0099     {
0100         /* Not running as service, write to stderr */
0101         write_console(errbuf, strlen(errbuf));
0102         fflush(stderr);
0103     }
0104 #endif
0105     va_end(ap);
0106 }
0107 
0108 /*
0109  * ExceptionalCondition - Handles the failure of an Assert()
0110  *
0111  * We intentionally do not go through elog() here, on the grounds of
0112  * wanting to minimize the amount of infrastructure that has to be
0113  * working to report an assertion failure.
0114  */
0115 void ExceptionalCondition(const char *conditionName,
0116                      const char *fileName,
0117                      int lineNumber)
0118 {
0119     /* Report the failure on stderr (or local equivalent) */
0120     if (!PointerIsValid(conditionName)
0121         || !PointerIsValid(fileName))
0122         write_stderr("TRAP: ExceptionalCondition: bad arguments in PID %d\n",
0123                      (int) getpid());
0124     else
0125         write_stderr("TRAP: failed Assert(\"%s\"), File: \"%s\", Line: %d, PID: %d\n",
0126                      conditionName, fileName, lineNumber, (int) getpid());
0127 
0128     /* Usually this shouldn't be needed, but make sure the msg went out */
0129     fflush(stderr);
0130 
0131     /*
0132      * If configured to do so, sleep indefinitely to allow user to attach a
0133      * debugger.  It would be nice to use pg_usleep() here, but that can sleep
0134      * at most 2G usec or ~33 minutes, which seems too short.
0135      */
0136 
0137     abort();
0138 }
0139 
0140 /*
0141  * rbt_create: create an empty RBTree
0142  *
0143  * Arguments are:
0144  *    The manipulation functions:
0145  *    comparator: compare two RBTNodes for less/equal/greater
0146  *    combiner: merge an existing tree entry with a new one
0147  *    freefunc: free an old RBTNode
0148  *    arg: passthrough pointer that will be passed to the manipulation functions
0149  *
0150  * Note that the combiner's righthand argument will be a "proposed" tree node,
0151  * ie the input to rbt_insert, in which the RBTNode fields themselves aren't
0152  * valid.  Similarly, either input to the comparator may be a "proposed" node.
0153  * This shouldn't matter since the functions aren't supposed to look at the
0154  * RBTNode fields, only the extra fields of the struct the RBTNode is embedded
0155  * in.
0156  *
0157  * The freefunc should just be pfree or equivalent; it should NOT attempt
0158  * to free any subsidiary data, because the node passed to it may not contain
0159  * valid data!    freefunc can be NULL if caller doesn't require retail
0160  * space reclamation.
0161  *
0162  * The RBTree node is palloc'd in the caller's memory context.  Note that
0163  * all contents of the tree are actually allocated by the caller, not here.
0164  *
0165  * Since tree contents are managed by the caller, there is currently not
0166  * an explicit "destroy" operation; typically a tree would be freed by
0167  * resetting or deleting the memory context it's stored in.  You can pfree
0168  * the RBTree node if you feel the urge.
0169  */
0170 ndrx_rbt_tree_t *ndrx_rbt_create(rbt_comparator comparator,
0171                                     rbt_combiner combiner,
0172                                     rbt_freefunc freefunc,
0173                                     void *arg)
0174 {
0175     ndrx_rbt_tree_t *tree = (ndrx_rbt_tree_t *) NDRX_FPMALLOC(sizeof(ndrx_rbt_tree_t),0);
0176     if (NULL==tree)
0177     {
0178         return NULL;
0179     }
0180 
0181     return ndrx_rbt_init(tree, comparator, combiner,
0182                          freefunc, arg);
0183 }
0184 
0185 /**
0186  * Initialize the tree
0187  * @param tree allocated tree
0188  * @param comparator comparator function
0189  * @param combiner combiner function
0190  * @param freefunc free function
0191  * @param arg additional data ptr to functions
0192  * @return tree
0193  */
0194 ndrx_rbt_tree_t *ndrx_rbt_init(ndrx_rbt_tree_t *tree,
0195                                     rbt_comparator comparator,
0196                                     rbt_combiner combiner,
0197                                     rbt_freefunc freefunc,
0198                                     void *arg)
0199 {
0200     tree->root = RBTNIL;
0201     tree->comparator = comparator;
0202     tree->combiner = combiner;
0203     tree->freefunc = freefunc;
0204     tree->arg = arg;
0205     return tree;
0206 }
0207 
0208 /**********************************************************************
0209  *                          Search                                      *
0210  **********************************************************************/
0211 
0212 /**
0213  * Test is tree empty
0214  * @param rbt tree to test
0215  * @return 0 - false, 1 - true
0216  */
0217 int ndrx_rbt_is_empty(ndrx_rbt_tree_t *rbt)
0218 {
0219 
0220    if (RBTNIL==rbt->root)
0221    {
0222        return 1;
0223    }
0224 
0225    return 0;
0226 }
0227 
0228 /*
0229  * rbt_find: search for a value in an RBTree
0230  *
0231  * data represents the value to try to find.  Its RBTNode fields need not
0232  * be valid, it's the extra data in the larger struct that is of interest.
0233  *
0234  * Returns the matching tree entry, or NULL if no match is found.
0235  */
0236 ndrx_rbt_node_t *ndrx_rbt_find(ndrx_rbt_tree_t *rbt, const ndrx_rbt_node_t *data)
0237 {
0238     ndrx_rbt_node_t *node = rbt->root;
0239 
0240     while (node != RBTNIL)
0241     {
0242         int cmp = rbt->comparator(data, node, rbt->arg);
0243 
0244         if (cmp == 0)
0245             return node;
0246         else if (cmp < 0)
0247             node = node->left;
0248         else
0249             node = node->right;
0250     }
0251 
0252     return NULL;
0253 }
0254 
0255 /*
0256  * rbt_find_great: search for a greater value in an RBTree
0257  *
0258  * If equal_match is true, this will be a great or equal search.
0259  *
0260  * Returns the matching tree entry, or NULL if no match is found.
0261  */
0262 ndrx_rbt_node_t *ndrx_rbt_find_great(ndrx_rbt_tree_t *rbt, const ndrx_rbt_node_t *data, int equal_match)
0263 {
0264     ndrx_rbt_node_t *node = rbt->root;
0265     ndrx_rbt_node_t *greater = NULL;
0266 
0267     while (node != RBTNIL)
0268     {
0269         int cmp = rbt->comparator(data, node, rbt->arg);
0270 
0271         if (equal_match && cmp == 0)
0272             return node;
0273         else if (cmp < 0)
0274         {
0275             greater = node;
0276             node = node->left;
0277         }
0278         else
0279             node = node->right;
0280     }
0281 
0282     return greater;
0283 }
0284 
0285 /*
0286  * rbt_find_less: search for a lesser value in an RBTree
0287  *
0288  * If equal_match is true, this will be a less or equal search.
0289  *
0290  * Returns the matching tree entry, or NULL if no match is found.
0291  */
0292 ndrx_rbt_node_t *ndrx_rbt_find_less(ndrx_rbt_tree_t *rbt, const ndrx_rbt_node_t *data, int equal_match)
0293 {
0294     ndrx_rbt_node_t *node = rbt->root;
0295     ndrx_rbt_node_t *lesser = NULL;
0296 
0297     while (node != RBTNIL)
0298     {
0299         int cmp = rbt->comparator(data, node, rbt->arg);
0300 
0301         if (equal_match && cmp == 0)
0302             return node;
0303         else if (cmp > 0)
0304         {
0305             lesser = node;
0306             node = node->right;
0307         }
0308         else
0309             node = node->left;
0310     }
0311 
0312     return lesser;
0313 }
0314 
0315 /*
0316  * rbt_leftmost: fetch the leftmost (smallest-valued) tree node.
0317  * Returns NULL if tree is empty.
0318  *
0319  * Note: in the original implementation this included an unlink step, but
0320  * that's a bit awkward.  Just call rbt_delete on the result if that's what
0321  * you want.
0322  */
0323 ndrx_rbt_node_t *ndrx_rbt_leftmost(ndrx_rbt_tree_t *rbt)
0324 {
0325     ndrx_rbt_node_t *node = rbt->root;
0326     ndrx_rbt_node_t *leftmost = rbt->root;
0327 
0328     while (node != RBTNIL)
0329     {
0330         leftmost = node;
0331         node = node->left;
0332     }
0333 
0334     if (leftmost != RBTNIL)
0335         return leftmost;
0336 
0337     return NULL;
0338 }
0339 
0340 /*
0341  * rbt_rightmost: fetch the rightmost (largest valued) tree node.
0342  * Returns NULL if tree is empty.
0343  *
0344  * Note: in the original implementation this included an unlink step, but
0345  * that's a bit awkward.  Just call rbt_delete on the result if that's what
0346  * you want.
0347  */
0348 ndrx_rbt_node_t *ndrx_rbt_rightmost(ndrx_rbt_tree_t *rbt)
0349 {
0350     ndrx_rbt_node_t *node = rbt->root;
0351     ndrx_rbt_node_t *rightmost = rbt->root;
0352 
0353     while (node != RBTNIL)
0354     {
0355         rightmost = node;
0356         node = node->right;
0357     }
0358 
0359     if (rightmost != RBTNIL)
0360         return rightmost;
0361 
0362     return NULL;
0363 }
0364 
0365 /**********************************************************************
0366  *                              Insertion                                  *
0367  **********************************************************************/
0368 
0369 /*
0370  * Rotate node x to left.
0371  *
0372  * x's right child takes its place in the tree, and x becomes the left
0373  * child of that node.
0374  */
0375 static void ndrx_rbt_rotate_left(ndrx_rbt_tree_t *rbt, ndrx_rbt_node_t *x)
0376 {
0377     ndrx_rbt_node_t *y = x->right;
0378 
0379     /* establish x->right link */
0380     x->right = y->left;
0381     if (y->left != RBTNIL)
0382         y->left->parent = x;
0383 
0384     /* establish y->parent link */
0385     if (y != RBTNIL)
0386         y->parent = x->parent;
0387     if (x->parent)
0388     {
0389         if (x == x->parent->left)
0390             x->parent->left = y;
0391         else
0392             x->parent->right = y;
0393     }
0394     else
0395     {
0396         rbt->root = y;
0397     }
0398 
0399     /* link x and y */
0400     y->left = x;
0401     if (x != RBTNIL)
0402         x->parent = y;
0403 }
0404 
0405 /*
0406  * Rotate node x to right.
0407  *
0408  * x's left right child takes its place in the tree, and x becomes the right
0409  * child of that node.
0410  */
0411 static void ndrx_rbt_rotate_right(ndrx_rbt_tree_t *rbt, ndrx_rbt_node_t *x)
0412 {
0413     ndrx_rbt_node_t *y = x->left;
0414 
0415     /* establish x->left link */
0416     x->left = y->right;
0417     if (y->right != RBTNIL)
0418         y->right->parent = x;
0419 
0420     /* establish y->parent link */
0421     if (y != RBTNIL)
0422         y->parent = x->parent;
0423     if (x->parent)
0424     {
0425         if (x == x->parent->right)
0426             x->parent->right = y;
0427         else
0428             x->parent->left = y;
0429     }
0430     else
0431     {
0432         rbt->root = y;
0433     }
0434 
0435     /* link x and y */
0436     y->right = x;
0437     if (x != RBTNIL)
0438         x->parent = y;
0439 }
0440 
0441 /*
0442  * Maintain Red-Black tree balance after inserting node x.
0443  *
0444  * The newly inserted node is always initially marked red.  That may lead to
0445  * a situation where a red node has a red child, which is prohibited.  We can
0446  * always fix the problem by a series of color changes and/or "rotations",
0447  * which move the problem progressively higher up in the tree.  If one of the
0448  * two red nodes is the root, we can always fix the problem by changing the
0449  * root from red to black.
0450  *
0451  * (This does not work lower down in the tree because we must also maintain
0452  * the invariant that every leaf has equal black-height.)
0453  */
0454 static void ndrx_rbt_insert_fixup(ndrx_rbt_tree_t *rbt, ndrx_rbt_node_t *x)
0455 {
0456     /*
0457      * x is always a red node.  Initially, it is the newly inserted node. Each
0458      * iteration of this loop moves it higher up in the tree.
0459      */
0460     while (x != rbt->root && x->parent->color == RBTRED)
0461     {
0462         /*
0463          * x and x->parent are both red.  Fix depends on whether x->parent is
0464          * a left or right child.  In either case, we define y to be the
0465          * "uncle" of x, that is, the other child of x's grandparent.
0466          *
0467          * If the uncle is red, we flip the grandparent to red and its two
0468          * children to black.  Then we loop around again to check whether the
0469          * grandparent still has a problem.
0470          *
0471          * If the uncle is black, we will perform one or two "rotations" to
0472          * balance the tree.  Either x or x->parent will take the
0473          * grandparent's position in the tree and recolored black, and the
0474          * original grandparent will be recolored red and become a child of
0475          * that node. This always leaves us with a valid red-black tree, so
0476          * the loop will terminate.
0477          */
0478         if (x->parent == x->parent->parent->left)
0479         {
0480             ndrx_rbt_node_t *y = x->parent->parent->right;
0481 
0482             if (y->color == RBTRED)
0483             {
0484                 /* uncle is RBTRED */
0485                 x->parent->color = RBTBLACK;
0486                 y->color = RBTBLACK;
0487                 x->parent->parent->color = RBTRED;
0488 
0489                 x = x->parent->parent;
0490             }
0491             else
0492             {
0493                 /* uncle is RBTBLACK */
0494                 if (x == x->parent->right)
0495                 {
0496                     /* make x a left child */
0497                     x = x->parent;
0498                     ndrx_rbt_rotate_left(rbt, x);
0499                 }
0500 
0501                 /* recolor and rotate */
0502                 x->parent->color = RBTBLACK;
0503                 x->parent->parent->color = RBTRED;
0504 
0505                 ndrx_rbt_rotate_right(rbt, x->parent->parent);
0506             }
0507         }
0508         else
0509         {
0510             /* mirror image of above code */
0511             ndrx_rbt_node_t *y = x->parent->parent->left;
0512 
0513             if (y->color == RBTRED)
0514             {
0515                 /* uncle is RBTRED */
0516                 x->parent->color = RBTBLACK;
0517                 y->color = RBTBLACK;
0518                 x->parent->parent->color = RBTRED;
0519 
0520                 x = x->parent->parent;
0521             }
0522             else
0523             {
0524                 /* uncle is RBTBLACK */
0525                 if (x == x->parent->left)
0526                 {
0527                     x = x->parent;
0528                     ndrx_rbt_rotate_right(rbt, x);
0529                 }
0530                 x->parent->color = RBTBLACK;
0531                 x->parent->parent->color = RBTRED;
0532 
0533                 ndrx_rbt_rotate_left(rbt, x->parent->parent);
0534             }
0535         }
0536     }
0537 
0538     /*
0539      * The root may already have been black; if not, the black-height of every
0540      * node in the tree increases by one.
0541      */
0542     rbt->root->color = RBTBLACK;
0543 }
0544 
0545 /*
0546  * rbt_insert: insert a new value into the tree.
0547  *
0548  * data represents the value to insert.  Its RBTNode fields need not
0549  * be valid, it's the extra data in the larger struct that is of interest.
0550  *
0551  * If the value represented by "data" is not present in the tree, then
0552  * we copy "data" into a new tree entry and return that node, setting *isNew
0553  * to true.
0554  *
0555  * If the value represented by "data" is already present, then we call the
0556  * combiner function to merge data into the existing node, and return the
0557  * existing node, setting *isNew to false.
0558  *
0559  * "data" is unmodified in either case; it's typically just a local
0560  * variable in the caller.
0561  */
0562 ndrx_rbt_node_t *ndrx_rbt_insert(ndrx_rbt_tree_t *rbt, ndrx_rbt_node_t *data, int *isNew)
0563 {
0564     ndrx_rbt_node_t *current,
0565                     *parent,
0566                     *x;
0567     int             cmp;
0568 
0569     /* find where node belongs */
0570     current = rbt->root;
0571     parent = NULL;
0572     cmp = 0;                    /* just to prevent compiler warning */
0573 
0574     while (current != RBTNIL)
0575     {
0576         cmp = rbt->comparator(data, current, rbt->arg);
0577         if (cmp == 0)
0578         {
0579             /*
0580              * Found node with given key.  Apply combiner.
0581              */
0582             rbt->combiner(current, data, rbt->arg);
0583             if (NULL!=isNew)
0584             {
0585                 *isNew = EXFALSE;
0586             }
0587             return current;
0588         }
0589         parent = current;
0590         current = (cmp < 0) ? current->left : current->right;
0591     }
0592 
0593     /*
0594      * Value is not present, so create a new node containing data.
0595      */
0596     if (NULL!=isNew)
0597     {
0598         *isNew = EXTRUE;
0599     }
0600 
0601     /* x = rbt->allocfunc(rbt->arg); */
0602     data->color = RBTRED;
0603 
0604     data->left = RBTNIL;
0605     data->right = RBTNIL;
0606     data->parent = parent;
0607     /* ndrx_rbt_copy_data(rbt, x, data);*/
0608 
0609     /* insert node in tree */
0610     if (parent)
0611     {
0612         if (cmp < 0)
0613             parent->left = data;
0614         else
0615             parent->right = data;
0616     }
0617     else
0618     {
0619         rbt->root = data;
0620     }
0621 
0622     ndrx_rbt_insert_fixup(rbt, data);
0623 
0624     return data;
0625 }
0626 
0627 /**********************************************************************
0628  *                            Deletion                                  *
0629  **********************************************************************/
0630 
0631 
0632 /*
0633  * Maintain Red-Black tree balance after deleting a black node.
0634  */
0635 static void ndrx_rbt_delete_fixup(ndrx_rbt_tree_t *rbt, ndrx_rbt_node_t *x)
0636 {
0637     /*
0638      * x is always a black node.  Initially, it is the former child of the
0639      * deleted node.  Each iteration of this loop moves it higher up in the
0640      * tree.
0641      */
0642     while (x != rbt->root && x->color == RBTBLACK)
0643     {
0644         /*
0645          * Left and right cases are symmetric.  Any nodes that are children of
0646          * x have a black-height one less than the remainder of the nodes in
0647          * the tree.  We rotate and recolor nodes to move the problem up the
0648          * tree: at some stage we'll either fix the problem, or reach the root
0649          * (where the black-height is allowed to decrease).
0650          */
0651         if (x == x->parent->left)
0652         {
0653             ndrx_rbt_node_t *w = x->parent->right;
0654 
0655             if (w->color == RBTRED)
0656             {
0657                 w->color = RBTBLACK;
0658                 x->parent->color = RBTRED;
0659 
0660                 ndrx_rbt_rotate_left(rbt, x->parent);
0661                 w = x->parent->right;
0662             }
0663 
0664             if (w->left->color == RBTBLACK && w->right->color == RBTBLACK)
0665             {
0666                 w->color = RBTRED;
0667 
0668                 x = x->parent;
0669             }
0670             else
0671             {
0672                 if (w->right->color == RBTBLACK)
0673                 {
0674                     w->left->color = RBTBLACK;
0675                     w->color = RBTRED;
0676 
0677                     ndrx_rbt_rotate_right(rbt, w);
0678                     w = x->parent->right;
0679                 }
0680                 w->color = x->parent->color;
0681                 x->parent->color = RBTBLACK;
0682                 w->right->color = RBTBLACK;
0683 
0684                 ndrx_rbt_rotate_left(rbt, x->parent);
0685                 x = rbt->root;    /* Arrange for loop to terminate. */
0686             }
0687         }
0688         else
0689         {
0690             ndrx_rbt_node_t *w = x->parent->left;
0691 
0692             if (w->color == RBTRED)
0693             {
0694                 w->color = RBTBLACK;
0695                 x->parent->color = RBTRED;
0696 
0697                 ndrx_rbt_rotate_right(rbt, x->parent);
0698                 w = x->parent->left;
0699             }
0700 
0701             if (w->right->color == RBTBLACK && w->left->color == RBTBLACK)
0702             {
0703                 w->color = RBTRED;
0704 
0705                 x = x->parent;
0706             }
0707             else
0708             {
0709                 if (w->left->color == RBTBLACK)
0710                 {
0711                     w->right->color = RBTBLACK;
0712                     w->color = RBTRED;
0713 
0714                     ndrx_rbt_rotate_left(rbt, w);
0715                     w = x->parent->left;
0716                 }
0717                 w->color = x->parent->color;
0718                 x->parent->color = RBTBLACK;
0719                 w->left->color = RBTBLACK;
0720 
0721                 ndrx_rbt_rotate_right(rbt, x->parent);
0722                 x = rbt->root;    /* Arrange for loop to terminate. */
0723             }
0724         }
0725     }
0726     x->color = RBTBLACK;
0727 }
0728 
0729 /**
0730  * Find the tree minimum (from the given node)
0731  */
0732 static ndrx_rbt_node_t *ndrx_rbt_tree_minimum(ndrx_rbt_node_t *x)
0733 {
0734     while (x->left != RBTNIL)
0735     {
0736         x = x->left;
0737     }
0738     return x;
0739 }
0740 
0741 /**
0742  * Standard transplant
0743  */
0744 static void ndx_rbt_transplant(struct ndrx_rbt_tree *tree, 
0745     ndrx_rbt_node_t *u, ndrx_rbt_node_t *v)
0746 {
0747     if (u->parent == NULL)
0748     {
0749         tree->root = v;
0750     } 
0751     else if (u == u->parent->left)
0752     {
0753         u->parent->left = v;
0754     } 
0755     else
0756     {
0757         u->parent->right = v;
0758     }
0759     v->parent = u->parent;
0760 }
0761 
0762 /**
0763  * Standard delete 
0764  */
0765 static void ndrx_rbt_delete_node(struct ndrx_rbt_tree *rbt, ndrx_rbt_node_t *z)
0766 {
0767     ndrx_rbt_node_t *y = z;
0768     ndrx_rbt_node_t *x;
0769     char y_original_color = y->color;
0770 
0771     if (z->left == RBTNIL)
0772     {
0773         x = z->right;
0774         ndx_rbt_transplant(rbt, z, z->right);
0775     } 
0776     else if (z->right == RBTNIL)
0777     {
0778         x = z->left;
0779         ndx_rbt_transplant(rbt, z, z->left);
0780     } 
0781     else
0782     {
0783         y = ndrx_rbt_tree_minimum(z->right);
0784         y_original_color = y->color;
0785         x = y->right;
0786 
0787         if (y->parent == z) {
0788             x->parent = y;  /* Update x's parent for fixup */
0789         } else {
0790             ndx_rbt_transplant(rbt, y, y->right);
0791             y->right = z->right;
0792             y->right->parent = y;
0793         }
0794 
0795         ndx_rbt_transplant(rbt, z, y);
0796         y->left = z->left;
0797         y->left->parent = y;
0798         y->color = z->color;
0799     }
0800 
0801     if (y_original_color == RBTBLACK)
0802     {
0803         ndrx_rbt_delete_fixup(rbt, x);
0804     }
0805 
0806     if (rbt->freefunc)
0807         rbt->freefunc(z, rbt->arg);
0808 }
0809 
0810 /*
0811  * rbt_delete: remove the given tree entry
0812  *
0813  * "node" must have previously been found via rbt_find or rbt_leftmost.
0814  * It is caller's responsibility to free any subsidiary data attached
0815  * to the node before calling rbt_delete.  (Do *not* try to push that
0816  * responsibility off to the freefunc, as some other physical node
0817  * may be the one actually freed!)
0818  */
0819 void ndrx_rbt_delete(ndrx_rbt_tree_t *rbt, ndrx_rbt_node_t *node)
0820 {
0821     ndrx_rbt_delete_node(rbt, node);
0822 }
0823 
0824 /**********************************************************************
0825  *                          Traverse                                      *
0826  **********************************************************************/
0827 
0828 static ndrx_rbt_node_t *rbt_left_right_iterator(ndrx_rbt_tree_iterator_t *iter)
0829 {
0830     if (iter->last_visited == NULL)
0831     {
0832         iter->last_visited = iter->rbt->root;
0833         while (iter->last_visited->left != RBTNIL)
0834             iter->last_visited = iter->last_visited->left;
0835 
0836         return iter->last_visited;
0837     }
0838 
0839     if (iter->last_visited->right != RBTNIL)
0840     {
0841         iter->last_visited = iter->last_visited->right;
0842         while (iter->last_visited->left != RBTNIL)
0843             iter->last_visited = iter->last_visited->left;
0844 
0845         return iter->last_visited;
0846     }
0847 
0848     for (;;)
0849     {
0850         ndrx_rbt_node_t *came_from = iter->last_visited;
0851 
0852         iter->last_visited = iter->last_visited->parent;
0853         if (iter->last_visited == NULL)
0854         {
0855             iter->is_over = EXTRUE;
0856             break;
0857         }
0858 
0859         if (iter->last_visited->left == came_from)
0860             break;          /* came from left sub-tree, return current node */
0861 
0862         /* else - came from right sub-tree, continue to move up */
0863     }
0864 
0865     return iter->last_visited;
0866 }
0867 
0868 static ndrx_rbt_node_t *rbt_right_left_iterator(ndrx_rbt_tree_iterator_t *iter)
0869 {
0870     if (iter->last_visited == NULL)
0871     {
0872         iter->last_visited = iter->rbt->root;
0873         while (iter->last_visited->right != RBTNIL)
0874             iter->last_visited = iter->last_visited->right;
0875 
0876         return iter->last_visited;
0877     }
0878 
0879     if (iter->last_visited->left != RBTNIL)
0880     {
0881         iter->last_visited = iter->last_visited->left;
0882         while (iter->last_visited->right != RBTNIL)
0883             iter->last_visited = iter->last_visited->right;
0884 
0885         return iter->last_visited;
0886     }
0887 
0888     for (;;)
0889     {
0890         ndrx_rbt_node_t *came_from = iter->last_visited;
0891 
0892         iter->last_visited = iter->last_visited->parent;
0893         if (iter->last_visited == NULL)
0894         {
0895             iter->is_over = EXTRUE;
0896             break;
0897         }
0898 
0899         if (iter->last_visited->right == came_from)
0900             break;          /* came from right sub-tree, return current node */
0901 
0902         /* else - came from left sub-tree, continue to move up */
0903     }
0904 
0905     return iter->last_visited;
0906 }
0907 
0908 /*
0909  * rbt_begin_iterate: prepare to traverse the tree in any of several orders
0910  *
0911  * After calling rbt_begin_iterate, call rbt_iterate repeatedly until it
0912  * returns NULL or the traversal stops being of interest.
0913  *
0914  * If the tree is changed during traversal, results of further calls to
0915  * rbt_iterate are unspecified.  Multiple concurrent iterators on the same
0916  * tree are allowed.
0917  *
0918  * The iterator state is stored in the 'iter' struct.  The caller should
0919  * treat it as an opaque struct.
0920  */
0921 void ndrx_rbt_begin_iterate(ndrx_rbt_tree_t *rbt, 
0922                             ndrx_rbt_order_control_t ctrl, 
0923                             ndrx_rbt_tree_iterator_t *iter)
0924 {
0925     /* Common initialization for all traversal orders */
0926     iter->rbt = rbt;
0927     iter->last_visited = NULL;
0928     iter->is_over = (rbt->root == RBTNIL);
0929 
0930     switch (ctrl)
0931     {
0932         case LeftRightWalk:        /* visit left, then self, then right */
0933             /* iter->iterate = rbt_left_right_iterator; */
0934             iter->iterate = rbt_left_right_iterator;
0935             break;
0936         case RightLeftWalk:        /* visit right, then self, then left */
0937             /* iter->iterate = rbt_right_left_iterator; */
0938             iter->iterate = rbt_right_left_iterator;
0939             break;
0940         default:
0941             NDRX_LOG(log_error, "unrecognized rbtree iteration order: %d", ctrl);
0942     }
0943 }
0944 
0945 /*
0946  * rbt_iterate: return the next node in traversal order, or NULL if no more
0947  */
0948 ndrx_rbt_node_t *ndrx_rbt_iterate(ndrx_rbt_tree_iterator_t *iter)
0949 {
0950     if (iter->is_over)
0951         return NULL;
0952 
0953     return iter->iterate(iter);
0954 }
0955 
0956