Header And Logo

PostgreSQL
| The world's most advanced open source database.

rbtree.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * rbtree.c
00004  *    implementation for PostgreSQL generic Red-Black binary tree package
00005  *    Adopted from http://algolist.manual.ru/ds/rbtree.php
00006  *
00007  * This code comes from Thomas Niemann's "Sorting and Searching Algorithms:
00008  * a Cookbook".
00009  *
00010  * See http://www.cs.auckland.ac.nz/software/AlgAnim/niemann/s_man.htm for
00011  * license terms: "Source code, when part of a software project, may be used
00012  * freely without reference to the author."
00013  *
00014  * Red-black trees are a type of balanced binary tree wherein (1) any child of
00015  * a red node is always black, and (2) every path from root to leaf traverses
00016  * an equal number of black nodes.  From these properties, it follows that the
00017  * longest path from root to leaf is only about twice as long as the shortest,
00018  * so lookups are guaranteed to run in O(lg n) time.
00019  *
00020  * Copyright (c) 2009-2013, PostgreSQL Global Development Group
00021  *
00022  * IDENTIFICATION
00023  *    src/backend/utils/misc/rbtree.c
00024  *
00025  *-------------------------------------------------------------------------
00026  */
00027 #include "postgres.h"
00028 
00029 #include "utils/rbtree.h"
00030 
00031 
00032 /*
00033  * Values of RBNode.iteratorState
00034  *
00035  * Note that iteratorState has an undefined value except in nodes that are
00036  * currently being visited by an active iteration.
00037  */
00038 #define InitialState    (0)
00039 #define FirstStepDone   (1)
00040 #define SecondStepDone  (2)
00041 #define ThirdStepDone   (3)
00042 
00043 /*
00044  * Colors of nodes (values of RBNode.color)
00045  */
00046 #define RBBLACK     (0)
00047 #define RBRED       (1)
00048 
00049 /*
00050  * RBTree control structure
00051  */
00052 struct RBTree
00053 {
00054     RBNode     *root;           /* root node, or RBNIL if tree is empty */
00055 
00056     /* Iteration state */
00057     RBNode     *cur;            /* current iteration node */
00058     RBNode     *(*iterate) (RBTree *rb);
00059 
00060     /* Remaining fields are constant after rb_create */
00061 
00062     Size        node_size;      /* actual size of tree nodes */
00063     /* The caller-supplied manipulation functions */
00064     rb_comparator comparator;
00065     rb_combiner combiner;
00066     rb_allocfunc allocfunc;
00067     rb_freefunc freefunc;
00068     /* Passthrough arg passed to all manipulation functions */
00069     void       *arg;
00070 };
00071 
00072 /*
00073  * all leafs are sentinels, use customized NIL name to prevent
00074  * collision with system-wide constant NIL which is actually NULL
00075  */
00076 #define RBNIL (&sentinel)
00077 
00078 static RBNode sentinel = {InitialState, RBBLACK, RBNIL, RBNIL, NULL};
00079 
00080 
00081 /*
00082  * rb_create: create an empty RBTree
00083  *
00084  * Arguments are:
00085  *  node_size: actual size of tree nodes (> sizeof(RBNode))
00086  *  The manipulation functions:
00087  *  comparator: compare two RBNodes for less/equal/greater
00088  *  combiner: merge an existing tree entry with a new one
00089  *  allocfunc: allocate a new RBNode
00090  *  freefunc: free an old RBNode
00091  *  arg: passthrough pointer that will be passed to the manipulation functions
00092  *
00093  * Note that the combiner's righthand argument will be a "proposed" tree node,
00094  * ie the input to rb_insert, in which the RBNode fields themselves aren't
00095  * valid.  Similarly, either input to the comparator may be a "proposed" node.
00096  * This shouldn't matter since the functions aren't supposed to look at the
00097  * RBNode fields, only the extra fields of the struct the RBNode is embedded
00098  * in.
00099  *
00100  * The freefunc should just be pfree or equivalent; it should NOT attempt
00101  * to free any subsidiary data, because the node passed to it may not contain
00102  * valid data!  freefunc can be NULL if caller doesn't require retail
00103  * space reclamation.
00104  *
00105  * The RBTree node is palloc'd in the caller's memory context.  Note that
00106  * all contents of the tree are actually allocated by the caller, not here.
00107  *
00108  * Since tree contents are managed by the caller, there is currently not
00109  * an explicit "destroy" operation; typically a tree would be freed by
00110  * resetting or deleting the memory context it's stored in.  You can pfree
00111  * the RBTree node if you feel the urge.
00112  */
00113 RBTree *
00114 rb_create(Size node_size,
00115           rb_comparator comparator,
00116           rb_combiner combiner,
00117           rb_allocfunc allocfunc,
00118           rb_freefunc freefunc,
00119           void *arg)
00120 {
00121     RBTree     *tree = (RBTree *) palloc(sizeof(RBTree));
00122 
00123     Assert(node_size > sizeof(RBNode));
00124 
00125     tree->root = RBNIL;
00126     tree->cur = RBNIL;
00127     tree->iterate = NULL;
00128     tree->node_size = node_size;
00129     tree->comparator = comparator;
00130     tree->combiner = combiner;
00131     tree->allocfunc = allocfunc;
00132     tree->freefunc = freefunc;
00133 
00134     tree->arg = arg;
00135 
00136     return tree;
00137 }
00138 
00139 /* Copy the additional data fields from one RBNode to another */
00140 static inline void
00141 rb_copy_data(RBTree *rb, RBNode *dest, const RBNode *src)
00142 {
00143     memcpy(dest + 1, src + 1, rb->node_size - sizeof(RBNode));
00144 }
00145 
00146 /**********************************************************************
00147  *                        Search                                      *
00148  **********************************************************************/
00149 
00150 /*
00151  * rb_find: search for a value in an RBTree
00152  *
00153  * data represents the value to try to find.  Its RBNode fields need not
00154  * be valid, it's the extra data in the larger struct that is of interest.
00155  *
00156  * Returns the matching tree entry, or NULL if no match is found.
00157  */
00158 RBNode *
00159 rb_find(RBTree *rb, const RBNode *data)
00160 {
00161     RBNode     *node = rb->root;
00162 
00163     while (node != RBNIL)
00164     {
00165         int         cmp = rb->comparator(data, node, rb->arg);
00166 
00167         if (cmp == 0)
00168             return node;
00169         else if (cmp < 0)
00170             node = node->left;
00171         else
00172             node = node->right;
00173     }
00174 
00175     return NULL;
00176 }
00177 
00178 /*
00179  * rb_leftmost: fetch the leftmost (smallest-valued) tree node.
00180  * Returns NULL if tree is empty.
00181  *
00182  * Note: in the original implementation this included an unlink step, but
00183  * that's a bit awkward.  Just call rb_delete on the result if that's what
00184  * you want.
00185  */
00186 RBNode *
00187 rb_leftmost(RBTree *rb)
00188 {
00189     RBNode     *node = rb->root;
00190     RBNode     *leftmost = rb->root;
00191 
00192     while (node != RBNIL)
00193     {
00194         leftmost = node;
00195         node = node->left;
00196     }
00197 
00198     if (leftmost != RBNIL)
00199         return leftmost;
00200 
00201     return NULL;
00202 }
00203 
00204 /**********************************************************************
00205  *                            Insertion                               *
00206  **********************************************************************/
00207 
00208 /*
00209  * Rotate node x to left.
00210  *
00211  * x's right child takes its place in the tree, and x becomes the left
00212  * child of that node.
00213  */
00214 static void
00215 rb_rotate_left(RBTree *rb, RBNode *x)
00216 {
00217     RBNode     *y = x->right;
00218 
00219     /* establish x->right link */
00220     x->right = y->left;
00221     if (y->left != RBNIL)
00222         y->left->parent = x;
00223 
00224     /* establish y->parent link */
00225     if (y != RBNIL)
00226         y->parent = x->parent;
00227     if (x->parent)
00228     {
00229         if (x == x->parent->left)
00230             x->parent->left = y;
00231         else
00232             x->parent->right = y;
00233     }
00234     else
00235     {
00236         rb->root = y;
00237     }
00238 
00239     /* link x and y */
00240     y->left = x;
00241     if (x != RBNIL)
00242         x->parent = y;
00243 }
00244 
00245 /*
00246  * Rotate node x to right.
00247  *
00248  * x's left right child takes its place in the tree, and x becomes the right
00249  * child of that node.
00250  */
00251 static void
00252 rb_rotate_right(RBTree *rb, RBNode *x)
00253 {
00254     RBNode     *y = x->left;
00255 
00256     /* establish x->left link */
00257     x->left = y->right;
00258     if (y->right != RBNIL)
00259         y->right->parent = x;
00260 
00261     /* establish y->parent link */
00262     if (y != RBNIL)
00263         y->parent = x->parent;
00264     if (x->parent)
00265     {
00266         if (x == x->parent->right)
00267             x->parent->right = y;
00268         else
00269             x->parent->left = y;
00270     }
00271     else
00272     {
00273         rb->root = y;
00274     }
00275 
00276     /* link x and y */
00277     y->right = x;
00278     if (x != RBNIL)
00279         x->parent = y;
00280 }
00281 
00282 /*
00283  * Maintain Red-Black tree balance after inserting node x.
00284  *
00285  * The newly inserted node is always initially marked red.  That may lead to
00286  * a situation where a red node has a red child, which is prohibited.  We can
00287  * always fix the problem by a series of color changes and/or "rotations",
00288  * which move the problem progressively higher up in the tree.  If one of the
00289  * two red nodes is the root, we can always fix the problem by changing the
00290  * root from red to black.
00291  *
00292  * (This does not work lower down in the tree because we must also maintain
00293  * the invariant that every leaf has equal black-height.)
00294  */
00295 static void
00296 rb_insert_fixup(RBTree *rb, RBNode *x)
00297 {
00298     /*
00299      * x is always a red node.  Initially, it is the newly inserted node. Each
00300      * iteration of this loop moves it higher up in the tree.
00301      */
00302     while (x != rb->root && x->parent->color == RBRED)
00303     {
00304         /*
00305          * x and x->parent are both red.  Fix depends on whether x->parent is
00306          * a left or right child.  In either case, we define y to be the
00307          * "uncle" of x, that is, the other child of x's grandparent.
00308          *
00309          * If the uncle is red, we flip the grandparent to red and its two
00310          * children to black.  Then we loop around again to check whether the
00311          * grandparent still has a problem.
00312          *
00313          * If the uncle is black, we will perform one or two "rotations" to
00314          * balance the tree.  Either x or x->parent will take the
00315          * grandparent's position in the tree and recolored black, and the
00316          * original grandparent will be recolored red and become a child of
00317          * that node. This always leaves us with a valid red-black tree, so
00318          * the loop will terminate.
00319          */
00320         if (x->parent == x->parent->parent->left)
00321         {
00322             RBNode     *y = x->parent->parent->right;
00323 
00324             if (y->color == RBRED)
00325             {
00326                 /* uncle is RBRED */
00327                 x->parent->color = RBBLACK;
00328                 y->color = RBBLACK;
00329                 x->parent->parent->color = RBRED;
00330 
00331                 x = x->parent->parent;
00332             }
00333             else
00334             {
00335                 /* uncle is RBBLACK */
00336                 if (x == x->parent->right)
00337                 {
00338                     /* make x a left child */
00339                     x = x->parent;
00340                     rb_rotate_left(rb, x);
00341                 }
00342 
00343                 /* recolor and rotate */
00344                 x->parent->color = RBBLACK;
00345                 x->parent->parent->color = RBRED;
00346 
00347                 rb_rotate_right(rb, x->parent->parent);
00348             }
00349         }
00350         else
00351         {
00352             /* mirror image of above code */
00353             RBNode     *y = x->parent->parent->left;
00354 
00355             if (y->color == RBRED)
00356             {
00357                 /* uncle is RBRED */
00358                 x->parent->color = RBBLACK;
00359                 y->color = RBBLACK;
00360                 x->parent->parent->color = RBRED;
00361 
00362                 x = x->parent->parent;
00363             }
00364             else
00365             {
00366                 /* uncle is RBBLACK */
00367                 if (x == x->parent->left)
00368                 {
00369                     x = x->parent;
00370                     rb_rotate_right(rb, x);
00371                 }
00372                 x->parent->color = RBBLACK;
00373                 x->parent->parent->color = RBRED;
00374 
00375                 rb_rotate_left(rb, x->parent->parent);
00376             }
00377         }
00378     }
00379 
00380     /*
00381      * The root may already have been black; if not, the black-height of every
00382      * node in the tree increases by one.
00383      */
00384     rb->root->color = RBBLACK;
00385 }
00386 
00387 /*
00388  * rb_insert: insert a new value into the tree.
00389  *
00390  * data represents the value to insert.  Its RBNode fields need not
00391  * be valid, it's the extra data in the larger struct that is of interest.
00392  *
00393  * If the value represented by "data" is not present in the tree, then
00394  * we copy "data" into a new tree entry and return that node, setting *isNew
00395  * to true.
00396  *
00397  * If the value represented by "data" is already present, then we call the
00398  * combiner function to merge data into the existing node, and return the
00399  * existing node, setting *isNew to false.
00400  *
00401  * "data" is unmodified in either case; it's typically just a local
00402  * variable in the caller.
00403  */
00404 RBNode *
00405 rb_insert(RBTree *rb, const RBNode *data, bool *isNew)
00406 {
00407     RBNode     *current,
00408                *parent,
00409                *x;
00410     int         cmp;
00411 
00412     /* find where node belongs */
00413     current = rb->root;
00414     parent = NULL;
00415     cmp = 0;                    /* just to prevent compiler warning */
00416 
00417     while (current != RBNIL)
00418     {
00419         cmp = rb->comparator(data, current, rb->arg);
00420         if (cmp == 0)
00421         {
00422             /*
00423              * Found node with given key.  Apply combiner.
00424              */
00425             rb->combiner(current, data, rb->arg);
00426             *isNew = false;
00427             return current;
00428         }
00429         parent = current;
00430         current = (cmp < 0) ? current->left : current->right;
00431     }
00432 
00433     /*
00434      * Value is not present, so create a new node containing data.
00435      */
00436     *isNew = true;
00437 
00438     x = rb->allocfunc (rb->arg);
00439 
00440     x->iteratorState = InitialState;
00441     x->color = RBRED;
00442 
00443     x->left = RBNIL;
00444     x->right = RBNIL;
00445     x->parent = parent;
00446     rb_copy_data(rb, x, data);
00447 
00448     /* insert node in tree */
00449     if (parent)
00450     {
00451         if (cmp < 0)
00452             parent->left = x;
00453         else
00454             parent->right = x;
00455     }
00456     else
00457     {
00458         rb->root = x;
00459     }
00460 
00461     rb_insert_fixup(rb, x);
00462 
00463     return x;
00464 }
00465 
00466 /**********************************************************************
00467  *                          Deletion                                  *
00468  **********************************************************************/
00469 
00470 /*
00471  * Maintain Red-Black tree balance after deleting a black node.
00472  */
00473 static void
00474 rb_delete_fixup(RBTree *rb, RBNode *x)
00475 {
00476     /*
00477      * x is always a black node.  Initially, it is the former child of the
00478      * deleted node.  Each iteration of this loop moves it higher up in the
00479      * tree.
00480      */
00481     while (x != rb->root && x->color == RBBLACK)
00482     {
00483         /*
00484          * Left and right cases are symmetric.  Any nodes that are children of
00485          * x have a black-height one less than the remainder of the nodes in
00486          * the tree.  We rotate and recolor nodes to move the problem up the
00487          * tree: at some stage we'll either fix the problem, or reach the root
00488          * (where the black-height is allowed to decrease).
00489          */
00490         if (x == x->parent->left)
00491         {
00492             RBNode     *w = x->parent->right;
00493 
00494             if (w->color == RBRED)
00495             {
00496                 w->color = RBBLACK;
00497                 x->parent->color = RBRED;
00498 
00499                 rb_rotate_left(rb, x->parent);
00500                 w = x->parent->right;
00501             }
00502 
00503             if (w->left->color == RBBLACK && w->right->color == RBBLACK)
00504             {
00505                 w->color = RBRED;
00506 
00507                 x = x->parent;
00508             }
00509             else
00510             {
00511                 if (w->right->color == RBBLACK)
00512                 {
00513                     w->left->color = RBBLACK;
00514                     w->color = RBRED;
00515 
00516                     rb_rotate_right(rb, w);
00517                     w = x->parent->right;
00518                 }
00519                 w->color = x->parent->color;
00520                 x->parent->color = RBBLACK;
00521                 w->right->color = RBBLACK;
00522 
00523                 rb_rotate_left(rb, x->parent);
00524                 x = rb->root;   /* Arrange for loop to terminate. */
00525             }
00526         }
00527         else
00528         {
00529             RBNode     *w = x->parent->left;
00530 
00531             if (w->color == RBRED)
00532             {
00533                 w->color = RBBLACK;
00534                 x->parent->color = RBRED;
00535 
00536                 rb_rotate_right(rb, x->parent);
00537                 w = x->parent->left;
00538             }
00539 
00540             if (w->right->color == RBBLACK && w->left->color == RBBLACK)
00541             {
00542                 w->color = RBRED;
00543 
00544                 x = x->parent;
00545             }
00546             else
00547             {
00548                 if (w->left->color == RBBLACK)
00549                 {
00550                     w->right->color = RBBLACK;
00551                     w->color = RBRED;
00552 
00553                     rb_rotate_left(rb, w);
00554                     w = x->parent->left;
00555                 }
00556                 w->color = x->parent->color;
00557                 x->parent->color = RBBLACK;
00558                 w->left->color = RBBLACK;
00559 
00560                 rb_rotate_right(rb, x->parent);
00561                 x = rb->root;   /* Arrange for loop to terminate. */
00562             }
00563         }
00564     }
00565     x->color = RBBLACK;
00566 }
00567 
00568 /*
00569  * Delete node z from tree.
00570  */
00571 static void
00572 rb_delete_node(RBTree *rb, RBNode *z)
00573 {
00574     RBNode     *x,
00575                *y;
00576 
00577     if (!z || z == RBNIL)
00578         return;
00579 
00580     /*
00581      * y is the node that will actually be removed from the tree.  This will
00582      * be z if z has fewer than two children, or the tree successor of z
00583      * otherwise.
00584      */
00585     if (z->left == RBNIL || z->right == RBNIL)
00586     {
00587         /* y has a RBNIL node as a child */
00588         y = z;
00589     }
00590     else
00591     {
00592         /* find tree successor */
00593         y = z->right;
00594         while (y->left != RBNIL)
00595             y = y->left;
00596     }
00597 
00598     /* x is y's only child */
00599     if (y->left != RBNIL)
00600         x = y->left;
00601     else
00602         x = y->right;
00603 
00604     /* Remove y from the tree. */
00605     x->parent = y->parent;
00606     if (y->parent)
00607     {
00608         if (y == y->parent->left)
00609             y->parent->left = x;
00610         else
00611             y->parent->right = x;
00612     }
00613     else
00614     {
00615         rb->root = x;
00616     }
00617 
00618     /*
00619      * If we removed the tree successor of z rather than z itself, then move
00620      * the data for the removed node to the one we were supposed to remove.
00621      */
00622     if (y != z)
00623         rb_copy_data(rb, z, y);
00624 
00625     /*
00626      * Removing a black node might make some paths from root to leaf contain
00627      * fewer black nodes than others, or it might make two red nodes adjacent.
00628      */
00629     if (y->color == RBBLACK)
00630         rb_delete_fixup(rb, x);
00631 
00632     /* Now we can recycle the y node */
00633     if (rb->freefunc)
00634         rb->freefunc (y, rb->arg);
00635 }
00636 
00637 /*
00638  * rb_delete: remove the given tree entry
00639  *
00640  * "node" must have previously been found via rb_find or rb_leftmost.
00641  * It is caller's responsibility to free any subsidiary data attached
00642  * to the node before calling rb_delete.  (Do *not* try to push that
00643  * responsibility off to the freefunc, as some other physical node
00644  * may be the one actually freed!)
00645  */
00646 void
00647 rb_delete(RBTree *rb, RBNode *node)
00648 {
00649     rb_delete_node(rb, node);
00650 }
00651 
00652 /**********************************************************************
00653  *                        Traverse                                    *
00654  **********************************************************************/
00655 
00656 /*
00657  * The iterator routines were originally coded in tail-recursion style,
00658  * which is nice to look at, but is trouble if your compiler isn't smart
00659  * enough to optimize it.  Now we just use looping.
00660  */
00661 #define descend(next_node) \
00662     do { \
00663         (next_node)->iteratorState = InitialState; \
00664         node = rb->cur = (next_node); \
00665         goto restart; \
00666     } while (0)
00667 
00668 #define ascend(next_node) \
00669     do { \
00670         node = rb->cur = (next_node); \
00671         goto restart; \
00672     } while (0)
00673 
00674 
00675 static RBNode *
00676 rb_left_right_iterator(RBTree *rb)
00677 {
00678     RBNode     *node = rb->cur;
00679 
00680 restart:
00681     switch (node->iteratorState)
00682     {
00683         case InitialState:
00684             if (node->left != RBNIL)
00685             {
00686                 node->iteratorState = FirstStepDone;
00687                 descend(node->left);
00688             }
00689             /* FALL THROUGH */
00690         case FirstStepDone:
00691             node->iteratorState = SecondStepDone;
00692             return node;
00693         case SecondStepDone:
00694             if (node->right != RBNIL)
00695             {
00696                 node->iteratorState = ThirdStepDone;
00697                 descend(node->right);
00698             }
00699             /* FALL THROUGH */
00700         case ThirdStepDone:
00701             if (node->parent)
00702                 ascend(node->parent);
00703             break;
00704         default:
00705             elog(ERROR, "unrecognized rbtree node state: %d",
00706                  node->iteratorState);
00707     }
00708 
00709     return NULL;
00710 }
00711 
00712 static RBNode *
00713 rb_right_left_iterator(RBTree *rb)
00714 {
00715     RBNode     *node = rb->cur;
00716 
00717 restart:
00718     switch (node->iteratorState)
00719     {
00720         case InitialState:
00721             if (node->right != RBNIL)
00722             {
00723                 node->iteratorState = FirstStepDone;
00724                 descend(node->right);
00725             }
00726             /* FALL THROUGH */
00727         case FirstStepDone:
00728             node->iteratorState = SecondStepDone;
00729             return node;
00730         case SecondStepDone:
00731             if (node->left != RBNIL)
00732             {
00733                 node->iteratorState = ThirdStepDone;
00734                 descend(node->left);
00735             }
00736             /* FALL THROUGH */
00737         case ThirdStepDone:
00738             if (node->parent)
00739                 ascend(node->parent);
00740             break;
00741         default:
00742             elog(ERROR, "unrecognized rbtree node state: %d",
00743                  node->iteratorState);
00744     }
00745 
00746     return NULL;
00747 }
00748 
00749 static RBNode *
00750 rb_direct_iterator(RBTree *rb)
00751 {
00752     RBNode     *node = rb->cur;
00753 
00754 restart:
00755     switch (node->iteratorState)
00756     {
00757         case InitialState:
00758             node->iteratorState = FirstStepDone;
00759             return node;
00760         case FirstStepDone:
00761             if (node->left != RBNIL)
00762             {
00763                 node->iteratorState = SecondStepDone;
00764                 descend(node->left);
00765             }
00766             /* FALL THROUGH */
00767         case SecondStepDone:
00768             if (node->right != RBNIL)
00769             {
00770                 node->iteratorState = ThirdStepDone;
00771                 descend(node->right);
00772             }
00773             /* FALL THROUGH */
00774         case ThirdStepDone:
00775             if (node->parent)
00776                 ascend(node->parent);
00777             break;
00778         default:
00779             elog(ERROR, "unrecognized rbtree node state: %d",
00780                  node->iteratorState);
00781     }
00782 
00783     return NULL;
00784 }
00785 
00786 static RBNode *
00787 rb_inverted_iterator(RBTree *rb)
00788 {
00789     RBNode     *node = rb->cur;
00790 
00791 restart:
00792     switch (node->iteratorState)
00793     {
00794         case InitialState:
00795             if (node->left != RBNIL)
00796             {
00797                 node->iteratorState = FirstStepDone;
00798                 descend(node->left);
00799             }
00800             /* FALL THROUGH */
00801         case FirstStepDone:
00802             if (node->right != RBNIL)
00803             {
00804                 node->iteratorState = SecondStepDone;
00805                 descend(node->right);
00806             }
00807             /* FALL THROUGH */
00808         case SecondStepDone:
00809             node->iteratorState = ThirdStepDone;
00810             return node;
00811         case ThirdStepDone:
00812             if (node->parent)
00813                 ascend(node->parent);
00814             break;
00815         default:
00816             elog(ERROR, "unrecognized rbtree node state: %d",
00817                  node->iteratorState);
00818     }
00819 
00820     return NULL;
00821 }
00822 
00823 /*
00824  * rb_begin_iterate: prepare to traverse the tree in any of several orders
00825  *
00826  * After calling rb_begin_iterate, call rb_iterate repeatedly until it
00827  * returns NULL or the traversal stops being of interest.
00828  *
00829  * If the tree is changed during traversal, results of further calls to
00830  * rb_iterate are unspecified.
00831  *
00832  * Note: this used to return a separately palloc'd iterator control struct,
00833  * but that's a bit pointless since the data structure is incapable of
00834  * supporting multiple concurrent traversals.  Now we just keep the state
00835  * in RBTree.
00836  */
00837 void
00838 rb_begin_iterate(RBTree *rb, RBOrderControl ctrl)
00839 {
00840     rb->cur = rb->root;
00841     if (rb->cur != RBNIL)
00842         rb->cur->iteratorState = InitialState;
00843 
00844     switch (ctrl)
00845     {
00846         case LeftRightWalk:     /* visit left, then self, then right */
00847             rb->iterate = rb_left_right_iterator;
00848             break;
00849         case RightLeftWalk:     /* visit right, then self, then left */
00850             rb->iterate = rb_right_left_iterator;
00851             break;
00852         case DirectWalk:        /* visit self, then left, then right */
00853             rb->iterate = rb_direct_iterator;
00854             break;
00855         case InvertedWalk:      /* visit left, then right, then self */
00856             rb->iterate = rb_inverted_iterator;
00857             break;
00858         default:
00859             elog(ERROR, "unrecognized rbtree iteration order: %d", ctrl);
00860     }
00861 }
00862 
00863 /*
00864  * rb_iterate: return the next node in traversal order, or NULL if no more
00865  */
00866 RBNode *
00867 rb_iterate(RBTree *rb)
00868 {
00869     if (rb->cur == RBNIL)
00870         return NULL;
00871 
00872     return rb->iterate(rb);
00873 }