| /*------------------------------------------------------------------------- |
| * |
| * rbtree.c |
| * implementation for PostgreSQL generic Red-Black binary tree package |
| * Adopted from http://algolist.manual.ru/ds/rbtree.php |
| * |
| * This code comes from Thomas Niemann's "Sorting and Searching Algorithms: |
| * a Cookbook". |
| * |
| * See http://www.cs.auckland.ac.nz/software/AlgAnim/niemann/s_man.htm for |
| * license terms: "Source code, when part of a software project, may be used |
| * freely without reference to the author." |
| * |
| * Red-black trees are a type of balanced binary tree wherein (1) any child of |
| * a red node is always black, and (2) every path from root to leaf traverses |
| * an equal number of black nodes. From these properties, it follows that the |
| * longest path from root to leaf is only about twice as long as the shortest, |
| * so lookups are guaranteed to run in O(lg n) time. |
| * |
| * Copyright (c) 2009-2023, PostgreSQL Global Development Group |
| * |
| * IDENTIFICATION |
| * src/backend/lib/rbtree.c |
| * |
| *------------------------------------------------------------------------- |
| */ |
| #include "postgres.h" |
| |
| #include "lib/rbtree.h" |
| |
| |
| /* |
| * Colors of nodes (values of RBTNode.color) |
| */ |
| #define RBTBLACK (0) |
| #define RBTRED (1) |
| |
| /* |
| * RBTree control structure |
| */ |
| struct RBTree |
| { |
| RBTNode *root; /* root node, or RBTNIL if tree is empty */ |
| |
| /* Remaining fields are constant after rbt_create */ |
| |
| Size node_size; /* actual size of tree nodes */ |
| /* The caller-supplied manipulation functions */ |
| rbt_comparator comparator; |
| rbt_combiner combiner; |
| rbt_allocfunc allocfunc; |
| rbt_freefunc freefunc; |
| /* Passthrough arg passed to all manipulation functions */ |
| void *arg; |
| }; |
| |
| /* |
| * all leafs are sentinels, use customized NIL name to prevent |
| * collision with system-wide constant NIL which is actually NULL |
| */ |
| #define RBTNIL (&sentinel) |
| |
| static RBTNode sentinel = |
| { |
| .color = RBTBLACK,.left = RBTNIL,.right = RBTNIL,.parent = NULL |
| }; |
| |
| |
| /* |
| * rbt_create: create an empty RBTree |
| * |
| * Arguments are: |
| * node_size: actual size of tree nodes (> sizeof(RBTNode)) |
| * The manipulation functions: |
| * comparator: compare two RBTNodes for less/equal/greater |
| * combiner: merge an existing tree entry with a new one |
| * allocfunc: allocate a new RBTNode |
| * freefunc: free an old RBTNode |
| * arg: passthrough pointer that will be passed to the manipulation functions |
| * |
| * Note that the combiner's righthand argument will be a "proposed" tree node, |
| * ie the input to rbt_insert, in which the RBTNode fields themselves aren't |
| * valid. Similarly, either input to the comparator may be a "proposed" node. |
| * This shouldn't matter since the functions aren't supposed to look at the |
| * RBTNode fields, only the extra fields of the struct the RBTNode is embedded |
| * in. |
| * |
| * The freefunc should just be pfree or equivalent; it should NOT attempt |
| * to free any subsidiary data, because the node passed to it may not contain |
| * valid data! freefunc can be NULL if caller doesn't require retail |
| * space reclamation. |
| * |
| * The RBTree node is palloc'd in the caller's memory context. Note that |
| * all contents of the tree are actually allocated by the caller, not here. |
| * |
| * Since tree contents are managed by the caller, there is currently not |
| * an explicit "destroy" operation; typically a tree would be freed by |
| * resetting or deleting the memory context it's stored in. You can pfree |
| * the RBTree node if you feel the urge. |
| */ |
| RBTree * |
| rbt_create(Size node_size, |
| rbt_comparator comparator, |
| rbt_combiner combiner, |
| rbt_allocfunc allocfunc, |
| rbt_freefunc freefunc, |
| void *arg) |
| { |
| RBTree *tree = (RBTree *) palloc(sizeof(RBTree)); |
| |
| Assert(node_size > sizeof(RBTNode)); |
| |
| tree->root = RBTNIL; |
| tree->node_size = node_size; |
| tree->comparator = comparator; |
| tree->combiner = combiner; |
| tree->allocfunc = allocfunc; |
| tree->freefunc = freefunc; |
| |
| tree->arg = arg; |
| |
| return tree; |
| } |
| |
| /* Copy the additional data fields from one RBTNode to another */ |
| static inline void |
| rbt_copy_data(RBTree *rbt, RBTNode *dest, const RBTNode *src) |
| { |
| memcpy(dest + 1, src + 1, rbt->node_size - sizeof(RBTNode)); |
| } |
| |
| /********************************************************************** |
| * Search * |
| **********************************************************************/ |
| |
| /* |
| * rbt_find: search for a value in an RBTree |
| * |
| * data represents the value to try to find. Its RBTNode fields need not |
| * be valid, it's the extra data in the larger struct that is of interest. |
| * |
| * Returns the matching tree entry, or NULL if no match is found. |
| */ |
| RBTNode * |
| rbt_find(RBTree *rbt, const RBTNode *data) |
| { |
| RBTNode *node = rbt->root; |
| |
| while (node != RBTNIL) |
| { |
| int cmp = rbt->comparator(data, node, rbt->arg); |
| |
| if (cmp == 0) |
| return node; |
| else if (cmp < 0) |
| node = node->left; |
| else |
| node = node->right; |
| } |
| |
| return NULL; |
| } |
| |
| /* |
| * rbt_find_great: search for a greater value in an RBTree |
| * |
| * If equal_match is true, this will be a great or equal search. |
| * |
| * Returns the matching tree entry, or NULL if no match is found. |
| */ |
| RBTNode * |
| rbt_find_great(RBTree *rbt, const RBTNode *data, bool equal_match) |
| { |
| RBTNode *node = rbt->root; |
| RBTNode *greater = NULL; |
| |
| while (node != RBTNIL) |
| { |
| int cmp = rbt->comparator(data, node, rbt->arg); |
| |
| if (equal_match && cmp == 0) |
| return node; |
| else if (cmp < 0) |
| { |
| greater = node; |
| node = node->left; |
| } |
| else |
| node = node->right; |
| } |
| |
| return greater; |
| } |
| |
| /* |
| * rbt_find_less: search for a lesser value in an RBTree |
| * |
| * If equal_match is true, this will be a less or equal search. |
| * |
| * Returns the matching tree entry, or NULL if no match is found. |
| */ |
| RBTNode * |
| rbt_find_less(RBTree *rbt, const RBTNode *data, bool equal_match) |
| { |
| RBTNode *node = rbt->root; |
| RBTNode *lesser = NULL; |
| |
| while (node != RBTNIL) |
| { |
| int cmp = rbt->comparator(data, node, rbt->arg); |
| |
| if (equal_match && cmp == 0) |
| return node; |
| else if (cmp > 0) |
| { |
| lesser = node; |
| node = node->right; |
| } |
| else |
| node = node->left; |
| } |
| |
| return lesser; |
| } |
| |
| /* |
| * rbt_leftmost: fetch the leftmost (smallest-valued) tree node. |
| * Returns NULL if tree is empty. |
| * |
| * Note: in the original implementation this included an unlink step, but |
| * that's a bit awkward. Just call rbt_delete on the result if that's what |
| * you want. |
| */ |
| RBTNode * |
| rbt_leftmost(RBTree *rbt) |
| { |
| RBTNode *node = rbt->root; |
| RBTNode *leftmost = rbt->root; |
| |
| while (node != RBTNIL) |
| { |
| leftmost = node; |
| node = node->left; |
| } |
| |
| if (leftmost != RBTNIL) |
| return leftmost; |
| |
| return NULL; |
| } |
| |
| /********************************************************************** |
| * Insertion * |
| **********************************************************************/ |
| |
| /* |
| * Rotate node x to left. |
| * |
| * x's right child takes its place in the tree, and x becomes the left |
| * child of that node. |
| */ |
| static void |
| rbt_rotate_left(RBTree *rbt, RBTNode *x) |
| { |
| RBTNode *y = x->right; |
| |
| /* establish x->right link */ |
| x->right = y->left; |
| if (y->left != RBTNIL) |
| y->left->parent = x; |
| |
| /* establish y->parent link */ |
| if (y != RBTNIL) |
| y->parent = x->parent; |
| if (x->parent) |
| { |
| if (x == x->parent->left) |
| x->parent->left = y; |
| else |
| x->parent->right = y; |
| } |
| else |
| { |
| rbt->root = y; |
| } |
| |
| /* link x and y */ |
| y->left = x; |
| if (x != RBTNIL) |
| x->parent = y; |
| } |
| |
| /* |
| * Rotate node x to right. |
| * |
| * x's left right child takes its place in the tree, and x becomes the right |
| * child of that node. |
| */ |
| static void |
| rbt_rotate_right(RBTree *rbt, RBTNode *x) |
| { |
| RBTNode *y = x->left; |
| |
| /* establish x->left link */ |
| x->left = y->right; |
| if (y->right != RBTNIL) |
| y->right->parent = x; |
| |
| /* establish y->parent link */ |
| if (y != RBTNIL) |
| y->parent = x->parent; |
| if (x->parent) |
| { |
| if (x == x->parent->right) |
| x->parent->right = y; |
| else |
| x->parent->left = y; |
| } |
| else |
| { |
| rbt->root = y; |
| } |
| |
| /* link x and y */ |
| y->right = x; |
| if (x != RBTNIL) |
| x->parent = y; |
| } |
| |
| /* |
| * Maintain Red-Black tree balance after inserting node x. |
| * |
| * The newly inserted node is always initially marked red. That may lead to |
| * a situation where a red node has a red child, which is prohibited. We can |
| * always fix the problem by a series of color changes and/or "rotations", |
| * which move the problem progressively higher up in the tree. If one of the |
| * two red nodes is the root, we can always fix the problem by changing the |
| * root from red to black. |
| * |
| * (This does not work lower down in the tree because we must also maintain |
| * the invariant that every leaf has equal black-height.) |
| */ |
| static void |
| rbt_insert_fixup(RBTree *rbt, RBTNode *x) |
| { |
| /* |
| * 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 != rbt->root && x->parent->color == RBTRED) |
| { |
| /* |
| * 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) |
| { |
| RBTNode *y = x->parent->parent->right; |
| |
| if (y->color == RBTRED) |
| { |
| /* uncle is RBTRED */ |
| x->parent->color = RBTBLACK; |
| y->color = RBTBLACK; |
| x->parent->parent->color = RBTRED; |
| |
| x = x->parent->parent; |
| } |
| else |
| { |
| /* uncle is RBTBLACK */ |
| if (x == x->parent->right) |
| { |
| /* make x a left child */ |
| x = x->parent; |
| rbt_rotate_left(rbt, x); |
| } |
| |
| /* recolor and rotate */ |
| x->parent->color = RBTBLACK; |
| x->parent->parent->color = RBTRED; |
| |
| rbt_rotate_right(rbt, x->parent->parent); |
| } |
| } |
| else |
| { |
| /* mirror image of above code */ |
| RBTNode *y = x->parent->parent->left; |
| |
| if (y->color == RBTRED) |
| { |
| /* uncle is RBTRED */ |
| x->parent->color = RBTBLACK; |
| y->color = RBTBLACK; |
| x->parent->parent->color = RBTRED; |
| |
| x = x->parent->parent; |
| } |
| else |
| { |
| /* uncle is RBTBLACK */ |
| if (x == x->parent->left) |
| { |
| x = x->parent; |
| rbt_rotate_right(rbt, x); |
| } |
| x->parent->color = RBTBLACK; |
| x->parent->parent->color = RBTRED; |
| |
| rbt_rotate_left(rbt, x->parent->parent); |
| } |
| } |
| } |
| |
| /* |
| * The root may already have been black; if not, the black-height of every |
| * node in the tree increases by one. |
| */ |
| rbt->root->color = RBTBLACK; |
| } |
| |
| /* |
| * rbt_insert: insert a new value into the tree. |
| * |
| * data represents the value to insert. Its RBTNode fields need not |
| * be valid, it's the extra data in the larger struct that is of interest. |
| * |
| * If the value represented by "data" is not present in the tree, then |
| * we copy "data" into a new tree entry and return that node, setting *isNew |
| * to true. |
| * |
| * If the value represented by "data" is already present, then we call the |
| * combiner function to merge data into the existing node, and return the |
| * existing node, setting *isNew to false. |
| * |
| * "data" is unmodified in either case; it's typically just a local |
| * variable in the caller. |
| */ |
| RBTNode * |
| rbt_insert(RBTree *rbt, const RBTNode *data, bool *isNew) |
| { |
| RBTNode *current, |
| *parent, |
| *x; |
| int cmp; |
| |
| /* find where node belongs */ |
| current = rbt->root; |
| parent = NULL; |
| cmp = 0; /* just to prevent compiler warning */ |
| |
| while (current != RBTNIL) |
| { |
| cmp = rbt->comparator(data, current, rbt->arg); |
| if (cmp == 0) |
| { |
| /* |
| * Found node with given key. Apply combiner. |
| */ |
| rbt->combiner(current, data, rbt->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 = rbt->allocfunc(rbt->arg); |
| |
| x->color = RBTRED; |
| |
| x->left = RBTNIL; |
| x->right = RBTNIL; |
| x->parent = parent; |
| rbt_copy_data(rbt, x, data); |
| |
| /* insert node in tree */ |
| if (parent) |
| { |
| if (cmp < 0) |
| parent->left = x; |
| else |
| parent->right = x; |
| } |
| else |
| { |
| rbt->root = x; |
| } |
| |
| rbt_insert_fixup(rbt, x); |
| |
| return x; |
| } |
| |
| /********************************************************************** |
| * Deletion * |
| **********************************************************************/ |
| |
| /* |
| * Maintain Red-Black tree balance after deleting a black node. |
| */ |
| static void |
| rbt_delete_fixup(RBTree *rbt, RBTNode *x) |
| { |
| /* |
| * 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 != rbt->root && x->color == RBTBLACK) |
| { |
| /* |
| * 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) |
| { |
| RBTNode *w = x->parent->right; |
| |
| if (w->color == RBTRED) |
| { |
| w->color = RBTBLACK; |
| x->parent->color = RBTRED; |
| |
| rbt_rotate_left(rbt, x->parent); |
| w = x->parent->right; |
| } |
| |
| if (w->left->color == RBTBLACK && w->right->color == RBTBLACK) |
| { |
| w->color = RBTRED; |
| |
| x = x->parent; |
| } |
| else |
| { |
| if (w->right->color == RBTBLACK) |
| { |
| w->left->color = RBTBLACK; |
| w->color = RBTRED; |
| |
| rbt_rotate_right(rbt, w); |
| w = x->parent->right; |
| } |
| w->color = x->parent->color; |
| x->parent->color = RBTBLACK; |
| w->right->color = RBTBLACK; |
| |
| rbt_rotate_left(rbt, x->parent); |
| x = rbt->root; /* Arrange for loop to terminate. */ |
| } |
| } |
| else |
| { |
| RBTNode *w = x->parent->left; |
| |
| if (w->color == RBTRED) |
| { |
| w->color = RBTBLACK; |
| x->parent->color = RBTRED; |
| |
| rbt_rotate_right(rbt, x->parent); |
| w = x->parent->left; |
| } |
| |
| if (w->right->color == RBTBLACK && w->left->color == RBTBLACK) |
| { |
| w->color = RBTRED; |
| |
| x = x->parent; |
| } |
| else |
| { |
| if (w->left->color == RBTBLACK) |
| { |
| w->right->color = RBTBLACK; |
| w->color = RBTRED; |
| |
| rbt_rotate_left(rbt, w); |
| w = x->parent->left; |
| } |
| w->color = x->parent->color; |
| x->parent->color = RBTBLACK; |
| w->left->color = RBTBLACK; |
| |
| rbt_rotate_right(rbt, x->parent); |
| x = rbt->root; /* Arrange for loop to terminate. */ |
| } |
| } |
| } |
| x->color = RBTBLACK; |
| } |
| |
| /* |
| * Delete node z from tree. |
| */ |
| static void |
| rbt_delete_node(RBTree *rbt, RBTNode *z) |
| { |
| RBTNode *x, |
| *y; |
| |
| /* This is just paranoia: we should only get called on a valid node */ |
| if (!z || z == RBTNIL) |
| 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 == RBTNIL || z->right == RBTNIL) |
| { |
| /* y has a RBTNIL node as a child */ |
| y = z; |
| } |
| else |
| { |
| /* find tree successor */ |
| y = z->right; |
| while (y->left != RBTNIL) |
| y = y->left; |
| } |
| |
| /* x is y's only child */ |
| if (y->left != RBTNIL) |
| 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 |
| { |
| rbt->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) |
| rbt_copy_data(rbt, 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 == RBTBLACK) |
| rbt_delete_fixup(rbt, x); |
| |
| /* Now we can recycle the y node */ |
| if (rbt->freefunc) |
| rbt->freefunc(y, rbt->arg); |
| } |
| |
| /* |
| * rbt_delete: remove the given tree entry |
| * |
| * "node" must have previously been found via rbt_find or rbt_leftmost. |
| * It is caller's responsibility to free any subsidiary data attached |
| * to the node before calling rbt_delete. (Do *not* try to push that |
| * responsibility off to the freefunc, as some other physical node |
| * may be the one actually freed!) |
| */ |
| void |
| rbt_delete(RBTree *rbt, RBTNode *node) |
| { |
| rbt_delete_node(rbt, node); |
| } |
| |
| /********************************************************************** |
| * Traverse * |
| **********************************************************************/ |
| |
| static RBTNode * |
| rbt_left_right_iterator(RBTreeIterator *iter) |
| { |
| if (iter->last_visited == NULL) |
| { |
| iter->last_visited = iter->rbt->root; |
| while (iter->last_visited->left != RBTNIL) |
| iter->last_visited = iter->last_visited->left; |
| |
| return iter->last_visited; |
| } |
| |
| if (iter->last_visited->right != RBTNIL) |
| { |
| iter->last_visited = iter->last_visited->right; |
| while (iter->last_visited->left != RBTNIL) |
| iter->last_visited = iter->last_visited->left; |
| |
| return iter->last_visited; |
| } |
| |
| for (;;) |
| { |
| RBTNode *came_from = iter->last_visited; |
| |
| iter->last_visited = iter->last_visited->parent; |
| if (iter->last_visited == NULL) |
| { |
| iter->is_over = true; |
| break; |
| } |
| |
| if (iter->last_visited->left == came_from) |
| break; /* came from left sub-tree, return current |
| * node */ |
| |
| /* else - came from right sub-tree, continue to move up */ |
| } |
| |
| return iter->last_visited; |
| } |
| |
| static RBTNode * |
| rbt_right_left_iterator(RBTreeIterator *iter) |
| { |
| if (iter->last_visited == NULL) |
| { |
| iter->last_visited = iter->rbt->root; |
| while (iter->last_visited->right != RBTNIL) |
| iter->last_visited = iter->last_visited->right; |
| |
| return iter->last_visited; |
| } |
| |
| if (iter->last_visited->left != RBTNIL) |
| { |
| iter->last_visited = iter->last_visited->left; |
| while (iter->last_visited->right != RBTNIL) |
| iter->last_visited = iter->last_visited->right; |
| |
| return iter->last_visited; |
| } |
| |
| for (;;) |
| { |
| RBTNode *came_from = iter->last_visited; |
| |
| iter->last_visited = iter->last_visited->parent; |
| if (iter->last_visited == NULL) |
| { |
| iter->is_over = true; |
| break; |
| } |
| |
| if (iter->last_visited->right == came_from) |
| break; /* came from right sub-tree, return current |
| * node */ |
| |
| /* else - came from left sub-tree, continue to move up */ |
| } |
| |
| return iter->last_visited; |
| } |
| |
| /* |
| * rbt_begin_iterate: prepare to traverse the tree in any of several orders |
| * |
| * After calling rbt_begin_iterate, call rbt_iterate repeatedly until it |
| * returns NULL or the traversal stops being of interest. |
| * |
| * If the tree is changed during traversal, results of further calls to |
| * rbt_iterate are unspecified. Multiple concurrent iterators on the same |
| * tree are allowed. |
| * |
| * The iterator state is stored in the 'iter' struct. The caller should |
| * treat it as an opaque struct. |
| */ |
| void |
| rbt_begin_iterate(RBTree *rbt, RBTOrderControl ctrl, RBTreeIterator *iter) |
| { |
| /* Common initialization for all traversal orders */ |
| iter->rbt = rbt; |
| iter->last_visited = NULL; |
| iter->is_over = (rbt->root == RBTNIL); |
| |
| switch (ctrl) |
| { |
| case LeftRightWalk: /* visit left, then self, then right */ |
| iter->iterate = rbt_left_right_iterator; |
| break; |
| case RightLeftWalk: /* visit right, then self, then left */ |
| iter->iterate = rbt_right_left_iterator; |
| break; |
| default: |
| elog(ERROR, "unrecognized rbtree iteration order: %d", ctrl); |
| } |
| } |
| |
| /* |
| * rbt_iterate: return the next node in traversal order, or NULL if no more |
| */ |
| RBTNode * |
| rbt_iterate(RBTreeIterator *iter) |
| { |
| if (iter->is_over) |
| return NULL; |
| |
| return iter->iterate(iter); |
| } |