summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2002-09-09 13:31:53 +0100
committerDavid Woodhouse <dwmw2@infradead.org>2002-09-09 13:31:53 +0100
commit713fd67f97dee40399d64fdc3ce5069281185bd3 (patch)
tree3f35970962b176edb839cec042a33fcfa92912ee /lib
parentc9581bb63607e96645f0066865464a80413a1248 (diff)
Add three functions for rbtree manipulation -- rb_next(), rb_prev() and rb_replace_node()
rb_next() and rb_prev() return the next and previous nodes in the tree, respectively. rb_replace_node() allows fast replacement of a single node without having to remove the victim, rebalance the tree, insert the replacement and then rebalance again to the original topology.
Diffstat (limited to 'lib')
-rw-r--r--lib/rbtree.c68
1 files changed, 68 insertions, 0 deletions
diff --git a/lib/rbtree.c b/lib/rbtree.c
index bed359bd4a92..97e8bb448afb 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -1,6 +1,7 @@
/*
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de>
+ (C) 2002 David Woodhouse <dwmw2@infradead.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -294,3 +295,70 @@ void rb_erase(rb_node_t * node, rb_root_t * root)
__rb_erase_color(child, parent, root);
}
EXPORT_SYMBOL(rb_erase);
+
+rb_node_t *rb_next(rb_node_t *node)
+{
+ /* If we have a right-hand child, go down and then left as far
+ as we can. */
+ if (node->rb_right) {
+ node = node->rb_right;
+ while (node->rb_left)
+ node=node->rb_left;
+ return node;
+ }
+
+ /* No right-hand children. Everything down and left is
+ smaller than us, so any 'next' node must be in the general
+ direction of our parent. Go up the tree; any time the
+ ancestor is a right-hand child of its parent, keep going
+ up. First time it's a left-hand child of its parent, said
+ parent is our 'next' node. */
+ while (node->rb_parent && node == node->rb_parent->rb_right)
+ node = node->rb_parent;
+
+ return node->rb_parent;
+}
+EXPORT_SYMBOL(rb_next);
+
+rb_node_t *rb_prev(rb_node_t *node)
+{
+ /* If we have a left-hand child, go down and then right as far
+ as we can. */
+ if (node->rb_left) {
+ node = node->rb_left;
+ while (node->rb_right)
+ node=node->rb_right;
+ return node;
+ }
+
+ /* No left-hand children. Go up till we find an ancestor which
+ is a right-hand child of its parent */
+ while (node->rb_parent && node == node->rb_parent->rb_left)
+ node = node->rb_parent;
+
+ return node->rb_parent;
+}
+EXPORT_SYMBOL(rb_prev);
+
+void rb_replace_node(rb_node_t *victim, rb_node_t *new, rb_root_t *root)
+{
+ rb_node_t *parent = victim->rb_parent;
+
+ /* Set the surrounding nodes to point to the replacement */
+ if (parent) {
+ if (victim == parent->rb_left)
+ parent->rb_left = new;
+ else
+ parent->rb_right = new;
+ } else {
+ root->rb_node = new;
+ }
+ if (victim->rb_left)
+ victim->rb_left->rb_parent = new;
+ if (victim->rb_right)
+ victim->rb_right->rb_parent = new;
+
+ /* Copy the pointers/colour from the victim to the replacement */
+ *new = *victim;
+}
+EXPORT_SYMBOL(rb_replace_node);