From: Michel Lespinasse <walken@google.com>
To: riel@redhat.com, peterz@infradead.org, daniel.santos@pobox.com,
aarcange@redhat.com, dwmw2@infradead.org,
akpm@linux-foundation.org
Cc: linux-mm@kvack.org, linux-kernel@vger.kernel.org
Subject: [PATCH 1/6] rbtree: rb_erase updates and comments
Date: Fri, 20 Jul 2012 05:31:02 -0700 [thread overview]
Message-ID: <1342787467-5493-2-git-send-email-walken@google.com> (raw)
In-Reply-To: <1342787467-5493-1-git-send-email-walken@google.com>
Minor updates to the rb_erase() function:
- Reorder code to put simplest / common case (no more than 1 child) first.
- Fetch the parent first, since it ends up being required in all 3 cases.
- Add a few comments to illustrate case 2 (node to remove has 2 childs,
but one of them is the successor) and case 3 (node to remove has 2 childs,
successor is a left-descendant of the right child).
Signed-off-by: Michel Lespinasse <walken@google.com>
---
lib/rbtree.c | 115 ++++++++++++++++++++++++++++++++++++----------------------
1 files changed, 72 insertions(+), 43 deletions(-)
diff --git a/lib/rbtree.c b/lib/rbtree.c
index 0892670..3b6ec98 100644
--- a/lib/rbtree.c
+++ b/lib/rbtree.c
@@ -2,7 +2,8 @@
Red Black Trees
(C) 1999 Andrea Arcangeli <andrea@suse.de>
(C) 2002 David Woodhouse <dwmw2@infradead.org>
-
+ (C) 2012 Michel Lespinasse <walken@google.com>
+
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
the Free Software Foundation; either version 2 of the License, or
@@ -356,65 +357,93 @@ static void __rb_erase_color(struct rb_node *node, struct rb_node *parent,
void rb_erase(struct rb_node *node, struct rb_root *root)
{
- struct rb_node *child, *parent;
- int color;
+ struct rb_node *parent = rb_parent(node);
+ struct rb_node *child = node->rb_right;
+ struct rb_node *tmp = node->rb_left;
+ bool black;
+
+ if (!tmp) {
+ /* Case 1: node to erase has no more than 1 child (easy!) */
+ if (child)
+one_child:
+ rb_set_parent(child, parent);
+ if (parent) {
+ if (parent->rb_left == node)
+ parent->rb_left = child;
+ else
+ parent->rb_right = child;
+ } else
+ root->rb_node = child;
- if (!node->rb_left)
- child = node->rb_right;
- else if (!node->rb_right)
- child = node->rb_left;
- else {
- struct rb_node *old = node, *left;
+ black = rb_is_black(node);
+ } else if (!child) {
+ /* Still case 1, but this time the child is node->rb_left */
+ child = tmp;
+ goto one_child;
+ } else {
+ struct rb_node *old = node;
+ /*
+ * Old is the node we want to erase. It's got left and right
+ * children, which makes things difficult. Let's find the
+ * next node in the tree to have it fill old's position.
+ */
node = node->rb_right;
- while ((left = node->rb_left) != NULL)
- node = left;
+ while ((tmp = node->rb_left) != NULL)
+ node = tmp;
- if (rb_parent(old)) {
- if (rb_parent(old)->rb_left == old)
- rb_parent(old)->rb_left = node;
+ /* Graft node (old's successor) under old's parent. */
+ if (parent) {
+ if (parent->rb_left == old)
+ parent->rb_left = node;
else
- rb_parent(old)->rb_right = node;
+ parent->rb_right = node;
} else
root->rb_node = node;
- child = node->rb_right;
parent = rb_parent(node);
- color = rb_color(node);
+ black = rb_is_black(node);
+ node->__rb_parent_color = old->__rb_parent_color;
+
+ /*
+ * Node doesn't have a left child, since it is old's successor,
+ * so we can take old's left child and graft it under node.
+ */
+ node->rb_left = tmp = old->rb_left;
+ rb_set_parent(tmp, node);
+ child = node->rb_right;
if (parent == old) {
+ /*
+ * Case 2: old is node's parent (we are done!)
+ *
+ * (o) (n)
+ * / \ / \
+ * (x) (n) -> (x) (c)
+ * \
+ * (c)
+ */
parent = node;
} else {
+ /*
+ * Case 3: old is node's ancestor but not its parent
+ *
+ * (o) (n)
+ * / \ / \
+ * (x) (y) -> (x) (y)
+ * / /
+ * (n) (c)
+ * \
+ * (c)
+ */
+ node->rb_right = tmp = old->rb_right;
+ parent->rb_left = child;
+ rb_set_parent(tmp, node);
if (child)
rb_set_parent(child, parent);
- parent->rb_left = child;
-
- node->rb_right = old->rb_right;
- rb_set_parent(old->rb_right, node);
}
-
- node->__rb_parent_color = old->__rb_parent_color;
- node->rb_left = old->rb_left;
- rb_set_parent(old->rb_left, node);
-
- goto color;
}
-
- parent = rb_parent(node);
- color = rb_color(node);
-
- if (child)
- rb_set_parent(child, parent);
- if (parent) {
- if (parent->rb_left == node)
- parent->rb_left = child;
- else
- parent->rb_right = child;
- } else
- root->rb_node = child;
-
-color:
- if (color == RB_BLACK)
+ if (black)
__rb_erase_color(child, parent, root);
}
EXPORT_SYMBOL(rb_erase);
--
1.7.7.3
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
next prev parent reply other threads:[~2012-07-20 12:31 UTC|newest]
Thread overview: 28+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-07-20 12:31 [RFC PATCH 0/6] augmented rbtree changes Michel Lespinasse
2012-07-20 12:31 ` Michel Lespinasse [this message]
2012-07-24 18:50 ` [PATCH 1/6] rbtree: rb_erase updates and comments Rik van Riel
2012-07-20 12:31 ` [PATCH 2/6] rbtree: optimize fetching of sibling node Michel Lespinasse
2012-07-24 21:52 ` Rik van Riel
2012-07-20 12:31 ` [PATCH 3/6] augmented rbtree test Michel Lespinasse
2012-07-25 15:42 ` Rik van Riel
2012-07-20 12:31 ` [PATCH 4/6] rbtree: faster augmented insert Michel Lespinasse
2012-07-25 16:10 ` Rik van Riel
2012-07-25 17:54 ` Rik van Riel
2012-07-27 19:26 ` Peter Zijlstra
2012-07-27 21:43 ` Michel Lespinasse
2012-07-27 19:31 ` Peter Zijlstra
2012-07-27 20:04 ` Peter Zijlstra
2012-07-27 21:55 ` Michel Lespinasse
2012-07-20 12:31 ` [PATCH 5/6] rbtree: faster augmented erase Michel Lespinasse
2012-07-24 1:54 ` Michel Lespinasse
2012-07-25 17:53 ` Rik van Riel
2012-07-27 19:43 ` Peter Zijlstra
2012-07-27 20:02 ` Peter Zijlstra
2012-07-28 0:44 ` Michel Lespinasse
2012-07-28 2:31 ` Michel Lespinasse
2012-07-20 12:31 ` [PATCH 6/6] rbtree: remove prior augmented rbtree implementation Michel Lespinasse
2012-07-24 1:55 ` Michel Lespinasse
2012-07-25 17:59 ` Rik van Riel
2012-07-24 1:46 ` [RFC PATCH 0/6] augmented rbtree changes Michel Lespinasse
[not found] <20120729040432.25753.qmail@science.horizon.com>
2012-07-29 12:36 ` [PATCH 1/6] rbtree: rb_erase updates and comments Michel Lespinasse
2012-07-29 20:27 ` George Spelvin
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1342787467-5493-2-git-send-email-walken@google.com \
--to=walken@google.com \
--cc=aarcange@redhat.com \
--cc=akpm@linux-foundation.org \
--cc=daniel.santos@pobox.com \
--cc=dwmw2@infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=peterz@infradead.org \
--cc=riel@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).