[svn-commits] rmudgett: branch rmudgett/ao2_red_black r371648 - /team/rmudgett/ao2_red_blac...

SVN commits to the Digium repositories svn-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 svn-commits mailing list