* Boston, MA 02111-1307, USA.
*/
+#include "config.h"
#include "gtkrbtree.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_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
- */
-struct _GAllocator /* from gmem.c */
-{
- gchar *name;
- guint16 n_preallocs;
- guint is_unused : 1;
- guint type : 4;
- GAllocator *last;
- GMemChunk *mem_chunk;
- GtkRBNode *free_nodes; /* implementation specific */
+#include "gtkdebug.h"
+
+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,
+ GtkRBNode *parent);
+static inline void _fixup_validation (GtkRBTree *tree,
+ GtkRBNode *node);
+static inline void _fixup_total_count (GtkRBTree *tree,
+ GtkRBNode *node);
+#ifdef G_ENABLE_DEBUG
+static void _gtk_rbtree_test (const gchar *where,
+ GtkRBTree *tree);
+static void _gtk_rbtree_debug_spew (GtkRBTree *tree);
+#endif
+
+static const GtkRBNode nil = {
+ /* .flags = */ GTK_RBNODE_BLACK,
+
+ /* rest is NULL */
};
-
-G_LOCK_DEFINE_STATIC (current_allocator);
-static GAllocator *current_allocator = NULL;
-
-/* HOLDS: current_allocator_lock */
-static void
-_gtk_rbnode_validate_allocator (GAllocator *allocator)
+gboolean
+_gtk_rbtree_is_nil (GtkRBNode *node)
{
- g_return_if_fail (allocator != NULL);
- g_return_if_fail (allocator->is_unused == TRUE);
-
- if (allocator->type != G_ALLOCATOR_NODE)
- {
- allocator->type = G_ALLOCATOR_NODE;
- if (allocator->mem_chunk)
- {
- g_mem_chunk_destroy (allocator->mem_chunk);
- allocator->mem_chunk = NULL;
- }
- }
-
- if (!allocator->mem_chunk)
- {
- allocator->mem_chunk = g_mem_chunk_new (allocator->name,
- sizeof (GtkRBNode),
- sizeof (GtkRBNode) * allocator->n_preallocs,
- G_ALLOC_ONLY);
- allocator->free_nodes = NULL;
- }
-
- allocator->is_unused = FALSE;
+ return node == &nil;
}
static GtkRBNode *
_gtk_rbnode_new (GtkRBTree *tree,
gint height)
{
- GtkRBNode *node;
-
- G_LOCK (current_allocator);
- if (!current_allocator)
- {
- GAllocator *allocator = g_allocator_new ("GTK+ default GtkRBNode allocator",
- 128);
- _gtk_rbnode_validate_allocator (allocator);
- allocator->last = NULL;
- current_allocator = allocator;
- }
- if (!current_allocator->free_nodes)
- node = g_chunk_new (GtkRBNode, current_allocator->mem_chunk);
- else
- {
- node = current_allocator->free_nodes;
- current_allocator->free_nodes = node->left;
- }
- G_UNLOCK (current_allocator);
+ GtkRBNode *node = g_slice_new (GtkRBNode);
- node->left = tree->nil;
- node->right = tree->nil;
- node->parent = tree->nil;
+ node->left = (GtkRBNode *) &nil;
+ node->right = (GtkRBNode *) &nil;
+ node->parent = (GtkRBNode *) &nil;
node->flags = GTK_RBNODE_RED;
+ node->total_count = 1;
node->count = 1;
node->children = NULL;
node->offset = height;
static void
_gtk_rbnode_free (GtkRBNode *node)
{
- G_LOCK (current_allocator);
- node->left = current_allocator->free_nodes;
- current_allocator->free_nodes = node;
- G_UNLOCK (current_allocator);
+#ifdef G_ENABLE_DEBUG
+ if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
+ {
+ node->left = (gpointer) 0xdeadbeef;
+ node->right = (gpointer) 0xdeadbeef;
+ node->parent = (gpointer) 0xdeadbeef;
+ node->total_count = 56789;
+ node->offset = 56789;
+ node->count = 56789;
+ node->flags = 0;
+ }
+#endif
+ g_slice_free (GtkRBNode, node);
}
static void
GtkRBNode *node)
{
gint node_height, right_height;
- GtkRBNode *right = node->right;
+ GtkRBNode *right;
- g_return_if_fail (node != tree->nil);
+ g_return_if_fail (!_gtk_rbtree_is_nil (node));
+ g_return_if_fail (!_gtk_rbtree_is_nil (node->right));
- node_height = node->offset -
- (node->left?node->left->offset:0) -
- (node->right?node->right->offset:0) -
- (node->children?node->children->root->offset:0);
- right_height = right->offset -
- (right->left?right->left->offset:0) -
- (right->right?right->right->offset:0) -
- (right->children?right->children->root->offset:0);
+ right = node->right;
+ node_height = GTK_RBNODE_GET_HEIGHT (node);
+ right_height = GTK_RBNODE_GET_HEIGHT (right);
node->right = right->left;
- if (right->left != tree->nil)
+ if (!_gtk_rbtree_is_nil (right->left))
right->left->parent = node;
- if (right != tree->nil)
- right->parent = node->parent;
- if (node->parent != tree->nil)
+ right->parent = node->parent;
+ if (!_gtk_rbtree_is_nil (node->parent))
{
if (node == node->parent->left)
node->parent->left = right;
}
right->left = node;
- if (node != tree->nil)
- node->parent = right;
-
- node->count = 1 + (node->left?node->left->count:0) +
- (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) +
- (node->children?node->children->root->offset:0);
- right->offset = right_height +
- (right->left?right->left->offset:0) +
- (right->right?right->right->offset:0) +
- (right->children?right->children->root->offset:0);
+ node->parent = right;
+
+ node->count = 1 + node->left->count + node->right->count;
+ right->count = 1 + right->left->count + right->right->count;
+
+ node->offset = node_height + node->left->offset + node->right->offset +
+ (node->children ? node->children->root->offset : 0);
+ right->offset = right_height + right->left->offset + right->right->offset +
+ (right->children ? right->children->root->offset : 0);
+
+ _fixup_validation (tree, node);
+ _fixup_validation (tree, right);
+ _fixup_total_count (tree, node);
+ _fixup_total_count (tree, right);
}
static void
GtkRBNode *node)
{
gint node_height, left_height;
- GtkRBNode *left = node->left;
+ GtkRBNode *left;
- g_return_if_fail (node != tree->nil);
+ g_return_if_fail (!_gtk_rbtree_is_nil (node));
+ g_return_if_fail (!_gtk_rbtree_is_nil (node->left));
- node_height = node->offset -
- (node->left?node->left->offset:0) -
- (node->right?node->right->offset:0) -
- (node->children?node->children->root->offset:0);
- left_height = left->offset -
- (left->left?left->left->offset:0) -
- (left->right?left->right->offset:0) -
- (left->children?left->children->root->offset:0);
+ left = node->left;
+ node_height = GTK_RBNODE_GET_HEIGHT (node);
+ left_height = GTK_RBNODE_GET_HEIGHT (left);
+
node->left = left->right;
- if (left->right != tree->nil)
+ if (!_gtk_rbtree_is_nil (left->right))
left->right->parent = node;
- if (left != tree->nil)
- left->parent = node->parent;
- if (node->parent != tree->nil)
+ left->parent = node->parent;
+ if (!_gtk_rbtree_is_nil (node->parent))
{
if (node == node->parent->right)
node->parent->right = left;
/* link node and left */
left->right = node;
- if (node != tree->nil)
- node->parent = left;
-
- node->count = 1 + (node->left?node->left->count:0) +
- (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) +
- (node->children?node->children->root->offset:0);
- left->offset = left_height +
- (left->left?left->left->offset:0) +
- (left->right?left->right->offset:0) +
- (left->children?left->children->root->offset:0);
+ node->parent = left;
+
+ node->count = 1 + node->left->count + node->right->count;
+ left->count = 1 + left->left->count + left->right->count;
+
+ node->offset = node_height + node->left->offset + node->right->offset +
+ (node->children ? node->children->root->offset : 0);
+ left->offset = left_height + left->left->offset + left->right->offset +
+ (left->children?left->children->root->offset:0);
+
+ _fixup_validation (tree, node);
+ _fixup_validation (tree, left);
+ _fixup_total_count (tree, node);
+ _fixup_total_count (tree, left);
}
static void
static void
_gtk_rbtree_remove_node_fixup (GtkRBTree *tree,
- GtkRBNode *node)
+ GtkRBNode *node,
+ GtkRBNode *parent)
{
while (node != tree->root && GTK_RBNODE_GET_COLOR (node) == GTK_RBNODE_BLACK)
{
- if (node == node->parent->left)
+ if (node == parent->left)
{
- GtkRBNode *w = node->parent->right;
+ GtkRBNode *w = parent->right;
if (GTK_RBNODE_GET_COLOR (w) == GTK_RBNODE_RED)
{
GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_BLACK);
- GTK_RBNODE_SET_COLOR (node->parent, GTK_RBNODE_RED);
- _gtk_rbnode_rotate_left (tree, node->parent);
- w = node->parent->right;
+ GTK_RBNODE_SET_COLOR (parent, GTK_RBNODE_RED);
+ _gtk_rbnode_rotate_left (tree, parent);
+ w = parent->right;
}
if (GTK_RBNODE_GET_COLOR (w->left) == GTK_RBNODE_BLACK && GTK_RBNODE_GET_COLOR (w->right) == GTK_RBNODE_BLACK)
{
GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_RED);
- node = node->parent;
+ node = parent;
}
else
{
GTK_RBNODE_SET_COLOR (w->left, GTK_RBNODE_BLACK);
GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_RED);
_gtk_rbnode_rotate_right (tree, w);
- w = node->parent->right;
+ w = parent->right;
}
- GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_GET_COLOR (node->parent));
- GTK_RBNODE_SET_COLOR (node->parent, GTK_RBNODE_BLACK);
+ GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_GET_COLOR (parent));
+ GTK_RBNODE_SET_COLOR (parent, GTK_RBNODE_BLACK);
GTK_RBNODE_SET_COLOR (w->right, GTK_RBNODE_BLACK);
- _gtk_rbnode_rotate_left (tree, node->parent);
+ _gtk_rbnode_rotate_left (tree, parent);
node = tree->root;
}
}
else
{
- GtkRBNode *w = node->parent->left;
+ GtkRBNode *w = parent->left;
if (GTK_RBNODE_GET_COLOR (w) == GTK_RBNODE_RED)
{
GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_BLACK);
- GTK_RBNODE_SET_COLOR (node->parent, GTK_RBNODE_RED);
- _gtk_rbnode_rotate_right (tree, node->parent);
- w = node->parent->left;
+ GTK_RBNODE_SET_COLOR (parent, GTK_RBNODE_RED);
+ _gtk_rbnode_rotate_right (tree, parent);
+ w = parent->left;
}
if (GTK_RBNODE_GET_COLOR (w->right) == GTK_RBNODE_BLACK && GTK_RBNODE_GET_COLOR (w->left) == GTK_RBNODE_BLACK)
{
GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_RED);
- node = node->parent;
+ node = parent;
}
else
{
GTK_RBNODE_SET_COLOR (w->right, GTK_RBNODE_BLACK);
GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_RED);
_gtk_rbnode_rotate_left (tree, w);
- w = node->parent->left;
+ w = parent->left;
}
- GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_GET_COLOR (node->parent));
- GTK_RBNODE_SET_COLOR (node->parent, GTK_RBNODE_BLACK);
+ GTK_RBNODE_SET_COLOR (w, GTK_RBNODE_GET_COLOR (parent));
+ GTK_RBNODE_SET_COLOR (parent, GTK_RBNODE_BLACK);
GTK_RBNODE_SET_COLOR (w->left, GTK_RBNODE_BLACK);
- _gtk_rbnode_rotate_right (tree, node->parent);
+ _gtk_rbnode_rotate_right (tree, parent);
node = tree->root;
}
}
- }
- GTK_RBNODE_SET_COLOR (node, GTK_RBNODE_BLACK);
-}
-
-/* Public functions */
-void
-_gtk_rbnode_push_allocator (GAllocator *allocator)
-{
- G_LOCK (current_allocator);
- _gtk_rbnode_validate_allocator ( allocator );
- allocator->last = current_allocator;
- current_allocator = allocator;
- G_UNLOCK (current_allocator);
-}
-
-void
-_gtk_rbnode_pop_allocator (void)
-{
- G_LOCK (current_allocator);
- if (current_allocator)
- {
- GAllocator *allocator;
- allocator = current_allocator;
- current_allocator = allocator->last;
- allocator->last = NULL;
- allocator->is_unused = TRUE;
+ parent = node->parent;
}
- G_UNLOCK (current_allocator);
+ GTK_RBNODE_SET_COLOR (node, GTK_RBNODE_BLACK);
}
GtkRBTree *
{
GtkRBTree *retval;
- retval = (GtkRBTree *) g_new (GtkRBTree, 1);
+ retval = g_new (GtkRBTree, 1);
retval->parent_tree = NULL;
retval->parent_node = NULL;
- retval->nil = g_new0 (GtkRBNode, 1);
- retval->nil->left = NULL;
- retval->nil->right = NULL;
- retval->nil->parent = NULL;
- retval->nil->flags = GTK_RBNODE_BLACK;
- retval->nil->count = 0;
- retval->nil->offset = 0;
+ retval->root = (GtkRBNode *) &nil;
- retval->root = retval->nil;
return retval;
}
if (tree->parent_node &&
tree->parent_node->children == tree)
tree->parent_node->children = NULL;
- _gtk_rbnode_free (tree->nil);
g_free (tree);
}
+static void
+gtk_rbnode_adjust (GtkRBTree *tree,
+ GtkRBNode *node,
+ int count_diff,
+ int total_count_diff,
+ int offset_diff)
+{
+ while (tree && node && !_gtk_rbtree_is_nil (node))
+ {
+ _fixup_validation (tree, node);
+ node->offset += offset_diff;
+ node->count += count_diff;
+ node->total_count += total_count_diff;
+
+ node = node->parent;
+ if (_gtk_rbtree_is_nil (node))
+ {
+ node = tree->parent_node;
+ tree = tree->parent_tree;
+ count_diff = 0;
+ }
+ }
+}
+
void
_gtk_rbtree_remove (GtkRBTree *tree)
{
+#ifdef G_ENABLE_DEBUG
GtkRBTree *tmp_tree;
- GtkRBNode *tmp_node;
- gint height = tree->root->offset;
+ if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
+ _gtk_rbtree_test (G_STRLOC, tree);
+#endif
+
+ /* 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);
+
+ gtk_rbnode_adjust (tree->parent_tree,
+ tree->parent_node,
+ 0,
+ - (int) tree->root->total_count,
+ - tree->root->offset);
+
+#ifdef G_ENABLE_DEBUG
tmp_tree = tree->parent_tree;
- tmp_node = tree->parent_node;
+#endif
- while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
- {
- tmp_node->offset -= height;
- tmp_node = tmp_node->parent;
- if (tmp_node == tmp_tree->nil)
- {
- tmp_node = tmp_tree->parent_node;
- tmp_tree = tmp_tree->parent_tree;
- }
- }
_gtk_rbtree_free (tree);
+
+#ifdef G_ENABLE_DEBUG
+ if (gtk_get_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;
- if (current != NULL && current->right != tree->nil)
+#ifdef G_ENABLE_DEBUG
+ if (gtk_get_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 && !_gtk_rbtree_is_nil (current->right))
{
current = current->right;
- while (current->left != tree->nil)
+ while (!_gtk_rbtree_is_nil (current->left))
current = current->left;
right = FALSE;
}
-
/* setup new node */
node = _gtk_rbnode_new (tree, height);
- node->parent = (current?current:tree->nil);
/* insert node in tree */
if (current)
{
+ node->parent = current;
if (right)
current->right = node;
else
current->left = node;
- tmp_node = node->parent;
- tmp_tree = tree;
+ gtk_rbnode_adjust (tree, node->parent,
+ 1, 1, height);
}
else
{
+ g_assert (_gtk_rbtree_is_nil (tree->root));
tree->root = node;
- tmp_node = tree->parent_node;
- tmp_tree = tree->parent_tree;
+ gtk_rbnode_adjust (tree->parent_tree, tree->parent_node,
+ 0, 1, height);
}
- while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
+ 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_get_debug_flags () & GTK_DEBUG_TREE)
{
- /* We only want to propagate the count if we are in the tree we
- * started in. */
- if (tmp_tree == tree)
- tmp_node->count++;
- tmp_node->offset += height;
- tmp_node = tmp_node->parent;
- if (tmp_node == tmp_tree->nil)
- {
- tmp_node = tmp_tree->parent_node;
- tmp_tree = tmp_tree->parent_tree;
- }
+ g_print ("_gtk_rbtree_insert_after finished...\n");
+ _gtk_rbtree_debug_spew (tree);
+ g_print ("\n\n");
+ _gtk_rbtree_test (G_STRLOC, tree);
}
- _gtk_rbtree_insert_fixup (tree, node);
+#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;
- if (current != NULL && current->left != tree->nil)
+#ifdef G_ENABLE_DEBUG
+ if (gtk_get_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 && !_gtk_rbtree_is_nil (current->left))
{
current = current->left;
- while (current->right != tree->nil)
+ while (!_gtk_rbtree_is_nil (current->right))
current = current->right;
left = FALSE;
}
/* setup new node */
node = _gtk_rbnode_new (tree, height);
- node->parent = (current?current:tree->nil);
/* insert node in tree */
if (current)
{
+ node->parent = current;
if (left)
current->left = node;
else
current->right = node;
- tmp_node = node->parent;
- tmp_tree = tree;
+ gtk_rbnode_adjust (tree, node->parent,
+ 1, 1, height);
}
else
{
+ g_assert (_gtk_rbtree_is_nil (tree->root));
tree->root = node;
- tmp_node = tree->parent_node;
- tmp_tree = tree->parent_tree;
+ gtk_rbnode_adjust (tree->parent_tree, tree->parent_node,
+ 0, 1, height);
}
- while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
- {
- /* We only want to propagate the count if we are in the tree we
- * started in. */
- if (tmp_tree == tree)
- tmp_node->count++;
- tmp_node->offset += height;
- tmp_node = tmp_node->parent;
- if (tmp_node == tmp_tree->nil)
- {
- tmp_node = tmp_tree->parent_node;
- 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_get_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;
}
GtkRBNode *node;
node = tree->root;
- while (node != tree->nil && (node->left->count + 1 != count))
+ while (!_gtk_rbtree_is_nil (node) && (node->left->count + 1 != count))
{
if (node->left->count >= count)
node = node->left;
node = node->right;
}
}
- if (node == tree->nil)
+ if (_gtk_rbtree_is_nil (node))
return NULL;
return node;
}
gint height)
{
gint diff = height - GTK_RBNODE_GET_HEIGHT (node);
- GtkRBNode *tmp_node = node;
- GtkRBTree *tmp_tree = tree;
if (diff == 0)
return;
- while (tmp_tree && tmp_node && tmp_node != tmp_tree->nil)
+ gtk_rbnode_adjust (tree, node, 0, 0, diff);
+
+#ifdef G_ENABLE_DEBUG
+ if (gtk_get_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
{
- tmp_node->offset += diff;
- tmp_node = tmp_node->parent;
- if (tmp_node == tmp_tree->nil)
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_DESCENDANTS_INVALID))
+ return;
+ GTK_RBNODE_SET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+ node = node->parent;
+ if (_gtk_rbtree_is_nil (node))
{
- tmp_node = tmp_tree->parent_node;
- tmp_tree = tmp_tree->parent_tree;
+ 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 (_gtk_rbtree_is_nil (node))
+ {
+ 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)) ||
+ (GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
+ (GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID)))
+ return;
+
+ GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+ node = node->parent;
+ if (_gtk_rbtree_is_nil (node))
+ {
+ 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 (_gtk_rbtree_is_nil (node))
+ {
+ 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 = _gtk_rbtree_first (tree);
+
+ 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 = _gtk_rbtree_first (tree);
+
+ 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,
+ gboolean mark_valid)
+{
+ GtkRBNode *node;
+
+ if (tree == NULL)
+ return;
+
+ node = _gtk_rbtree_first (tree);
+
+ do
+ {
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID))
+ {
+ _gtk_rbtree_node_set_height (tree, node, height);
+ if (mark_valid)
+ _gtk_rbtree_node_mark_valid (tree, node);
+ }
+
+ if (node->children)
+ _gtk_rbtree_set_fixed_height (node->children, height, mark_valid);
+ }
+ while ((node = _gtk_rbtree_next (tree, node)) != NULL);
+}
+
+static void
+reorder_prepare (GtkRBTree *tree,
+ GtkRBNode *node,
+ gpointer data)
+{
+ node->offset -= node->left->offset + node->right->offset;
+ GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+}
+
+static void
+reorder_fixup (GtkRBTree *tree,
+ GtkRBNode *node,
+ gpointer data)
+{
+ node->offset += node->left->offset + node->right->offset;
+ node->count = 1 + node->left->count + node->right->count;
+ _fixup_validation (tree, node);
+ _fixup_total_count (tree, node);
+}
+
+static void
+reorder_copy_node (GtkRBTree *tree,
+ GtkRBNode *to,
+ GtkRBNode *from)
+{
+ to->flags = (to->flags & GTK_RBNODE_NON_COLORS) | GTK_RBNODE_GET_COLOR (from);
+
+ to->left = from->left;
+ if (!_gtk_rbtree_is_nil (to->left))
+ to->left->parent = to;
+
+ to->right = from->right;
+ if (!_gtk_rbtree_is_nil (to->right))
+ to->right->parent = to;
+
+ to->parent = from->parent;
+ if (_gtk_rbtree_is_nil (to->parent))
+ tree->root = to;
+ else if (to->parent->left == from)
+ to->parent->left = to;
+ else if (to->parent->right == from)
+ to->parent->right = to;
+}
+
+/* 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)
+{
+ GtkRBNode **nodes;
+ GtkRBNode *node;
+ gint i, j;
+
+ g_return_if_fail (tree != NULL);
+ g_return_if_fail (length > 0);
+ g_return_if_fail (tree->root->count == length);
+
+ nodes = g_new (GtkRBNode *, length);
+
+ _gtk_rbtree_traverse (tree, tree->root, G_PRE_ORDER, reorder_prepare, NULL);
+
+ for (node = _gtk_rbtree_first (tree), i = 0;
+ node;
+ node = _gtk_rbtree_next (tree, node), i++)
+ {
+ nodes[i] = node;
+ }
+
+ for (i = 0; i < length; i++)
+ {
+ GtkRBNode tmp = { 0, };
+ GSList *l, *cycle = NULL;
+
+ tmp.offset = -1;
+
+ /* already swapped */
+ if (nodes[i] == NULL)
+ continue;
+ /* no need to swap */
+ if (new_order[i] == i)
+ continue;
+
+ /* make a list out of the pending nodes */
+ for (j = i; new_order[j] != i; j = new_order[j])
+ {
+ cycle = g_slist_prepend (cycle, nodes[j]);
+ nodes[j] = NULL;
+ }
+
+ node = nodes[j];
+ reorder_copy_node (tree, &tmp, node);
+ for (l = cycle; l; l = l->next)
+ {
+ reorder_copy_node (tree, node, l->data);
+ node = l->data;
+ }
+
+ reorder_copy_node (tree, node, &tmp);
+ nodes[j] = NULL;
+ g_slist_free (cycle);
+ }
+
+ _gtk_rbtree_traverse (tree, tree->root, G_POST_ORDER, reorder_fixup, NULL);
+
+ g_free (nodes);
+}
+
+/**
+ * _gtk_rbtree_contains:
+ * @tree: a tree
+ * @potential_child: a potential child of @tree
+ *
+ * Checks if @potential_child is a child (direct or via intermediate
+ * trees) of @tree.
+ *
+ * Returns: %TRUE if @potentitial_child is a child of @tree.
+ **/
+gboolean
+_gtk_rbtree_contains (GtkRBTree *tree,
+ GtkRBTree *potential_child)
+{
+ g_return_val_if_fail (tree != NULL, FALSE);
+ g_return_val_if_fail (potential_child != NULL, FALSE);
+
+ do {
+ potential_child = potential_child->parent_tree;
+ if (potential_child == tree)
+ return TRUE;
+ } while (potential_child != NULL);
+
+ return FALSE;
}
gint
GtkRBNode *node)
{
GtkRBNode *last;
- gint retval = node->left->offset;
+ gint retval;
- while (tree && node && node != tree->nil)
+ g_assert (node);
+ g_assert (node->left);
+
+ retval = node->left->offset;
+
+ while (tree && node && !_gtk_rbtree_is_nil (node))
{
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);
- if (node == tree->nil)
+ retval += node->offset - node->right->offset;
+
+ if (_gtk_rbtree_is_nil (node))
{
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;
}
+guint
+_gtk_rbtree_node_get_index (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ GtkRBNode *last;
+ guint retval;
+
+ g_assert (node);
+ g_assert (node->left);
+
+ retval = node->left->total_count;
+
+ while (tree && node && !_gtk_rbtree_is_nil (node))
+ {
+ last = node;
+ node = node->parent;
+
+ /* Add left branch, plus children, iff we came from the right */
+ if (node->right == last)
+ retval += node->total_count - node->right->total_count;
+
+ if (_gtk_rbtree_is_nil (node))
+ {
+ node = tree->parent_node;
+ tree = tree->parent_tree;
+
+ /* Add the parent node, plus the left branch. */
+ if (node)
+ retval += node->left->total_count + 1; /* 1 == GTK_RBNODE_GET_PARITY() */
+ }
+ }
+
+ return retval;
+}
+
gint
-_gtk_rbtree_find_offset (GtkRBTree *tree,
- gint height,
- GtkRBTree **new_tree,
- GtkRBNode **new_node)
+_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 &&
+ while (!_gtk_rbtree_is_nil (tmp_node) &&
(tmp_node->left->offset > height ||
(tmp_node->offset - tmp_node->right->offset) < height))
{
tmp_node = tmp_node->right;
}
}
- if (tmp_node == tree->nil)
+ if (_gtk_rbtree_is_nil (tmp_node))
{
*new_tree = NULL;
*new_node = NULL;
*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);
+}
+
+gboolean
+_gtk_rbtree_find_index (GtkRBTree *tree,
+ guint index,
+ GtkRBTree **new_tree,
+ GtkRBNode **new_node)
+{
+ GtkRBNode *tmp_node;
+
+ g_assert (tree);
+
+ tmp_node = tree->root;
+ while (!_gtk_rbtree_is_nil (tmp_node))
+ {
+ if (tmp_node->left->total_count > index)
+ {
+ tmp_node = tmp_node->left;
+ }
+ else if (tmp_node->total_count - tmp_node->right->total_count <= index)
+ {
+ index -= tmp_node->total_count - tmp_node->right->total_count;
+ tmp_node = tmp_node->right;
+ }
+ else
+ {
+ index -= tmp_node->left->total_count;
+ break;
+ }
+ }
+ if (_gtk_rbtree_is_nil (tmp_node))
+ {
+ *new_tree = NULL;
+ *new_node = NULL;
+ return FALSE;
+ }
+
+ if (index > 0)
+ {
+ g_assert (tmp_node->children);
+
+ return _gtk_rbtree_find_index (tmp_node->children,
+ index - 1,
+ new_tree,
+ new_node);
+ }
+
+ *new_tree = tree;
+ *new_node = tmp_node;
+ return TRUE;
+}
void
_gtk_rbtree_remove_node (GtkRBTree *tree,
GtkRBNode *node)
{
GtkRBNode *x, *y;
-
+ gint y_height;
+ guint y_total_count;
+
g_return_if_fail (tree != NULL);
g_return_if_fail (node != NULL);
+
+
+#ifdef G_ENABLE_DEBUG
+ if (gtk_get_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)
+ for (x = node; !_gtk_rbtree_is_nil (x->parent); x = x->parent)
;
g_return_if_fail (x == tree->root);
- if (node->left == tree->nil || node->right == tree->nil)
+#ifdef G_ENABLE_DEBUG
+ if (gtk_get_debug_flags () & GTK_DEBUG_TREE)
+ _gtk_rbtree_test (G_STRLOC, tree);
+#endif
+
+ if (_gtk_rbtree_is_nil (node->left) ||
+ _gtk_rbtree_is_nil (node->right))
{
y = node;
}
{
y = node->right;
- while (y->left != tree->nil)
+ while (!_gtk_rbtree_is_nil (y->left))
y = y->left;
}
- for (x = y; x != tree->nil; x = x->parent)
- x->count--;
- y->count = node->count;
- /* x is y's only child */
- if (y->left != tree->nil)
+
+ y_height = GTK_RBNODE_GET_HEIGHT (y)
+ + (y->children ? y->children->root->offset : 0);
+ y_total_count = 1 + (y->children ? y->children->root->total_count : 0);
+
+ /* x is y's only child, or nil */
+ if (!_gtk_rbtree_is_nil (y->left))
x = y->left;
else
x = y->right;
/* 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 (!_gtk_rbtree_is_nil (x))
+ x->parent = y->parent;
+ if (!_gtk_rbtree_is_nil (y->parent))
+ {
+ if (y == y->parent->left)
+ y->parent->left = x;
+ else
+ y->parent->right = x;
+ }
else
- tree->root = x;
+ {
+ tree->root = x;
+ }
- if (y != node)
- node->children = y->children;
+ /* We need to clean up the validity of the tree.
+ */
+ gtk_rbnode_adjust (tree, y, -1, - y_total_count, - y_height);
if (GTK_RBNODE_GET_COLOR (y) == GTK_RBNODE_BLACK)
- _gtk_rbtree_remove_node_fixup (tree, x);
+ _gtk_rbtree_remove_node_fixup (tree, x, y->parent);
+
+ if (y != node)
+ {
+ gint node_height, node_total_count;
+
+ /* We want to see how much we remove from the aggregate values.
+ * This is all the children we remove plus the node's values.
+ */
+ node_height = GTK_RBNODE_GET_HEIGHT (node)
+ + (node->children ? node->children->root->offset : 0);
+ node_total_count = 1
+ + (node->children ? node->children->root->total_count : 0);
+
+ /* Move the node over */
+ if (GTK_RBNODE_GET_COLOR (node) != GTK_RBNODE_GET_COLOR (y))
+ y->flags ^= (GTK_RBNODE_BLACK | GTK_RBNODE_RED);
+
+ y->left = node->left;
+ if (!_gtk_rbtree_is_nil (y->left))
+ y->left->parent = y;
+ y->right = node->right;
+ if (!_gtk_rbtree_is_nil (y->right))
+ y->right->parent = y;
+ y->parent = node->parent;
+ if (!_gtk_rbtree_is_nil (y->parent))
+ {
+ if (y->parent->left == node)
+ y->parent->left = y;
+ else
+ y->parent->right = y;
+ }
+ else
+ {
+ tree->root = y;
+ }
+ y->count = node->count;
+ y->total_count = node->total_count;
+ y->offset = node->offset;
+
+ gtk_rbnode_adjust (tree, y,
+ 0,
+ y_total_count - node_total_count,
+ y_height - node_height);
+ }
+
+ _gtk_rbnode_free (node);
- 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_get_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 *
+_gtk_rbtree_first (GtkRBTree *tree)
+{
+ GtkRBNode *node;
+
+ node = tree->root;
+
+ if (_gtk_rbtree_is_nil (node))
+ return NULL;
+
+ while (!_gtk_rbtree_is_nil (node->left))
+ node = node->left;
+
+ return node;
}
GtkRBNode *
g_return_val_if_fail (node != NULL, NULL);
/* Case 1: the node's below us. */
- if (node->right != tree->nil)
+ if (!_gtk_rbtree_is_nil (node->right))
{
node = node->right;
- while (node->left != tree->nil)
+ while (!_gtk_rbtree_is_nil (node->left))
node = node->left;
return node;
}
/* Case 2: it's an ancestor */
- while (node->parent != tree->nil)
+ while (!_gtk_rbtree_is_nil (node->parent))
{
if (node->parent->right == node)
node = node->parent;
g_return_val_if_fail (node != NULL, NULL);
/* Case 1: the node's below us. */
- if (node->left != tree->nil)
+ if (!_gtk_rbtree_is_nil (node->left))
{
node = node->left;
- while (node->right != tree->nil)
+ while (!_gtk_rbtree_is_nil (node->right))
node = node->right;
return node;
}
/* Case 2: it's an ancestor */
- while (node->parent != tree->nil)
+ while (!_gtk_rbtree_is_nil (node->parent))
{
if (node->parent->left == node)
node = node->parent;
{
*new_tree = node->children;
*new_node = (*new_tree)->root;
- while ((*new_node)->left != (*new_tree)->nil)
+ while (!_gtk_rbtree_is_nil ((*new_node)->left))
*new_node = (*new_node)->left;
return;
}
{
*new_tree = (*new_node)->children;
*new_node = (*new_tree)->root;
- while ((*new_node)->right != (*new_tree)->nil)
+ while (!_gtk_rbtree_is_nil ((*new_node)->right))
*new_node = (*new_node)->right;
}
}
}
+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,
GtkRBTreeTraverseFunc func,
gpointer data)
{
- if (node == tree->nil)
+ if (_gtk_rbtree_is_nil (node))
return;
(* func) (tree, node, data);
GtkRBTreeTraverseFunc func,
gpointer data)
{
- if (node == tree->nil)
+ if (_gtk_rbtree_is_nil (node))
return;
_gtk_rbtree_traverse_post_order (tree, node->left, func, data);
}
}
+static inline
+void _fixup_validation (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
+ GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) ||
+ GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID) ||
+ 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
+ {
+ GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
+ }
+}
+
+static inline
+void _fixup_total_count (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ node->total_count = 1 +
+ (node->children != NULL ? node->children->root->total_count : 0) +
+ node->left->total_count + node->right->total_count;
+}
+
+#ifdef G_ENABLE_DEBUG
+static guint
+get_total_count (GtkRBNode *node)
+{
+ guint child_total = 0;
+
+ child_total += (guint) node->left->total_count;
+ child_total += (guint) node->right->total_count;
+
+ if (node->children)
+ child_total += (guint) node->children->root->total_count;
+
+ return child_total + 1;
+}
+
+static guint
+count_total (GtkRBTree *tree,
+ GtkRBNode *node)
+{
+ guint res;
+
+ if (_gtk_rbtree_is_nil (node))
+ return 0;
+
+ res =
+ count_total (tree, node->left) +
+ count_total (tree, node->right) +
+ (guint)1 +
+ (node->children ? count_total (node->children, node->children->root) : 0);
+
+ if (res != node->total_count)
+ g_print ("total count incorrect for node\n");
+
+ if (get_total_count (node) != node->total_count)
+ g_error ("Node has incorrect total count %u, should be %u", node->total_count, get_total_count (node));
+
+ return res;
+}
+
static gint
_count_nodes (GtkRBTree *tree,
- GtkRBNode *node)
+ GtkRBNode *node)
{
gint res;
- if (node == tree->nil)
+ if (_gtk_rbtree_is_nil (node))
return 0;
+ g_assert (node->left);
+ g_assert (node->right);
+
res = (_count_nodes (tree, node->left) +
- _count_nodes (tree, node->right) + 1);
+ _count_nodes (tree, node->right) + 1);
if (res != node->count)
g_print ("Tree failed\n");
return res;
}
-void
-_gtk_rbtree_test (GtkRBTree *tree)
+static void
+_gtk_rbtree_test_height (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");
+ gint computed_offset = 0;
+
+ /* This whole test is sort of a useless truism. */
+
+ if (!_gtk_rbtree_is_nil (node->left))
+ computed_offset += node->left->offset;
+
+ if (!_gtk_rbtree_is_nil (node->right))
+ computed_offset += node->right->offset;
+
+ if (node->children && !_gtk_rbtree_is_nil (node->children->root))
+ computed_offset += node->children->root->offset;
+
+ if (GTK_RBNODE_GET_HEIGHT (node) + computed_offset != node->offset)
+ g_error ("node has broken offset\n");
+
+ if (!_gtk_rbtree_is_nil (node->left))
+ _gtk_rbtree_test_height (tree, node->left);
+
+ if (!_gtk_rbtree_is_nil (node->right))
+ _gtk_rbtree_test_height (tree, node->right);
+
+ if (node->children && !_gtk_rbtree_is_nil (node->children->root))
+ _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) ||
+ GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID) ||
+ 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_print ("Tree failed\n");
+ {
+ g_assert (! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) &&
+ ! GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID));
+ if (!_gtk_rbtree_is_nil (node->left))
+ g_assert (! GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID));
+ if (!_gtk_rbtree_is_nil (node->right))
+ 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 (!_gtk_rbtree_is_nil (node->left))
+ _gtk_rbtree_test_dirty (tree, node->left, GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID));
+ if (!_gtk_rbtree_is_nil (node->right))
+ _gtk_rbtree_test_dirty (tree, node->right, GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID));
+ if (node->children != NULL && !_gtk_rbtree_is_nil (node->children->root))
+ _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 (!_gtk_rbtree_is_nil (node));
+
+ g_assert (node->left != NULL);
+ g_assert (node->right != NULL);
+ g_assert (node->parent != NULL);
+
+ if (!_gtk_rbtree_is_nil (node->left))
+ {
+ g_assert (node->left->parent == node);
+ _gtk_rbtree_test_structure_helper (tree, node->left);
+ }
+ if (!_gtk_rbtree_is_nil (node->right))
+ {
+ 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_height_helper (GtkRBTree *tree,
- GtkRBNode *node,
- gint height)
+_gtk_rbtree_test_structure (GtkRBTree *tree)
{
- if (node == tree->nil)
+ g_assert (tree->root);
+ if (_gtk_rbtree_is_nil (tree->root))
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 (_gtk_rbtree_is_nil (tree->root->parent));
+ _gtk_rbtree_test_structure_helper (tree, tree->root);
+}
- _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);
+static void
+_gtk_rbtree_test (const gchar *where,
+ GtkRBTree *tree)
+{
+ GtkRBTree *tmp_tree;
+
+ if (tree == NULL)
+ return;
+
+ /* Test the entire tree */
+ tmp_tree = tree;
+ while (tmp_tree->parent_tree)
+ tmp_tree = tmp_tree->parent_tree;
+
+ if (_gtk_rbtree_is_nil (tmp_tree->root))
+ 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_total (tmp_tree, tmp_tree->root) == tmp_tree->root->total_count);
}
-void
-_gtk_rbtree_test_height (GtkRBTree *tree,
- gint height)
+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->total_count,
+ (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 (!_gtk_rbtree_is_nil (node->left))
+ {
+ _gtk_rbtree_debug_spew_helper (tree, node->left, depth+1);
+ }
+ if (!_gtk_rbtree_is_nil (node->right))
+ {
+ _gtk_rbtree_debug_spew_helper (tree, node->right, depth+1);
+ }
+}
+
+static void
+_gtk_rbtree_debug_spew (GtkRBTree *tree)
{
- _gtk_rbtree_test_height_helper (tree, tree->root, height);
+ g_return_if_fail (tree != NULL);
+
+ if (_gtk_rbtree_is_nil (tree->root))
+ g_print ("Empty tree...\n");
+ else
+ _gtk_rbtree_debug_spew_helper (tree, tree->root, 0);
}
+#endif /* G_ENABLE_DEBUG */