[asterisk-commits] rmudgett: branch rmudgett/ao2_red_black r371648 - /team/rmudgett/ao2_red_blac...
SVN commits to the Asterisk project
asterisk-commits at lists.digium.com
Thu Aug 23 22:01:03 CDT 2012
Author: rmudgett
Date: Thu Aug 23 22:01:00 2012
New Revision: 371648
URL: http://svnview.digium.com/svn/asterisk?view=rev&rev=371648
Log:
Fixup rbtree after node insertion.
Modified:
team/rmudgett/ao2_red_black/main/astobj2.c
Modified: team/rmudgett/ao2_red_black/main/astobj2.c
URL: http://svnview.digium.com/svn/asterisk/team/rmudgett/ao2_red_black/main/astobj2.c?view=diff&rev=371648&r1=371647&r2=371648
==============================================================================
--- team/rmudgett/ao2_red_black/main/astobj2.c (original)
+++ team/rmudgett/ao2_red_black/main/astobj2.c Thu Aug 23 22:01:00 2012
@@ -3027,16 +3027,16 @@
*
* 1) Every node is either black or red.
*
- * 2) If a node has a NULL child, that "child" is considered
+ * 2) The root is black.
+ *
+ * 3) If a node has a NULL child, that "child" is considered
* black.
*
- * 3) If a node is red, then both of its children are black.
- *
- * 4) Every simple path from a node to a descendant NULL child
- * has the same number of black nodes. (Including the black
- * NULL child.)
- *
- * 5) The root is black.
+ * 4) If a node is red, then both of its children are black.
+ *
+ * 5) Every path from a node to a descendant NULL child has the
+ * same number of black nodes. (Including the black NULL
+ * child.)
*/
struct rbtree_node {
/*!
@@ -3374,6 +3374,106 @@
/*!
* \internal
+ * \brief Tree node rotation left.
+ * \since 12.0.0
+ *
+ * \param self Container holding node.
+ * \param node Node to perform a left rotation with.
+ *
+ * p p
+ * | Left rotation |
+ * N ---> Ch
+ * / \ / \
+ * a Ch N c
+ * / \ / \
+ * b c a b
+ *
+ * \note It is assumed that the node's right child exists.
+ *
+ * \return Nothing
+ */
+static void rb_rotate_left(struct ao2_container_rbtree *self, struct rbtree_node *node)
+{
+ struct rbtree_node *child; /*!< Node's right child. */
+
+ child = node->right;
+
+ /* Link the node's parent to the child. */
+ if (!node->parent) {
+ /* Node is the root so we get a new root node. */
+ self->root = child;
+ } else if (node->parent->left == node) {
+ /* Node is a left child. */
+ node->parent->left = child;
+ } else {
+ /* Node is a right child. */
+ node->parent->right = child;
+ }
+ child->parent = node->parent;
+
+ /* Link node's right subtree to the child's left subtree. */
+ node->right = child->left;
+ if (node->right) {
+ node->right->parent = node;
+ }
+
+ /* Link the node to the child's left. */
+ node->parent = child;
+ child->left = node;
+}
+
+/*!
+ * \internal
+ * \brief Tree node rotation right.
+ * \since 12.0.0
+ *
+ * \param self Container holding node.
+ * \param node Node to perform a right rotation with.
+ *
+ * p p
+ * | Right rotation |
+ * Ch N
+ * / \ <--- / \
+ * a N Ch c
+ * / \ / \
+ * b c a b
+ *
+ * \note It is assumed that the node's left child exists.
+ *
+ * \return Nothing
+ */
+static void rb_rotate_right(struct ao2_container_rbtree *self, struct rbtree_node *node)
+{
+ struct rbtree_node *child; /*!< Node's left child. */
+
+ child = node->left;
+
+ /* Link the node's parent to the child. */
+ if (!node->parent) {
+ /* Node is the root so we get a new root node. */
+ self->root = child;
+ } else if (node->parent->right == node) {
+ /* Node is a right child. */
+ node->parent->right = child;
+ } else {
+ /* Node is a left child. */
+ node->parent->left = child;
+ }
+ child->parent = node->parent;
+
+ /* Link node's left subtree to the child's right subtree. */
+ node->left = child->right;
+ if (node->left) {
+ node->left->parent = node;
+ }
+
+ /* Link the node to the child's right. */
+ node->parent = child;
+ child->right = node;
+}
+
+/*!
+ * \internal
* \brief Create an empty copy of this container.
* \since 12.0.0
*
@@ -3523,17 +3623,87 @@
/*!
* \internal
- * \brief Fixup the rbtree after inserting a non-root node.
+ * \brief Fixup the rbtree after inserting a node.
* \since 12.0.0
*
* \param self Container to operate upon.
* \param node Container node just inserted into the container.
*
+ * \note The just inserted node is red.
+ *
* \return Nothing
*/
static void rb_insert_fixup(struct ao2_container_rbtree *self, struct rbtree_node *node)
{
- /*! \todo BUGBUG rb_insert_fixup() not written */
+ struct rbtree_node *g_parent; /* Grand parent node. */
+
+ while (node->parent && node->parent->is_red) {
+ g_parent = node->parent->parent;
+
+ /* The grand parent must exist if the parent is red. */
+ ast_assert(g_parent != NULL);
+
+ if (node->parent == g_parent->left) {
+ /* The parent is a left child. */
+ if (g_parent->right && g_parent->right->is_red) {
+ /* Case 1: Push the black down from the grand parent node. */
+ g_parent->right->is_red = 0;
+ g_parent->left->is_red = 0;
+ g_parent->is_red = 1;
+
+ node = g_parent;
+ } else {
+ /* The uncle node is black. */
+ if (node->parent->right == node) {
+ /*
+ * Case 2: The node is a right child.
+ *
+ * Which node is the grand parent does not change.
+ */
+ node = node->parent;
+ rb_rotate_left(self, node);
+ }
+ /* Case 3: The node is a left child. */
+ node->parent->is_red = 0;
+ g_parent->is_red = 1;
+ rb_rotate_right(self, g_parent);
+ }
+ } else {
+ /* The parent is a right child. */
+ if (g_parent->left && g_parent->left->is_red) {
+ /* Case 1: Push the black down from the grand parent node. */
+ g_parent->left->is_red = 0;
+ g_parent->right->is_red = 0;
+ g_parent->is_red = 1;
+
+ node = g_parent;
+ } else {
+ /* The uncle node is black. */
+ if (node->parent->left == node) {
+ /*
+ * Case 2: The node is a left child.
+ *
+ * Which node is the grand parent does not change.
+ */
+ node = node->parent;
+ rb_rotate_right(self, node);
+ }
+ /* Case 3: The node is a right child. */
+ node->parent->is_red = 0;
+ g_parent->is_red = 1;
+ rb_rotate_left(self, g_parent);
+ }
+ }
+ }
+
+ /*
+ * The root could be red here because:
+ * 1) We just inserted the root node in an empty tree.
+ *
+ * 2) Case 1 could leave the root red if the grand parent were
+ * the root.
+ */
+ self->root->is_red = 0;
}
/*!
More information about the asterisk-commits
mailing list