]> Pileus Git - ~andy/gtk/blobdiff - gtk/gtkrbtree.c
stylecontext: Do invalidation on first resize container
[~andy/gtk] / gtk / gtkrbtree.c
index 6304ee875cfc8b0a74636112fab886c312e6fcfa..d3e1fef7a61b37624aac786e780daa1db567e56d 100644 (file)
@@ -12,9 +12,7 @@
  * Library General Public License for more details.
  *
  * You should have received a copy of the GNU Library General Public
- * License along with this library; if not, write to the
- * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
- * Boston, MA 02111-1307, USA.
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
 #include "config.h"
@@ -61,9 +59,9 @@ _gtk_rbnode_new (GtkRBTree *tree,
 {
   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;
@@ -95,24 +93,20 @@ _gtk_rbnode_rotate_left (GtkRBTree *tree,
                         GtkRBNode *node)
 {
   gint node_height, right_height;
-  GtkRBNode *right = node->right;
+  GtkRBNode *right;
 
   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 (!_gtk_rbtree_is_nil (right->left))
     right->left->parent = node;
 
-  if (!_gtk_rbtree_is_nil (right))
-    right->parent = node->parent;
+  right->parent = node->parent;
   if (!_gtk_rbtree_is_nil (node->parent))
     {
       if (node == node->parent->left)
@@ -124,22 +118,15 @@ _gtk_rbnode_rotate_left (GtkRBTree *tree,
     }
 
   right->left = node;
-  if (!_gtk_rbtree_is_nil (node))
-    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);
@@ -152,25 +139,21 @@ _gtk_rbnode_rotate_right (GtkRBTree *tree,
                          GtkRBNode *node)
 {
   gint node_height, left_height;
-  GtkRBNode *left = node->left;
+  GtkRBNode *left;
 
   g_return_if_fail (!_gtk_rbtree_is_nil (node));
+  g_return_if_fail (!_gtk_rbtree_is_nil (node->left));
+
+  left = 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);
+  node_height = GTK_RBNODE_GET_HEIGHT (node);
+  left_height = GTK_RBNODE_GET_HEIGHT (left);
   
   node->left = left->right;
   if (!_gtk_rbtree_is_nil (left->right))
     left->right->parent = node;
 
-  if (!_gtk_rbtree_is_nil (left))
-    left->parent = node->parent;
+  left->parent = node->parent;
   if (!_gtk_rbtree_is_nil (node->parent))
     {
       if (node == node->parent->right)
@@ -185,22 +168,15 @@ _gtk_rbnode_rotate_right (GtkRBTree *tree,
 
   /* link node and left */
   left->right = node;
-  if (!_gtk_rbtree_is_nil (node))
-    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);
@@ -357,9 +333,8 @@ _gtk_rbtree_new (void)
   retval->parent_tree = NULL;
   retval->parent_node = NULL;
 
-  retval->nil = (GtkRBNode *) &nil;
+  retval->root = (GtkRBNode *) &nil;
 
-  retval->root = retval->nil;
   return retval;
 }
 
@@ -473,11 +448,11 @@ _gtk_rbtree_insert_after (GtkRBTree *tree,
     }
   /* 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
@@ -541,11 +516,11 @@ _gtk_rbtree_insert_before (GtkRBTree *tree,
 
   /* 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
@@ -681,8 +656,8 @@ _gtk_rbtree_node_mark_valid (GtkRBTree *tree,
       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_rbtree_is_nil (node->left) && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
-         (!_gtk_rbtree_is_nil (node->right) && GTK_RBNODE_FLAG_SET (node->right, 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);
@@ -790,65 +765,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_rbtree_is_nil (node->right) && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_INVALID)) ||
-      (!_gtk_rbtree_is_nil (node->left) && 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
@@ -862,61 +820,89 @@ _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);
 }
 
+/**
+ * _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
 _gtk_rbtree_node_find_offset (GtkRBTree *tree,
@@ -987,11 +973,11 @@ _gtk_rbtree_node_get_index (GtkRBTree *tree,
   return retval;
 }
 
-gint
-_gtk_rbtree_real_find_offset (GtkRBTree  *tree,
-                             gint        height,
-                             GtkRBTree **new_tree,
-                             GtkRBNode **new_node)
+static gint
+gtk_rbtree_real_find_offset (GtkRBTree  *tree,
+                            gint        height,
+                            GtkRBTree **new_tree,
+                            GtkRBNode **new_node)
 {
   GtkRBNode *tmp_node;
 
@@ -1035,14 +1021,14 @@ _gtk_rbtree_real_find_offset (GtkRBTree  *tree,
          *new_node = tmp_node;
          return (height - tmp_node->left->offset);
        }
-      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);
+      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;
@@ -1051,9 +1037,9 @@ _gtk_rbtree_real_find_offset (GtkRBTree  *tree,
 
 gint
 _gtk_rbtree_find_offset (GtkRBTree  *tree,
-                             gint        height,
-                             GtkRBTree **new_tree,
-                             GtkRBNode **new_node)
+                        gint        height,
+                        GtkRBTree **new_tree,
+                        GtkRBNode **new_node)
 {
   g_assert (tree);
 
@@ -1065,7 +1051,7 @@ _gtk_rbtree_find_offset (GtkRBTree  *tree,
 
       return 0;
     }
-  return _gtk_rbtree_real_find_offset (tree, height, new_tree, new_node);
+  return gtk_rbtree_real_find_offset (tree, height, new_tree, new_node);
 }
 
 gboolean
@@ -1467,8 +1453,8 @@ void _fixup_validation (GtkRBTree *tree,
 {
   if (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
       GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) ||
-      (!_gtk_rbtree_is_nil (node->left) && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
-      (!_gtk_rbtree_is_nil (node->right) && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_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);
@@ -1586,8 +1572,8 @@ _gtk_rbtree_test_dirty (GtkRBTree *tree,
     {
       g_assert (GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_COLUMN_INVALID) ||
                GTK_RBNODE_FLAG_SET (node, GTK_RBNODE_INVALID) ||
-               (!_gtk_rbtree_is_nil (node->left) && GTK_RBNODE_FLAG_SET (node->left, GTK_RBNODE_DESCENDANTS_INVALID)) ||
-               (!_gtk_rbtree_is_nil (node->right) && GTK_RBNODE_FLAG_SET (node->right, GTK_RBNODE_DESCENDANTS_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
@@ -1666,8 +1652,6 @@ _gtk_rbtree_test (const gchar *where,
   while (tmp_tree->parent_tree)
     tmp_tree = tmp_tree->parent_tree;
   
-  g_assert (tmp_tree->nil != NULL);
-
   if (_gtk_rbtree_is_nil (tmp_tree->root))
     return;