[gtk+] rbtree: Rewrite to not lose node order
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] rbtree: Rewrite to not lose node order
- Date: Tue, 22 Nov 2011 22:30:32 +0000 (UTC)
commit 6d0499a5002a46600cfe95a7feb4d69d4f6dfb51
Author: Benjamin Otte <otte redhat com>
Date: Tue Nov 22 23:15:53 2011 +0100
rbtree: Rewrite to not lose node order
_gtk_rbtree_reorder() was moving the node's data while reordering. As we
use the node pointer in the a11y code as a hash key, this didn't work.
So this rewrite changes that. As a bonus, it is less code and faster.
Woohoo!
gtk/gtkrbtree.c | 162 +++++++++++++++++++++++++------------------------------
1 files changed, 74 insertions(+), 88 deletions(-)
---
diff --git a/gtk/gtkrbtree.c b/gtk/gtkrbtree.c
index ef2d735..d6dc938 100644
--- a/gtk/gtkrbtree.c
+++ b/gtk/gtkrbtree.c
@@ -767,65 +767,48 @@ _gtk_rbtree_set_fixed_height (GtkRBTree *tree,
while ((node = _gtk_rbtree_next (tree, node)) != NULL);
}
-typedef struct _GtkRBReorder
-{
- GtkRBTree *children;
- gint height;
- gint flags;
- gint order;
- gint invert_order;
- guint total_count;
-} GtkRBReorder;
-
-static int
-gtk_rbtree_reorder_sort_func (gconstpointer a,
- gconstpointer b)
+static void
+reorder_prepare (GtkRBTree *tree,
+ GtkRBNode *node,
+ gpointer data)
{
- return ((GtkRBReorder *) a)->order - ((GtkRBReorder *) b)->order;
+ node->offset -= node->left->offset + node->right->offset;
+ GTK_RBNODE_UNSET_FLAG (node, GTK_RBNODE_DESCENDANTS_INVALID);
}
-static int
-gtk_rbtree_reorder_invert_func (gconstpointer a,
- gconstpointer b)
+static void
+reorder_fixup (GtkRBTree *tree,
+ GtkRBNode *node,
+ gpointer data)
{
- return ((GtkRBReorder *) a)->invert_order - ((GtkRBReorder *) b)->invert_order;
+ 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
-gtk_rbtree_reorder_fixup (GtkRBTree *tree,
- GtkRBNode *node)
+reorder_copy_node (GtkRBTree *tree,
+ GtkRBNode *to,
+ GtkRBNode *from)
{
- if (_gtk_rbtree_is_nil (node))
- return;
-
- node->total_count = 1;
-
- if (!_gtk_rbtree_is_nil (node->left))
- {
- gtk_rbtree_reorder_fixup (tree, node->left);
- node->offset += node->left->offset;
- node->total_count += node->left->total_count;
- }
- if (!_gtk_rbtree_is_nil (node->right))
- {
- gtk_rbtree_reorder_fixup (tree, node->right);
- node->offset += node->right->offset;
- node->total_count += node->right->total_count;
- }
-
- if (node->children)
- {
- node->offset += node->children->root->offset;
- node->total_count += node->children->root->total_count;
- }
-
- if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
- GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID) ||
- 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);
+ 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
@@ -839,59 +822,62 @@ _gtk_rbtree_reorder (GtkRBTree *tree,
gint *new_order,
gint length)
{
- GtkRBReorder reorder = { NULL };
- GArray *array;
+ GtkRBNode **nodes;
GtkRBNode *node;
- gint i;
+ gint i, j;
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);
- }
+ nodes = g_new (GtkRBNode *, length);
- g_array_sort(array, gtk_rbtree_reorder_sort_func);
+ _gtk_rbtree_traverse (tree, tree->root, G_PRE_ORDER, reorder_prepare, NULL);
- /* rewind node*/
- node = _gtk_rbtree_first (tree);
+ 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++)
{
- g_assert (!_gtk_rbtree_is_nil (node));
- 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);
+ GtkRBNode tmp = { 0, };
+ GSList *l, *cycle = NULL;
- node = _gtk_rbtree_next (tree, node);
- }
+ tmp.offset = -1;
- g_array_sort (array, gtk_rbtree_reorder_invert_func);
-
- /* rewind node*/
- node = _gtk_rbtree_first (tree);
+ /* already swapped */
+ if (nodes[i] == NULL)
+ continue;
+ /* no need to swap */
+ if (new_order[i] == i)
+ continue;
- /* 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);
+ /* 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_reorder_fixup (tree, tree->root);
- g_array_free (array, TRUE);
+ _gtk_rbtree_traverse (tree, tree->root, G_POST_ORDER, reorder_fixup, NULL);
+
+ g_free (nodes);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]