#include "postgres.h"#include "utils/rbtree.h"
Go to the source code of this file.
Data Structures | |
| struct | RBTree |
Defines | |
| #define | InitialState (0) |
| #define | FirstStepDone (1) |
| #define | SecondStepDone (2) |
| #define | ThirdStepDone (3) |
| #define | RBBLACK (0) |
| #define | RBRED (1) |
| #define | RBNIL (&sentinel) |
| #define | descend(next_node) |
| #define | ascend(next_node) |
Functions | |
| RBTree * | rb_create (Size node_size, rb_comparator comparator, rb_combiner combiner, rb_allocfunc allocfunc, rb_freefunc freefunc, void *arg) |
| static void | rb_copy_data (RBTree *rb, RBNode *dest, const RBNode *src) |
| RBNode * | rb_find (RBTree *rb, const RBNode *data) |
| RBNode * | rb_leftmost (RBTree *rb) |
| static void | rb_rotate_left (RBTree *rb, RBNode *x) |
| static void | rb_rotate_right (RBTree *rb, RBNode *x) |
| static void | rb_insert_fixup (RBTree *rb, RBNode *x) |
| RBNode * | rb_insert (RBTree *rb, const RBNode *data, bool *isNew) |
| static void | rb_delete_fixup (RBTree *rb, RBNode *x) |
| static void | rb_delete_node (RBTree *rb, RBNode *z) |
| void | rb_delete (RBTree *rb, RBNode *node) |
| static RBNode * | rb_left_right_iterator (RBTree *rb) |
| static RBNode * | rb_right_left_iterator (RBTree *rb) |
| static RBNode * | rb_direct_iterator (RBTree *rb) |
| static RBNode * | rb_inverted_iterator (RBTree *rb) |
| void | rb_begin_iterate (RBTree *rb, RBOrderControl ctrl) |
| RBNode * | rb_iterate (RBTree *rb) |
Variables | |
| static RBNode | sentinel = {InitialState, RBBLACK, RBNIL, RBNIL, NULL} |
| #define ascend | ( | next_node | ) |
do { \ node = rb->cur = (next_node); \ goto restart; \ } while (0)
Definition at line 668 of file rbtree.c.
Referenced by rb_direct_iterator(), rb_inverted_iterator(), rb_left_right_iterator(), and rb_right_left_iterator().
| #define descend | ( | next_node | ) |
do { \ (next_node)->iteratorState = InitialState; \ node = rb->cur = (next_node); \ goto restart; \ } while (0)
Definition at line 661 of file rbtree.c.
Referenced by rb_direct_iterator(), rb_inverted_iterator(), rb_left_right_iterator(), and rb_right_left_iterator().
| #define FirstStepDone (1) |
Definition at line 39 of file rbtree.c.
Referenced by rb_direct_iterator(), rb_inverted_iterator(), rb_left_right_iterator(), and rb_right_left_iterator().
| #define InitialState (0) |
Definition at line 38 of file rbtree.c.
Referenced by rb_direct_iterator(), rb_inverted_iterator(), rb_left_right_iterator(), and rb_right_left_iterator().
| #define RBBLACK (0) |
Definition at line 46 of file rbtree.c.
Referenced by rb_delete_fixup(), and rb_delete_node().
| #define RBNIL (&sentinel) |
Definition at line 76 of file rbtree.c.
Referenced by rb_begin_iterate(), rb_delete_node(), rb_direct_iterator(), rb_find(), rb_insert(), rb_inverted_iterator(), rb_iterate(), rb_left_right_iterator(), rb_leftmost(), rb_right_left_iterator(), rb_rotate_left(), and rb_rotate_right().
| #define RBRED (1) |
Definition at line 47 of file rbtree.c.
Referenced by rb_delete_fixup(), and rb_insert_fixup().
| #define SecondStepDone (2) |
Definition at line 40 of file rbtree.c.
Referenced by rb_direct_iterator(), rb_inverted_iterator(), rb_left_right_iterator(), and rb_right_left_iterator().
| #define ThirdStepDone (3) |
Definition at line 41 of file rbtree.c.
Referenced by rb_direct_iterator(), rb_inverted_iterator(), rb_left_right_iterator(), and rb_right_left_iterator().
| void rb_begin_iterate | ( | RBTree * | rb, | |
| RBOrderControl | ctrl | |||
| ) |
Definition at line 838 of file rbtree.c.
References RBTree::cur, DirectWalk, elog, ERROR, InvertedWalk, RBTree::iterate, RBNode::iteratorState, LeftRightWalk, RBNIL, RightLeftWalk, and RBTree::root.
Referenced by ginBeginBAScan().
{
rb->cur = rb->root;
if (rb->cur != RBNIL)
rb->cur->iteratorState = InitialState;
switch (ctrl)
{
case LeftRightWalk: /* visit left, then self, then right */
rb->iterate = rb_left_right_iterator;
break;
case RightLeftWalk: /* visit right, then self, then left */
rb->iterate = rb_right_left_iterator;
break;
case DirectWalk: /* visit self, then left, then right */
rb->iterate = rb_direct_iterator;
break;
case InvertedWalk: /* visit left, then right, then self */
rb->iterate = rb_inverted_iterator;
break;
default:
elog(ERROR, "unrecognized rbtree iteration order: %d", ctrl);
}
}
Definition at line 141 of file rbtree.c.
References RBTree::node_size.
Referenced by rb_delete_node(), and rb_insert().
| RBTree* rb_create | ( | Size | node_size, | |
| rb_comparator | comparator, | |||
| rb_combiner | combiner, | |||
| rb_allocfunc | allocfunc, | |||
| rb_freefunc | freefunc, | |||
| void * | arg | |||
| ) |
Definition at line 114 of file rbtree.c.
References RBTree::allocfunc, RBTree::arg, Assert, RBTree::combiner, RBTree::comparator, RBTree::cur, RBTree::freefunc, RBTree::iterate, RBTree::node_size, palloc(), and RBTree::root.
Referenced by ginInitBA(), and gistrescan().
{
RBTree *tree = (RBTree *) palloc(sizeof(RBTree));
Assert(node_size > sizeof(RBNode));
tree->root = RBNIL;
tree->cur = RBNIL;
tree->iterate = NULL;
tree->node_size = node_size;
tree->comparator = comparator;
tree->combiner = combiner;
tree->allocfunc = allocfunc;
tree->freefunc = freefunc;
tree->arg = arg;
return tree;
}
Definition at line 647 of file rbtree.c.
References rb_delete_node().
Referenced by getNextGISTSearchItem().
{
rb_delete_node(rb, node);
}
Definition at line 474 of file rbtree.c.
References RBNode::color, RBNode::left, RBNode::parent, rb_rotate_left(), rb_rotate_right(), RBBLACK, RBRED, RBNode::right, and RBTree::root.
Referenced by rb_delete_node().
{
/*
* x is always a black node. Initially, it is the former child of the
* deleted node. Each iteration of this loop moves it higher up in the
* tree.
*/
while (x != rb->root && x->color == RBBLACK)
{
/*
* Left and right cases are symmetric. Any nodes that are children of
* x have a black-height one less than the remainder of the nodes in
* the tree. We rotate and recolor nodes to move the problem up the
* tree: at some stage we'll either fix the problem, or reach the root
* (where the black-height is allowed to decrease).
*/
if (x == x->parent->left)
{
RBNode *w = x->parent->right;
if (w->color == RBRED)
{
w->color = RBBLACK;
x->parent->color = RBRED;
rb_rotate_left(rb, x->parent);
w = x->parent->right;
}
if (w->left->color == RBBLACK && w->right->color == RBBLACK)
{
w->color = RBRED;
x = x->parent;
}
else
{
if (w->right->color == RBBLACK)
{
w->left->color = RBBLACK;
w->color = RBRED;
rb_rotate_right(rb, w);
w = x->parent->right;
}
w->color = x->parent->color;
x->parent->color = RBBLACK;
w->right->color = RBBLACK;
rb_rotate_left(rb, x->parent);
x = rb->root; /* Arrange for loop to terminate. */
}
}
else
{
RBNode *w = x->parent->left;
if (w->color == RBRED)
{
w->color = RBBLACK;
x->parent->color = RBRED;
rb_rotate_right(rb, x->parent);
w = x->parent->left;
}
if (w->right->color == RBBLACK && w->left->color == RBBLACK)
{
w->color = RBRED;
x = x->parent;
}
else
{
if (w->left->color == RBBLACK)
{
w->right->color = RBBLACK;
w->color = RBRED;
rb_rotate_left(rb, w);
w = x->parent->left;
}
w->color = x->parent->color;
x->parent->color = RBBLACK;
w->left->color = RBBLACK;
rb_rotate_right(rb, x->parent);
x = rb->root; /* Arrange for loop to terminate. */
}
}
}
x->color = RBBLACK;
}
Definition at line 572 of file rbtree.c.
References RBTree::arg, RBNode::color, RBTree::freefunc, RBNode::left, RBNode::parent, rb_copy_data(), rb_delete_fixup(), RBBLACK, RBNIL, RBNode::right, and RBTree::root.
Referenced by rb_delete().
{
RBNode *x,
*y;
if (!z || z == RBNIL)
return;
/*
* y is the node that will actually be removed from the tree. This will
* be z if z has fewer than two children, or the tree successor of z
* otherwise.
*/
if (z->left == RBNIL || z->right == RBNIL)
{
/* y has a RBNIL node as a child */
y = z;
}
else
{
/* find tree successor */
y = z->right;
while (y->left != RBNIL)
y = y->left;
}
/* x is y's only child */
if (y->left != RBNIL)
x = y->left;
else
x = y->right;
/* Remove y from the tree. */
x->parent = y->parent;
if (y->parent)
{
if (y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
}
else
{
rb->root = x;
}
/*
* If we removed the tree successor of z rather than z itself, then move
* the data for the removed node to the one we were supposed to remove.
*/
if (y != z)
rb_copy_data(rb, z, y);
/*
* Removing a black node might make some paths from root to leaf contain
* fewer black nodes than others, or it might make two red nodes adjacent.
*/
if (y->color == RBBLACK)
rb_delete_fixup(rb, x);
/* Now we can recycle the y node */
if (rb->freefunc)
rb->freefunc (y, rb->arg);
}
Definition at line 750 of file rbtree.c.
References ascend, RBTree::cur, descend, elog, ERROR, FirstStepDone, InitialState, RBNode::iteratorState, RBNode::left, RBNode::parent, RBNIL, RBNode::right, SecondStepDone, and ThirdStepDone.
{
RBNode *node = rb->cur;
restart:
switch (node->iteratorState)
{
case InitialState:
node->iteratorState = FirstStepDone;
return node;
case FirstStepDone:
if (node->left != RBNIL)
{
node->iteratorState = SecondStepDone;
descend(node->left);
}
/* FALL THROUGH */
case SecondStepDone:
if (node->right != RBNIL)
{
node->iteratorState = ThirdStepDone;
descend(node->right);
}
/* FALL THROUGH */
case ThirdStepDone:
if (node->parent)
ascend(node->parent);
break;
default:
elog(ERROR, "unrecognized rbtree node state: %d",
node->iteratorState);
}
return NULL;
}
Definition at line 159 of file rbtree.c.
References RBTree::arg, cmp(), RBTree::comparator, RBNode::left, RBNIL, RBNode::right, and RBTree::root.
Definition at line 405 of file rbtree.c.
References RBTree::allocfunc, RBTree::arg, RBNode::color, RBTree::combiner, RBTree::comparator, RBNode::iteratorState, RBNode::left, RBNode::parent, rb_copy_data(), rb_insert_fixup(), RBNIL, RBNode::right, and RBTree::root.
Referenced by ginInsertBAEntry(), and gistScanPage().
{
RBNode *current,
*parent,
*x;
int cmp;
/* find where node belongs */
current = rb->root;
parent = NULL;
cmp = 0; /* just to prevent compiler warning */
while (current != RBNIL)
{
cmp = rb->comparator(data, current, rb->arg);
if (cmp == 0)
{
/*
* Found node with given key. Apply combiner.
*/
rb->combiner(current, data, rb->arg);
*isNew = false;
return current;
}
parent = current;
current = (cmp < 0) ? current->left : current->right;
}
/*
* Value is not present, so create a new node containing data.
*/
*isNew = true;
x = rb->allocfunc (rb->arg);
x->iteratorState = InitialState;
x->color = RBRED;
x->left = RBNIL;
x->right = RBNIL;
x->parent = parent;
rb_copy_data(rb, x, data);
/* insert node in tree */
if (parent)
{
if (cmp < 0)
parent->left = x;
else
parent->right = x;
}
else
{
rb->root = x;
}
rb_insert_fixup(rb, x);
return x;
}
Definition at line 296 of file rbtree.c.
References RBNode::color, RBNode::left, RBNode::parent, rb_rotate_left(), rb_rotate_right(), RBRED, RBNode::right, and RBTree::root.
Referenced by rb_insert().
{
/*
* x is always a red node. Initially, it is the newly inserted node. Each
* iteration of this loop moves it higher up in the tree.
*/
while (x != rb->root && x->parent->color == RBRED)
{
/*
* x and x->parent are both red. Fix depends on whether x->parent is
* a left or right child. In either case, we define y to be the
* "uncle" of x, that is, the other child of x's grandparent.
*
* If the uncle is red, we flip the grandparent to red and its two
* children to black. Then we loop around again to check whether the
* grandparent still has a problem.
*
* If the uncle is black, we will perform one or two "rotations" to
* balance the tree. Either x or x->parent will take the
* grandparent's position in the tree and recolored black, and the
* original grandparent will be recolored red and become a child of
* that node. This always leaves us with a valid red-black tree, so
* the loop will terminate.
*/
if (x->parent == x->parent->parent->left)
{
RBNode *y = x->parent->parent->right;
if (y->color == RBRED)
{
/* uncle is RBRED */
x->parent->color = RBBLACK;
y->color = RBBLACK;
x->parent->parent->color = RBRED;
x = x->parent->parent;
}
else
{
/* uncle is RBBLACK */
if (x == x->parent->right)
{
/* make x a left child */
x = x->parent;
rb_rotate_left(rb, x);
}
/* recolor and rotate */
x->parent->color = RBBLACK;
x->parent->parent->color = RBRED;
rb_rotate_right(rb, x->parent->parent);
}
}
else
{
/* mirror image of above code */
RBNode *y = x->parent->parent->left;
if (y->color == RBRED)
{
/* uncle is RBRED */
x->parent->color = RBBLACK;
y->color = RBBLACK;
x->parent->parent->color = RBRED;
x = x->parent->parent;
}
else
{
/* uncle is RBBLACK */
if (x == x->parent->left)
{
x = x->parent;
rb_rotate_right(rb, x);
}
x->parent->color = RBBLACK;
x->parent->parent->color = RBRED;
rb_rotate_left(rb, x->parent->parent);
}
}
}
/*
* The root may already have been black; if not, the black-height of every
* node in the tree increases by one.
*/
rb->root->color = RBBLACK;
}
Definition at line 787 of file rbtree.c.
References ascend, RBTree::cur, descend, elog, ERROR, FirstStepDone, InitialState, RBNode::iteratorState, RBNode::left, RBNode::parent, RBNIL, RBNode::right, SecondStepDone, and ThirdStepDone.
{
RBNode *node = rb->cur;
restart:
switch (node->iteratorState)
{
case InitialState:
if (node->left != RBNIL)
{
node->iteratorState = FirstStepDone;
descend(node->left);
}
/* FALL THROUGH */
case FirstStepDone:
if (node->right != RBNIL)
{
node->iteratorState = SecondStepDone;
descend(node->right);
}
/* FALL THROUGH */
case SecondStepDone:
node->iteratorState = ThirdStepDone;
return node;
case ThirdStepDone:
if (node->parent)
ascend(node->parent);
break;
default:
elog(ERROR, "unrecognized rbtree node state: %d",
node->iteratorState);
}
return NULL;
}
Definition at line 867 of file rbtree.c.
References RBTree::cur, RBTree::iterate, and RBNIL.
Referenced by ginGetBAEntry().
Definition at line 676 of file rbtree.c.
References ascend, RBTree::cur, descend, elog, ERROR, FirstStepDone, InitialState, RBNode::iteratorState, RBNode::left, RBNode::parent, RBNIL, RBNode::right, SecondStepDone, and ThirdStepDone.
{
RBNode *node = rb->cur;
restart:
switch (node->iteratorState)
{
case InitialState:
if (node->left != RBNIL)
{
node->iteratorState = FirstStepDone;
descend(node->left);
}
/* FALL THROUGH */
case FirstStepDone:
node->iteratorState = SecondStepDone;
return node;
case SecondStepDone:
if (node->right != RBNIL)
{
node->iteratorState = ThirdStepDone;
descend(node->right);
}
/* FALL THROUGH */
case ThirdStepDone:
if (node->parent)
ascend(node->parent);
break;
default:
elog(ERROR, "unrecognized rbtree node state: %d",
node->iteratorState);
}
return NULL;
}
Definition at line 187 of file rbtree.c.
References RBNode::left, RBNIL, and RBTree::root.
Referenced by getNextGISTSearchItem().
Definition at line 713 of file rbtree.c.
References ascend, RBTree::cur, descend, elog, ERROR, FirstStepDone, InitialState, RBNode::iteratorState, RBNode::left, RBNode::parent, RBNIL, RBNode::right, SecondStepDone, and ThirdStepDone.
{
RBNode *node = rb->cur;
restart:
switch (node->iteratorState)
{
case InitialState:
if (node->right != RBNIL)
{
node->iteratorState = FirstStepDone;
descend(node->right);
}
/* FALL THROUGH */
case FirstStepDone:
node->iteratorState = SecondStepDone;
return node;
case SecondStepDone:
if (node->left != RBNIL)
{
node->iteratorState = ThirdStepDone;
descend(node->left);
}
/* FALL THROUGH */
case ThirdStepDone:
if (node->parent)
ascend(node->parent);
break;
default:
elog(ERROR, "unrecognized rbtree node state: %d",
node->iteratorState);
}
return NULL;
}
Definition at line 215 of file rbtree.c.
References RBNode::left, RBNode::parent, RBNIL, RBNode::right, and RBTree::root.
Referenced by rb_delete_fixup(), and rb_insert_fixup().
{
RBNode *y = x->right;
/* establish x->right link */
x->right = y->left;
if (y->left != RBNIL)
y->left->parent = x;
/* establish y->parent link */
if (y != RBNIL)
y->parent = x->parent;
if (x->parent)
{
if (x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
}
else
{
rb->root = y;
}
/* link x and y */
y->left = x;
if (x != RBNIL)
x->parent = y;
}
Definition at line 252 of file rbtree.c.
References RBNode::left, RBNode::parent, RBNIL, RBNode::right, and RBTree::root.
Referenced by rb_delete_fixup(), and rb_insert_fixup().
{
RBNode *y = x->left;
/* establish x->left link */
x->left = y->right;
if (y->right != RBNIL)
y->right->parent = x;
/* establish y->parent link */
if (y != RBNIL)
y->parent = x->parent;
if (x->parent)
{
if (x == x->parent->right)
x->parent->right = y;
else
x->parent->left = y;
}
else
{
rb->root = y;
}
/* link x and y */
y->right = x;
if (x != RBNIL)
x->parent = y;
}
1.7.1