]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkrbtree.c
ri Jun 14 10:00:29 2002 Owen Taylor <otaylor@redhat.com>
[~andy/gtk] / gtk / gtkrbtree.c
index 6afc080ecf3c24f326abcbcf2dcb6e305546911e..3a4841e9a4fc6c1d5c1174ff7c7cc54ae338dd78 100644 (file)
  */
 
 #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
@@ -52,6 +58,7 @@ struct _GAllocator /* from gmem.c */
 G_LOCK_DEFINE_STATIC (current_allocator);
 static GAllocator *current_allocator = NULL;
 
+
 /* HOLDS: current_allocator_lock */
 static void
 _gtk_rbnode_validate_allocator (GAllocator *allocator)
@@ -109,6 +116,7 @@ _gtk_rbnode_new (GtkRBTree *tree,
   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;
@@ -121,6 +129,17 @@ _gtk_rbnode_free (GtkRBNode *node)
   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);
 }
 
@@ -141,7 +160,6 @@ _gtk_rbnode_rotate_left (GtkRBTree *tree,
     (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;
@@ -166,6 +184,7 @@ _gtk_rbnode_rotate_left (GtkRBTree *tree,
     (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) +
@@ -174,6 +193,11 @@ _gtk_rbnode_rotate_left (GtkRBTree *tree,
     (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
@@ -193,7 +217,7 @@ _gtk_rbnode_rotate_right (GtkRBTree *tree,
     (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;
@@ -221,6 +245,7 @@ _gtk_rbnode_rotate_right (GtkRBTree *tree,
     (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) +
@@ -229,6 +254,11 @@ _gtk_rbnode_rotate_right (GtkRBTree *tree,
     (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
@@ -411,6 +441,7 @@ _gtk_rbtree_new (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;
@@ -450,12 +481,28 @@ _gtk_rbtree_remove (GtkRBTree *tree)
   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)
        {
@@ -463,19 +510,37 @@ _gtk_rbtree_remove (GtkRBTree *tree)
          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)
     {
@@ -484,7 +549,6 @@ _gtk_rbtree_insert_after (GtkRBTree  *tree,
        current = current->left;
       right = FALSE;
     }
-
   /* setup new node */
   node = _gtk_rbnode_new (tree, height);
   node->parent = (current?current:tree->nil);
@@ -512,6 +576,8 @@ _gtk_rbtree_insert_after (GtkRBTree  *tree,
        * 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)
@@ -520,21 +586,47 @@ _gtk_rbtree_insert_after (GtkRBTree  *tree,
          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;
@@ -570,6 +662,8 @@ _gtk_rbtree_insert_before (GtkRBTree  *tree,
        * 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)
@@ -578,8 +672,24 @@ _gtk_rbtree_insert_before (GtkRBTree  *tree,
          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;
 }
 
@@ -627,46 +737,405 @@ _gtk_rbtree_node_set_height (GtkRBTree *tree,
          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 &&
@@ -697,34 +1166,72 @@ _gtk_rbtree_find_offset (GtkRBTree  *tree,
          *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;
@@ -736,10 +1243,33 @@ _gtk_rbtree_remove_node (GtkRBTree *tree,
       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
@@ -748,23 +1278,94 @@ _gtk_rbtree_remove_node (GtkRBTree *tree,
   /* 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 *
@@ -889,6 +1490,22 @@ _gtk_rbtree_prev_full (GtkRBTree  *tree,
     }
 }
 
+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,
@@ -953,6 +1570,9 @@ _count_nodes (GtkRBTree *tree,
   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);
 
@@ -961,41 +1581,267 @@ _count_nodes (GtkRBTree *tree,
   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 */