*/
#include "gtkrbtree.h"
+#include "gtkdebug.h"
+
+static void _gtk_rbnode_validate_allocator (GAllocator *allocator);
+static GtkRBNode * _gtk_rbnode_new (GtkRBTree *tree,
+ gint height);
+static void _gtk_rbnode_free (GtkRBNode *node);
+static void _gtk_rbnode_rotate_left (GtkRBTree *tree,
+ GtkRBNode *node);
+static void _gtk_rbnode_rotate_right (GtkRBTree *tree,
+ GtkRBNode *node);
+static void _gtk_rbtree_insert_fixup (GtkRBTree *tree,
+ GtkRBNode *node);
+static void _gtk_rbtree_remove_node_fixup (GtkRBTree *tree,
+ GtkRBNode *node);
+static gint _count_nodes (GtkRBTree *tree,
+ GtkRBNode *node);
+static inline void _fixup_validation (GtkRBTree *tree,
+ GtkRBNode *node);
+static inline void _fixup_parity (GtkRBTree *tree,
+ GtkRBNode *node);
-static void _gtk_rbnode_validate_allocator (GAllocator *allocator);
-static GtkRBNode *_gtk_rbnode_new (GtkRBTree *tree,
- gint height);
-static void _gtk_rbnode_free (GtkRBNode *node);
-static void _gtk_rbnode_rotate_left (GtkRBTree *tree,
- GtkRBNode *node);
-static void _gtk_rbnode_rotate_left (GtkRBTree *tree,
- GtkRBNode *node);
-static void _gtk_rbtree_insert_fixup (GtkRBTree *tree,
- GtkRBNode *node);
-static void _gtk_rbtree_remove_node_fixup (GtkRBTree *tree,
- GtkRBNode *node);
-static gint _count_nodes (GtkRBTree *tree,
- GtkRBNode *node);
/* node allocation
G_LOCK_DEFINE_STATIC (current_allocator);
static GAllocator *current_allocator = NULL;
+
/* HOLDS: current_allocator_lock */
static void
_gtk_rbnode_validate_allocator (GAllocator *allocator)
node->right = tree->nil;
node->parent = tree->nil;
node->flags = GTK_RBNODE_RED;
+ node->parity = 1;
node->count = 1;
node->children = NULL;
node->offset = height;
G_LOCK (current_allocator);
node->left = current_allocator->free_nodes;
current_allocator->free_nodes = node;
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ {
+ /* unfortunately node->left has to continue to point to
+ * a node...
+ */
+ node->right = (gpointer) 0xdeadbeef;
+ node->parent = (gpointer) 0xdeadbeef;
+ node->offset = 56789;
+ node->count = 56789;
+ node->flags = 0;
+ }
G_UNLOCK (current_allocator);
}
(right->left?right->left->offset:0) -
(right->right?right->right->offset:0) -
(right->children?right->children->root->offset:0);
-
node->right = right->left;
if (right->left != tree->nil)
right->left->parent = node;
(node->right?node->right->count:0);
right->count = 1 + (right->left?right->left->count:0) +
(right->right?right->right->count:0);
+
node->offset = node_height +
(node->left?node->left->offset:0) +
(node->right?node->right->offset:0) +
(right->left?right->left->offset:0) +
(right->right?right->right->offset:0) +
(right->children?right->children->root->offset:0);
+
+ _fixup_validation (tree, node);
+ _fixup_validation (tree, right);
+ _fixup_parity (tree, node);
+ _fixup_parity (tree, right);
}
static void
(left->left?left->left->offset:0) -
(left->right?left->right->offset:0) -
(left->children?left->children->root->offset:0);
-
+
node->left = left->right;
if (left->right != tree->nil)
left->right->parent = node;
(node->right?node->right->count:0);
left->count = 1 + (left->left?left->left->count:0) +
(left->right?left->right->count:0);
+
node->offset = node_height +
(node->left?node->left->offset:0) +
(node->right?node->right->offset:0) +
(left->left?left->left->offset:0) +
(left->right?left->right->offset:0) +
(left->children?left->children->root->offset:0);
+
+ _fixup_validation (tree, node);
+ _fixup_validation (tree, left);
+ _fixup_parity (tree, node);
+ _fixup_parity (tree, left);
}
static void
retval->nil->flags = GTK_RBNODE_BLACK;
retval->nil->count = 0;
retval->nil->offset = 0;
+ retval->nil->parity = 0;
retval->root = retval->nil;
return retval;
GtkRBNode *tmp_node;
gint height = tree->root->offset;
+
+#ifdef G_ENABLE_DEBUG
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ _gtk_rbtree_test (G_STRLOC, tree);
+#endif
+
tmp_tree = tree->parent_tree;
tmp_node = tree->parent_node;
+ /* ugly hack to make _fixup_validation work in the first iteration of the
+ * loop below */
+ GTK_RBNODE_UNSET_FLAG (tree->root, GTK_RBNODE_DESCENDANTS_INVALID);
+
while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
{
+ _fixup_validation (tmp_tree, tmp_node);
tmp_node->offset -= height;
+
+ /* If the removed tree was odd, flip all parents */
+ if (tree->root->parity)
+ tmp_node->parity = !tmp_node->parity;
+
tmp_node = tmp_node->parent;
if (tmp_node == tmp_tree->nil)
{
tmp_tree = tmp_tree->parent_tree;
}
}
+
+ tmp_tree = tree->parent_tree;
+ tmp_node = tree->parent_node;
_gtk_rbtree_free (tree);
+
+#ifdef G_ENABLE_DEBUG
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ _gtk_rbtree_test (G_STRLOC, tmp_tree);
+#endif
}
GtkRBNode *
-_gtk_rbtree_insert_after (GtkRBTree *tree,
- GtkRBNode *current,
- gint height)
+_gtk_rbtree_insert_after (GtkRBTree *tree,
+ GtkRBNode *current,
+ gint height,
+ gboolean valid)
{
GtkRBNode *node;
gboolean right = TRUE;
GtkRBNode *tmp_node;
- GtkRBTree *tmp_tree;
+ GtkRBTree *tmp_tree;
+
+#ifdef G_ENABLE_DEBUG
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ {
+ g_print ("\n\n_gtk_rbtree_insert_after: %p\n", current);
+ _gtk_rbtree_debug_spew (tree);
+ _gtk_rbtree_test (G_STRLOC, tree);
+ }
+#endif /* G_ENABLE_DEBUG */
if (current != NULL && current->right != tree->nil)
{
current = current->left;
right = FALSE;
}
-
/* setup new node */
node = _gtk_rbnode_new (tree, height);
node->parent = (current?current:tree->nil);
* started in. */
if (tmp_tree == tree)
tmp_node->count++;
+
+ tmp_node->parity += 1;
tmp_node->offset += height;
tmp_node = tmp_node->parent;
if (tmp_node == tmp_tree->nil)
tmp_tree = tmp_tree->parent_tree;
}
}
+
+ if (valid)
+ _gtk_rbtree_node_mark_valid (tree, node);
+ else
+ _gtk_rbtree_node_mark_invalid (tree, node);
+
_gtk_rbtree_insert_fixup (tree, node);
+#ifdef G_ENABLE_DEBUG
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ {
+ g_print ("_gtk_rbtree_insert_after finished...\n");
+ _gtk_rbtree_debug_spew (tree);
+ g_print ("\n\n");
+ _gtk_rbtree_test (G_STRLOC, tree);
+ }
+#endif /* G_ENABLE_DEBUG */
+
return node;
}
GtkRBNode *
-_gtk_rbtree_insert_before (GtkRBTree *tree,
- GtkRBNode *current,
- gint height)
+_gtk_rbtree_insert_before (GtkRBTree *tree,
+ GtkRBNode *current,
+ gint height,
+ gboolean valid)
{
GtkRBNode *node;
gboolean left = TRUE;
GtkRBNode *tmp_node;
GtkRBTree *tmp_tree;
+#ifdef G_ENABLE_DEBUG
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ {
+ g_print ("\n\n_gtk_rbtree_insert_before: %p\n", current);
+ _gtk_rbtree_debug_spew (tree);
+ _gtk_rbtree_test (G_STRLOC, tree);
+ }
+#endif /* G_ENABLE_DEBUG */
+
if (current != NULL && current->left != tree->nil)
{
current = current->left;
* started in. */
if (tmp_tree == tree)
tmp_node->count++;
+
+ tmp_node->parity += 1;
tmp_node->offset += height;
tmp_node = tmp_node->parent;
if (tmp_node == tmp_tree->nil)
tmp_tree = tmp_tree->parent_tree;
}
}
+
+ if (valid)
+ _gtk_rbtree_node_mark_valid (tree, node);
+ else
+ _gtk_rbtree_node_mark_invalid (tree, node);
+
_gtk_rbtree_insert_fixup (tree, node);
+#ifdef G_ENABLE_DEBUG
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ {
+ g_print ("_gtk_rbtree_insert_before finished...\n");
+ _gtk_rbtree_debug_spew (tree);
+ g_print ("\n\n");
+ _gtk_rbtree_test (G_STRLOC, tree);
+ }
+#endif /* G_ENABLE_DEBUG */
+
return node;
}
tmp_tree = tmp_tree->parent_tree;
}
}
+#ifdef G_ENABLE_DEBUG
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ _gtk_rbtree_test (G_STRLOC, tree);
+#endif
}
+void
+_gtk_rbtree_node_mark_invalid (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID))
+ return;
+
+ GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_INVALID);
+ do
+ {
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID))
+ return;
+ GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+ node = node->parent;
+ if (node == tree->nil)
+ {
+ node = tree->parent_node;
+ tree = tree->parent_tree;
+ }
+ }
+ while (node);
+}
+
+#if 0
+/* Draconian version. */
+void
+_gtk_rbtree_node_mark_invalid (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_INVALID);
+ do
+ {
+ _fixup_validation (tree, node);
+ node = node->parent;
+ if (node == tree->nil)
+ {
+ node = tree->parent_node;
+ tree = tree->parent_tree;
+ }
+ }
+ while (node);
+}
+#endif
+
+void
+_gtk_rbtree_node_mark_valid (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ if ((!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)) &&
+ (!GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID)))
+ return;
+
+ GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_INVALID);
+ GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_COLUMN_INVALID);
+
+ do
+ {
+ if ((GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)) ||
+ (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID)) ||
+ (node->children && GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+ (node->left != tree->nil && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+ (node->right != tree->nil && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID)))
+ return;
+
+ GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+ node = node->parent;
+ if (node == tree->nil)
+ {
+ node = tree->parent_node;
+ tree = tree->parent_tree;
+ }
+ }
+ while (node);
+}
+
+#if 0
+/* Draconian version */
+void
+_gtk_rbtree_node_mark_valid (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_INVALID);
+ GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_COLUMN_INVALID);
+
+ do
+ {
+ _fixup_validation (tree, node);
+ node = node->parent;
+ if (node == tree->nil)
+ {
+ node = tree->parent_node;
+ tree = tree->parent_tree;
+ }
+ }
+ while (node);
+}
+#endif
+/* Assume tree is the root node as it doesn't set DESCENDANTS_INVALID above.
+ */
+void
+_gtk_rbtree_column_invalid (GtkRBTree *tree)
+{
+ GtkRBNode *node;
+
+ if (tree == NULL)
+ return;
+ node = tree->root;
+ g_assert (node);
+
+ while (node->left != tree->nil)
+ node = node->left;
+
+ do
+ {
+ if (! (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID)))
+ GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_COLUMN_INVALID);
+ GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+
+ if (node->children)
+ _gtk_rbtree_column_invalid (node->children);
+ }
+ while ((node = _gtk_rbtree_next (tree, node)) != NULL);
+}
+
+void
+_gtk_rbtree_mark_invalid (GtkRBTree *tree)
+{
+ GtkRBNode *node;
+
+ if (tree == NULL)
+ return;
+ node = tree->root;
+ g_assert (node);
+
+ while (node->left != tree->nil)
+ node = node->left;
+
+ do
+ {
+ GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_INVALID);
+ GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+
+ if (node->children)
+ _gtk_rbtree_mark_invalid (node->children);
+ }
+ while ((node = _gtk_rbtree_next (tree, node)) != NULL);
+}
+
+void
+_gtk_rbtree_set_fixed_height (GtkRBTree *tree,
+ gint height)
+{
+ GtkRBNode *node;
+
+ if (tree == NULL)
+ return;
+
+ node = tree->root;
+ g_assert (node);
+
+ while (node->left != tree->nil)
+ node = node->left;
+
+ do
+ {
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID))
+ _gtk_rbtree_node_set_height (tree, node, height);
+
+ if (node->children)
+ _gtk_rbtree_set_fixed_height (node->children, height);
+ }
+ while ((node = _gtk_rbtree_next (tree, node)) != NULL);
+}
+
+typedef struct _GtkRBReorder
+{
+ GtkRBTree *children;
+ gint height;
+ gint flags;
+ gint order;
+ gint invert_order;
+ gint parity;
+} GtkRBReorder;
+
+static int
+gtk_rbtree_reorder_sort_func (gconstpointer a,
+ gconstpointer b)
+{
+ return ((GtkRBReorder *) a)->order > ((GtkRBReorder *) b)->order;
+}
+
+static int
+gtk_rbtree_reorder_invert_func (gconstpointer a,
+ gconstpointer b)
+{
+ return ((GtkRBReorder *) a)->invert_order > ((GtkRBReorder *) b)->invert_order;
+}
+
+static void
+gtk_rbtree_reorder_fixup (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ if (node == tree->nil)
+ return;
+
+ node->parity = 1;
+
+ if (node->left != tree->nil)
+ {
+ gtk_rbtree_reorder_fixup (tree, node->left);
+ node->offset += node->left->offset;
+ node->parity += node->left->parity;
+ }
+ if (node->right != tree->nil)
+ {
+ gtk_rbtree_reorder_fixup (tree, node->right);
+ node->offset += node->right->offset;
+ node->parity += node->right->parity;
+ }
+
+ if (node->children)
+ {
+ node->offset += node->children->root->offset;
+ node->parity += node->children->root->parity;
+ }
+
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+ (node->right != tree->nil && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+ (node->left != tree->nil && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+ (node->children && GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID)))
+ GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+ else
+ GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+}
+
+/* It basically pulls everything out of the tree, rearranges it, and puts it
+ * back together. Our strategy is to keep the old RBTree intact, and just
+ * rearrange the contents. When that is done, we go through and update the
+ * heights. There is probably a more elegant way to write this function. If
+ * anyone wants to spend the time writing it, patches will be accepted.
+ */
+void
+_gtk_rbtree_reorder (GtkRBTree *tree,
+ gint *new_order,
+ gint length)
+{
+ GtkRBReorder reorder;
+ GArray *array;
+ GtkRBNode *node;
+ gint i;
+
+ g_return_if_fail (tree != NULL);
+ g_return_if_fail (length > 0);
+ g_return_if_fail (tree->root->count == length);
+
+ /* Sort the trees values in the new tree. */
+ array = g_array_sized_new (FALSE, FALSE, sizeof (GtkRBReorder), length);
+ for (i = 0; i < length; i++)
+ {
+ reorder.order = new_order[i];
+ reorder.invert_order = i;
+ g_array_append_val (array, reorder);
+ }
+
+ g_array_sort(array, gtk_rbtree_reorder_sort_func);
+
+ /* rewind node*/
+ node = tree->root;
+ while (node && node->left != tree->nil)
+ node = node->left;
+
+ for (i = 0; i < length; i++)
+ {
+ g_assert (node != tree->nil);
+ g_array_index (array, GtkRBReorder, i).children = node->children;
+ g_array_index (array, GtkRBReorder, i).flags = GTK_RBNODE_NON_COLORS & node->flags;
+ g_array_index (array, GtkRBReorder, i).height = GTK_RBNODE_GET_HEIGHT (node);
+
+ node = _gtk_rbtree_next (tree, node);
+ }
+
+ g_array_sort (array, gtk_rbtree_reorder_invert_func);
+
+ /* rewind node*/
+ node = tree->root;
+ while (node && node->left != tree->nil)
+ node = node->left;
+
+ /* Go through the tree and change the values to the new ones. */
+ for (i = 0; i < length; i++)
+ {
+ reorder = g_array_index (array, GtkRBReorder, i);
+ node->children = reorder.children;
+ if (node->children)
+ node->children->parent_node = node;
+ node->flags = GTK_RBNODE_GET_COLOR (node) | reorder.flags;
+ /* We temporarily set the height to this. */
+ node->offset = reorder.height;
+ node = _gtk_rbtree_next (tree, node);
+ }
+ gtk_rbtree_reorder_fixup (tree, tree->root);
+
+ g_array_free (array, TRUE);
+}
+
+
gint
_gtk_rbtree_node_find_offset (GtkRBTree *tree,
GtkRBNode *node)
{
GtkRBNode *last;
- gint retval = node->left->offset;
+ gint retval;
+
+ g_assert (node);
+ g_assert (node->left);
+
+ retval = node->left->offset;
while (tree && node && node != tree->nil)
{
last = node;
node = node->parent;
+
+ /* Add left branch, plus children, iff we came from the right */
if (node->right == last)
- retval += node->left->offset + GTK_RBNODE_GET_HEIGHT (node);
+ retval += node->offset - node->right->offset;
+
if (node == tree->nil)
{
node = tree->parent_node;
tree = tree->parent_tree;
+
+ /* Add the parent node, plus the left branch. */
if (node)
- retval += node->left->offset;
+ retval += node->left->offset + GTK_RBNODE_GET_HEIGHT (node);
}
}
return retval;
}
gint
-_gtk_rbtree_find_offset (GtkRBTree *tree,
- gint height,
- GtkRBTree **new_tree,
- GtkRBNode **new_node)
+_gtk_rbtree_node_find_parity (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ GtkRBNode *last;
+ gint retval;
+
+ g_assert (node);
+ g_assert (node->left);
+
+ retval = node->left->parity;
+
+ while (tree && node && node != tree->nil)
+ {
+ last = node;
+ node = node->parent;
+
+ /* Add left branch, plus children, iff we came from the right */
+ if (node->right == last)
+ retval += node->parity - node->right->parity;
+
+ if (node == tree->nil)
+ {
+ node = tree->parent_node;
+ tree = tree->parent_tree;
+
+ /* Add the parent node, plus the left branch. */
+ if (node)
+ retval += node->left->parity + 1; /* 1 == GTK_RBNODE_GET_PARITY() */
+ }
+ }
+
+ return retval % 2;
+}
+
+gint
+_gtk_rbtree_real_find_offset (GtkRBTree *tree,
+ gint height,
+ GtkRBTree **new_tree,
+ GtkRBNode **new_node)
{
GtkRBNode *tmp_node;
+ g_assert (tree);
+
if (height < 0)
{
*new_tree = NULL;
*new_node = NULL;
+
return 0;
}
+
tmp_node = tree->root;
while (tmp_node != tree->nil &&
*new_node = tmp_node;
return (height - tmp_node->left->offset);
}
- return _gtk_rbtree_find_offset (tmp_node->children,
- height - tmp_node->left->offset -
- (tmp_node->offset -
- tmp_node->left->offset -
- tmp_node->right->offset -
- tmp_node->children->root->offset),
- new_tree,
- new_node);
+ return _gtk_rbtree_real_find_offset (tmp_node->children,
+ height - tmp_node->left->offset -
+ (tmp_node->offset -
+ tmp_node->left->offset -
+ tmp_node->right->offset -
+ tmp_node->children->root->offset),
+ new_tree,
+ new_node);
}
*new_tree = tree;
*new_node = tmp_node;
return (height - tmp_node->left->offset);
}
+gint
+_gtk_rbtree_find_offset (GtkRBTree *tree,
+ gint height,
+ GtkRBTree **new_tree,
+ GtkRBNode **new_node)
+{
+ g_assert (tree);
+
+ if ((height < 0) ||
+ (height >= tree->root->offset))
+ {
+ *new_tree = NULL;
+ *new_node = NULL;
+
+ return 0;
+ }
+ return _gtk_rbtree_real_find_offset (tree, height, new_tree, new_node);
+}
void
_gtk_rbtree_remove_node (GtkRBTree *tree,
GtkRBNode *node)
{
GtkRBNode *x, *y;
-
+ GtkRBTree *tmp_tree;
+ GtkRBNode *tmp_node;
+ gint node_height;
+ gint y_height;
+
g_return_if_fail (tree != NULL);
g_return_if_fail (node != NULL);
+
+
+#ifdef G_ENABLE_DEBUG
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ {
+ g_print ("\n\n_gtk_rbtree_remove_node: %p\n", node);
+ _gtk_rbtree_debug_spew (tree);
+ _gtk_rbtree_test (G_STRLOC, tree);
+ }
+#endif /* G_ENABLE_DEBUG */
+
/* make sure we're deleting a node that's actually in the tree */
for (x = node; x->parent != tree->nil; x = x->parent)
;
g_return_if_fail (x == tree->root);
+#ifdef G_ENABLE_DEBUG
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ _gtk_rbtree_test (G_STRLOC, tree);
+#endif
+
if (node->left == tree->nil || node->right == tree->nil)
{
y = node;
while (y->left != tree->nil)
y = y->left;
}
+
+ /* adjust count only beneath tree */
for (x = y; x != tree->nil; x = x->parent)
- x->count--;
- y->count = node->count;
- /* x is y's only child */
+ {
+ x->count--;
+ }
+
+ /* offsets and parity adjust all the way up through parent trees */
+ y_height = GTK_RBNODE_GET_HEIGHT (y);
+ node_height = GTK_RBNODE_GET_HEIGHT (node) + (node->children?node->children->root->offset:0);
+
+ tmp_tree = tree;
+ tmp_node = y;
+ while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
+ {
+ tmp_node->offset -= (y_height + (y->children?y->children->root->offset:0));
+ _fixup_validation (tmp_tree, tmp_node);
+ _fixup_parity (tmp_tree, tmp_node);
+ tmp_node = tmp_node->parent;
+ if (tmp_node == tmp_tree->nil)
+ {
+ tmp_node = tmp_tree->parent_node;
+ tmp_tree = tmp_tree->parent_tree;
+ }
+ }
+
+ /* x is y's only child, or nil */
if (y->left != tree->nil)
x = y->left;
else
/* remove y from the parent chain */
x->parent = y->parent;
if (y->parent != tree->nil)
- if (y == y->parent->left)
- y->parent->left = x;
- else
- y->parent->right = x;
+ {
+ if (y == y->parent->left)
+ y->parent->left = x;
+ else
+ y->parent->right = x;
+ }
else
- tree->root = x;
+ {
+ tree->root = x;
+ }
+
+ /* We need to clean up the validity of the tree.
+ */
+
+ tmp_tree = tree;
+ tmp_node = x;
+ do
+ {
+ /* We skip the first time, iff x is nil */
+ if (tmp_node != tmp_tree->nil)
+ {
+ _fixup_validation (tmp_tree, tmp_node);
+ _fixup_parity (tmp_tree, tmp_node);
+ }
+ tmp_node = tmp_node->parent;
+ if (tmp_node == tmp_tree->nil)
+ {
+ tmp_node = tmp_tree->parent_node;
+ tmp_tree = tmp_tree->parent_tree;
+ }
+ }
+ while (tmp_tree != NULL);
if (y != node)
- node->children = y->children;
+ {
+ gint diff;
+
+ /* Copy the node over */
+ if (GTK_RBNODE_GET_COLOR (node) == GTK_RBNODE_BLACK)
+ node->flags = ((y->flags & (GTK_RBNODE_NON_COLORS)) | GTK_RBNODE_BLACK);
+ else
+ node->flags = ((y->flags & (GTK_RBNODE_NON_COLORS)) | GTK_RBNODE_RED);
+ node->children = y->children;
+ if (y->children)
+ {
+ node->children = y->children;
+ node->children->parent_node = node;
+ }
+ else
+ {
+ node->children = NULL;
+ }
+ _fixup_validation (tree, node);
+ _fixup_parity (tree, node);
+ /* We want to see how different our height is from the previous node.
+ * To do this, we compare our current height with our supposed height.
+ */
+ diff = y_height - GTK_RBNODE_GET_HEIGHT (node);
+ tmp_tree = tree;
+ tmp_node = node;
+
+ while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
+ {
+ tmp_node->offset += diff;
+ _fixup_validation (tmp_tree, tmp_node);
+ _fixup_parity (tmp_tree, tmp_node);
+ tmp_node = tmp_node->parent;
+ if (tmp_node == tmp_tree->nil)
+ {
+ tmp_node = tmp_tree->parent_node;
+ tmp_tree = tmp_tree->parent_tree;
+ }
+ }
+ }
if (GTK_RBNODE_GET_COLOR (y) == GTK_RBNODE_BLACK)
_gtk_rbtree_remove_node_fixup (tree, x);
+ _gtk_rbnode_free (y);
- G_LOCK (current_allocator);
- y->left = current_allocator->free_nodes;
- current_allocator->free_nodes = y;
- G_UNLOCK (current_allocator);
+#ifdef G_ENABLE_DEBUG
+ if (gtk_debug_flags & GTK_DEBUG_TREE)
+ {
+ g_print ("_gtk_rbtree_remove_node finished...\n");
+ _gtk_rbtree_debug_spew (tree);
+ g_print ("\n\n");
+ _gtk_rbtree_test (G_STRLOC, tree);
+ }
+#endif /* G_ENABLE_DEBUG */
}
GtkRBNode *
}
}
+gint
+_gtk_rbtree_get_depth (GtkRBTree *tree)
+{
+ GtkRBTree *tmp_tree;
+ gint depth = 0;
+
+ tmp_tree = tree->parent_tree;
+ while (tmp_tree)
+ {
+ ++depth;
+ tmp_tree = tmp_tree->parent_tree;
+ }
+
+ return depth;
+}
+
static void
_gtk_rbtree_traverse_pre_order (GtkRBTree *tree,
GtkRBNode *node,
if (node == tree->nil)
return 0;
+ g_assert (node->left);
+ g_assert (node->right);
+
res = (_count_nodes (tree, node->left) +
_count_nodes (tree, node->right) + 1);
return res;
}
-void
-_gtk_rbtree_test (GtkRBTree *tree)
+static inline
+void _fixup_validation (GtkRBTree *tree,
+ GtkRBNode *node)
{
- if ((_count_nodes (tree, tree->root->left) +
- _count_nodes (tree, tree->root->right) + 1) == tree->root->count)
- g_print ("Tree passed\n");
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+ GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) ||
+ (node->left != tree->nil && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+ (node->right != tree->nil && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+ (node->children != NULL && GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID)))
+ {
+ GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+ }
else
- g_print ("Tree failed\n");
+ {
+ GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+ }
+}
+static inline
+void _fixup_parity (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ node->parity = 1 +
+ ((node->children != NULL && node->children->root != node->children->nil) ? node->children->root->parity : 0) +
+ ((node->left != tree->nil) ? node->left->parity : 0) +
+ ((node->right != tree->nil) ? node->right->parity : 0);
}
-static void
-_gtk_rbtree_test_height_helper (GtkRBTree *tree,
- GtkRBNode *node,
- gint height)
+#ifdef G_ENABLE_DEBUG
+static guint
+get_parity (GtkRBNode *node)
+{
+ guint child_total = 0;
+ guint rem;
+
+ /* The parity of a node is node->parity minus
+ * the parity of left, right, and children.
+ *
+ * This is equivalent to saying that if left, right, children
+ * sum to 0 parity, then node->parity is the parity of node,
+ * and if left, right, children are odd parity, then
+ * node->parity is the reverse of the node's parity.
+ */
+
+ child_total += (guint) node->left->parity;
+ child_total += (guint) node->right->parity;
+
+ if (node->children)
+ child_total += (guint) node->children->root->parity;
+
+ rem = child_total % 2;
+
+ if (rem == 0)
+ return node->parity;
+ else
+ return !node->parity;
+}
+
+static guint
+count_parity (GtkRBTree *tree,
+ GtkRBNode *node)
{
+ guint res;
+
if (node == tree->nil)
+ return 0;
+
+ res =
+ count_parity (tree, node->left) +
+ count_parity (tree, node->right) +
+ (guint)1 +
+ (node->children ? count_parity (node->children, node->children->root) : 0);
+
+ res = res % (guint)2;
+
+ if (res != node->parity)
+ g_print ("parity incorrect for node\n");
+
+ if (get_parity (node) != 1)
+ g_error ("Node has incorrect parity %d", get_parity (node));
+
+ return res;
+}
+
+static void
+_gtk_rbtree_test_height (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ gint computed_offset = 0;
+
+ /* This whole test is sort of a useless truism. */
+
+ if (node->left != tree->nil)
+ computed_offset += node->left->offset;
+
+ if (node->right != tree->nil)
+ computed_offset += node->right->offset;
+
+ if (node->children && node->children->root != node->children->nil)
+ computed_offset += node->children->root->offset;
+
+ if (GTK_RBNODE_GET_HEIGHT (node) + computed_offset != node->offset)
+ g_error ("node has broken offset\n");
+
+ if (node->left != tree->nil)
+ _gtk_rbtree_test_height (tree, node->left);
+
+ if (node->right != tree->nil)
+ _gtk_rbtree_test_height (tree, node->right);
+
+ if (node->children && node->children->root != node->children->nil)
+ _gtk_rbtree_test_height (node->children, node->children->root);
+}
+
+static void
+_gtk_rbtree_test_dirty (GtkRBTree *tree,
+ GtkRBNode *node,
+ gint expected_dirtyness)
+{
+
+ if (expected_dirtyness)
+ {
+ g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) ||
+ GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+ (node->left != tree->nil && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+ (node->right != tree->nil && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+ (node->children && GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID)));
+ }
+ else
+ {
+ g_assert (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) &&
+ ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID));
+ if (node->left != tree->nil)
+ g_assert (! GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID));
+ if (node->right != tree->nil)
+ g_assert (! GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID));
+ if (node->children != NULL)
+ g_assert (! GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID));
+ }
+
+ if (node->left != tree->nil)
+ _gtk_rbtree_test_dirty (tree, node->left, GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID));
+ if (node->right != tree->nil)
+ _gtk_rbtree_test_dirty (tree, node->right, GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID));
+ if (node->children != NULL && node->children->root != node->children->nil)
+ _gtk_rbtree_test_dirty (node->children, node->children->root, GTK_RBNODE_FLAG_SET (node->children->root, GTK_RBNODE_DESCENDANTS_INVALID));
+}
+
+static void _gtk_rbtree_test_structure (GtkRBTree *tree);
+
+static void
+_gtk_rbtree_test_structure_helper (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ g_assert (node != tree->nil);
+
+ g_assert (node->left != NULL);
+ g_assert (node->right != NULL);
+ g_assert (node->parent != NULL);
+
+ if (node->left != tree->nil)
+ {
+ g_assert (node->left->parent == node);
+ _gtk_rbtree_test_structure_helper (tree, node->left);
+ }
+ if (node->right != tree->nil)
+ {
+ g_assert (node->right->parent == node);
+ _gtk_rbtree_test_structure_helper (tree, node->right);
+ }
+
+ if (node->children != NULL)
+ {
+ g_assert (node->children->parent_tree == tree);
+ g_assert (node->children->parent_node == node);
+
+ _gtk_rbtree_test_structure (node->children);
+ }
+}
+static void
+_gtk_rbtree_test_structure (GtkRBTree *tree)
+{
+ g_assert (tree->root);
+ if (tree->root == tree->nil)
return;
- if (node->offset -
- (node->left?node->left->offset:0) -
- (node->right?node->right->offset:0) -
- (node->children?node->children->root->offset:0) != height)
- g_error ("tree failed\n");
+ g_assert (tree->root->parent == tree->nil);
+ _gtk_rbtree_test_structure_helper (tree, tree->root);
+}
+
+void
+_gtk_rbtree_test (const gchar *where,
+ GtkRBTree *tree)
+{
+ GtkRBTree *tmp_tree;
- _gtk_rbtree_test_height_helper (tree, node->left, height);
- _gtk_rbtree_test_height_helper (tree, node->right, height);
- if (node->children)
- _gtk_rbtree_test_height_helper (node->children, node->children->root, height);
+ if (tree == NULL)
+ return;
+
+ /* Test the entire tree */
+ tmp_tree = tree;
+ while (tmp_tree->parent_tree)
+ tmp_tree = tmp_tree->parent_tree;
+
+ g_assert (tmp_tree->nil != NULL);
+
+ if (tmp_tree->root == tmp_tree->nil)
+ return;
+ _gtk_rbtree_test_structure (tmp_tree);
+
+ g_assert ((_count_nodes (tmp_tree, tmp_tree->root->left) +
+ _count_nodes (tmp_tree, tmp_tree->root->right) + 1) == tmp_tree->root->count);
+
+
+ _gtk_rbtree_test_height (tmp_tree, tmp_tree->root);
+ _gtk_rbtree_test_dirty (tmp_tree, tmp_tree->root, GTK_RBNODE_FLAG_SET (tmp_tree->root, GTK_RBNODE_DESCENDANTS_INVALID));
+ g_assert (count_parity (tmp_tree, tmp_tree->root) == tmp_tree->root->parity);
+}
+
+static void
+_gtk_rbtree_debug_spew_helper (GtkRBTree *tree,
+ GtkRBNode *node,
+ gint depth)
+{
+ gint i;
+ for (i = 0; i < depth; i++)
+ g_print ("\t");
+
+ g_print ("(%p - %s) (Offset %d) (Parity %d) (Validity %d%d%d)\n",
+ node,
+ (GTK_RBNODE_GET_COLOR (node) == GTK_RBNODE_BLACK)?"BLACK":" RED ",
+ node->offset,
+ node->parity?1:0,
+ (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID))?1:0,
+ (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID))?1:0,
+ (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID))?1:0);
+ if (node->children != NULL)
+ {
+ g_print ("Looking at child.\n");
+ _gtk_rbtree_debug_spew (node->children);
+ g_print ("Done looking at child.\n");
+ }
+ if (node->left != tree->nil)
+ {
+ _gtk_rbtree_debug_spew_helper (tree, node->left, depth+1);
+ }
+ if (node->right != tree->nil)
+ {
+ _gtk_rbtree_debug_spew_helper (tree, node->right, depth+1);
+ }
}
void
-_gtk_rbtree_test_height (GtkRBTree *tree,
- gint height)
+_gtk_rbtree_debug_spew (GtkRBTree *tree)
{
- _gtk_rbtree_test_height_helper (tree, tree->root, height);
+ g_return_if_fail (tree != NULL);
+
+ if (tree->root == tree->nil)
+ g_print ("Empty tree...\n");
+ else
+ _gtk_rbtree_debug_spew_helper (tree, tree->root, 0);
}
+#endif /* G_ENABLE_DEBUG */