For move, test moving between two sequences. Add test for swap.
authorSoren Sandmann <sandmann@redhat.com>
Fri, 16 Feb 2007 06:00:08 +0000 (06:00 +0000)
committerSøren Sandmann Pedersen <ssp@src.gnome.org>
Fri, 16 Feb 2007 06:00:08 +0000 (06:00 +0000)
2007-02-16  Soren Sandmann <sandmann@redhat.com>

* tests/sequence-test.c: For move, test moving between two
sequences. Add test for swap.

* glib/gsequence.c: Replace splay tree with a treap.
(check_node): Add checks for the treap invariants.

svn path=/trunk/; revision=5337

ChangeLog
glib/gsequence.c
tests/sequence-test.c

index fedfc43..ab18c7b 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-02-16  Soren Sandmann <sandmann@redhat.com>
+
+       * tests/sequence-test.c: For move, test moving between two
+       sequences. Add test for swap.
+
+       * glib/gsequence.c: Replace splay tree with a treap.
+       (check_node): Add checks for the treap invariants.
+
 2007-02-10  Hans Breuer  <hans@breuer.org>
 
        * glib/makefile.msc.in : added gsequence.obj
index bf1ddf4..3f97f54 100644 (file)
@@ -72,17 +72,18 @@ static gint           node_get_length    (GSequenceNode            *node);
 static void           node_free          (GSequenceNode            *node,
                                           GSequence                *seq);
 static void           node_cut           (GSequenceNode            *split);
-static void           node_insert_after  (GSequenceNode            *node,
-                                          GSequenceNode            *second);
 static void           node_insert_before (GSequenceNode            *node,
                                           GSequenceNode            *new);
 static void           node_unlink        (GSequenceNode            *node);
+static void           node_join          (GSequenceNode            *left,
+                                         GSequenceNode            *right);
 static void           node_insert_sorted (GSequenceNode            *node,
                                           GSequenceNode            *new,
                                           GSequenceNode            *end,
                                           GSequenceIterCompareFunc  cmp_func,
                                           gpointer                  cmp_data);
 
+
 /*
  * Various helper functions
  */
@@ -551,12 +552,23 @@ g_sequence_move_range (GSequenceIter *dest,
   node_cut (end);
   
   if (first != begin)
-    node_insert_after (node_get_last (first), end);
+    node_join (first, end);
   
   if (dest)
-    node_insert_before (dest, begin);
+    {
+      first = node_get_first (dest);
+      
+      node_cut (dest);
+      
+      node_join (begin, dest);
+      
+      if (dest != first)
+       node_join (first, begin);
+    }
   else
-    node_free (begin, src_seq);
+    {
+      node_free (begin, src_seq);
+    }
 }
 
 /**
@@ -899,18 +911,6 @@ g_sequence_search_iter (GSequence                *seq,
   
   seq->access_prohibited = TRUE;
 
-  /* Create a new temporary sequence and put the dummy node into
-   * that. The reason for this is that the user compare function
-   * will be called with the new node, and if it dereferences, 
-   * "is_end" will be called on it. But that will crash if the
-   * node is not actually in a sequence.
-   *
-   * node_insert_sorted() makes sure the node is unlinked before
-   * is is inserted.
-   *
-   * The reason we need the "iter" versions at all is that that
-   * is the only kind of compare functions GtkTreeView can use.
-   */
   tmp_seq = g_sequence_new (NULL);
   tmp_seq->real_sequence = seq;
   
@@ -1055,6 +1055,7 @@ GSequenceIter *
 g_sequence_get_begin_iter (GSequence *seq)
 {
   g_return_val_if_fail (seq != NULL, NULL);
+
   return node_get_first (seq->end_node);
 }
 
@@ -1104,7 +1105,8 @@ g_sequence_get_iter_at_pos (GSequence *seq,
  *
  * Moves the item pointed to by @src to the position indicated by @dest.
  * After calling this function @dest will point to the position immediately
- * after @src.
+ * after @src. It is allowed for @src and @dest to point into different
+ * sequences.
  * 
  * Since: 2.14
  **/
@@ -1253,7 +1255,8 @@ g_sequence_iter_move (GSequenceIter *iter,
  * @a: a #GSequenceIter
  * @b: a #GSequenceIter
  * 
- * Swaps the items pointed to by @a and @b
+ * Swaps the items pointed to by @a and @b. It is allowed for @a and @b
+ * to point into difference sequences.
  * 
  * Since: 2.14
  **/
@@ -1296,158 +1299,37 @@ g_sequence_swap (GSequenceIter *a,
 }
 
 /*
- * Implementation of the splay tree. 
- */
-
-/* Splay Tree vs. Other Kinds of Trees
+ * Implementation of a treap
  *
- * There are both advantages and disadvantages to using a splay tree vs. some other
- * kind of tree such as a red/black tree or a btree.
- *
- * Advantages of splay trees
- *
- * - They are very simple to implement, especially things like move_range or concatenate
- *   are easy to do for splay trees. The algorithm to split a red/black tree, while still O(log n),
- *   is much more complicated
- *
- * - If we add aggregates at some point, splay trees make it easy to compute the aggregate
- *   for an arbitrary range of the tree. In a red/black tree you would have to pick out
- *   the correct subtrees, then call out to the aggregator function to compute them.
- *      On the other hand, for a splay tree, aggregates would be invalidated on lookups, so you
- *   would call the aggregator much more often. The aggregates could be invalidated lazily though.
- *      In both cases, the aggregator function would be called O(log n) times as a side-effect of
- *   asking for the aggregate of a range.
- *
- * - If you are only using the list API and never the insert_sorted(), the operations on a
- *   splay tree will actually be O(1) rather than O(log n). But this is most likely just
- *   not that interesting in practice since the O(log n) of a BTree is actually very fast.
- *
- * The disadvantages
- *
- * - Splay trees are only amortized O(log n) which means individual operations could take a long
- *   time, which is undesirable in GUI applications
- *
- * - Red/black trees are more widely known since they are tought in CS101 courses.
- *
- * - Red/black trees or btrees are more efficient. Not only is the red/black algorithm faster
- *   in itself, the splaying writes to nodes on lookup which causes dirty pages that the VM
- *   system will have to launder.
- *
- * - Splay trees are not necessarily balanced at all which means straight-forward recursive
- *   algorithms can use lots of stack.
- *
- * It is likely worth investigating whether a BTree would be a better choice, in particular the
- * algorithm to split a BTree may not be all that complicated given that split/join for nodes
- * will have to be implemented anyway.
  *
  */
-
-static void
-node_update_fields (GSequenceNode *node)
+static guint
+get_priority (GSequenceNode *node)
 {
-  int n_nodes = 1;
-  
-  g_assert (node != NULL);
-
-  if (node->left)
-    n_nodes += node->left->n_nodes;
+  guint key = GPOINTER_TO_UINT (node);
 
-  if (node->right)
-    n_nodes += node->right->n_nodes;
-
-  node->n_nodes = n_nodes;
-}
-
-#define NODE_LEFT_CHILD(n)  (((n)->parent) && ((n)->parent->left) == (n))
-#define NODE_RIGHT_CHILD(n) (((n)->parent) && ((n)->parent->right) == (n))
+  /* This hash function is based on one found on Thomas Wang's
+   * web page at
+   *
+   *    http://www.concentric.net/~Ttwang/tech/inthash.htm
+   *
+   */
+  key = (key << 15) - key - 1;
+  key = key ^ (key >> 12);
+  key = key + (key << 2);
+  key = key ^ (key >> 4);
+  key = key + (key << 3) + (key << 11);
+  key = key ^ (key >> 16);
 
-static void
-node_rotate (GSequenceNode *node)
-{
-  GSequenceNode *tmp, *old;
-  
-  g_assert (node->parent);
-  g_assert (node->parent != node);
-  
-  if (NODE_LEFT_CHILD (node))
-    {
-      /* rotate right */
-      tmp = node->right;
-      
-      node->right = node->parent;
-      node->parent = node->parent->parent;
-      if (node->parent)
-        {
-          if (node->parent->left == node->right)
-            node->parent->left = node;
-          else
-            node->parent->right = node;
-        }
-      
-      g_assert (node->right);
-      
-      node->right->parent = node;
-      node->right->left = tmp;
-      
-      if (node->right->left)
-        node->right->left->parent = node->right;
-      
-      old = node->right;
-    }
-  else
-    {
-      /* rotate left */
-      tmp = node->left;
-      
-      node->left = node->parent;
-      node->parent = node->parent->parent;
-      if (node->parent)
-        {
-          if (node->parent->right == node->left)
-            node->parent->right = node;
-          else
-            node->parent->left = node;
-        }
-      
-      g_assert (node->left);
-      
-      node->left->parent = node;
-      node->left->right = tmp;
-      
-      if (node->left->right)
-        node->left->right->parent = node->left;
-      
-      old = node->left;
-    }
-  
-  node_update_fields (old);
-  node_update_fields (node);
+  /* We rely on 0 being less than all other priorities */
+  return key? key : 1;
 }
 
 static GSequenceNode *
-splay (GSequenceNode *node)
+find_root (GSequenceNode *node)
 {
   while (node->parent)
-    {
-      if (!node->parent->parent)
-        {
-          /* zig */
-          node_rotate (node);
-        }
-      else if ((NODE_LEFT_CHILD (node) && NODE_LEFT_CHILD (node->parent)) ||
-               (NODE_RIGHT_CHILD (node) && NODE_RIGHT_CHILD (node->parent)))
-        {
-          /* zig-zig */
-          node_rotate (node->parent);
-          node_rotate (node);
-        }
-      else
-        {
-          /* zig-zag */
-          node_rotate (node);
-          node_rotate (node);
-        }
-    }
+    node = node->parent;
   
   return node;
 }
@@ -1457,21 +1339,19 @@ node_new (gpointer data)
 {
   GSequenceNode *node = g_slice_new0 (GSequenceNode);
   
-  node->parent = NULL;
-  node->parent = NULL;
+  node->n_nodes = 1;
+  node->data = data;
   node->left = NULL;
   node->right = NULL;
-  
-  node->data = data;
-  node->n_nodes = 1;
+  node->parent = NULL;
   
   return node;
 }
 
 static GSequenceNode *
-find_min (GSequenceNode *node)
+node_get_first (GSequenceNode *node)
 {
-  splay (node);
+  node = find_root (node);
   
   while (node->left)
     node = node->left;
@@ -1480,9 +1360,9 @@ find_min (GSequenceNode *node)
 }
 
 static GSequenceNode *
-find_max (GSequenceNode *node)
+node_get_last (GSequenceNode *node)
 {
-  splay (node);
+  node = find_root (node);
   
   while (node->right)
     node = node->right;
@@ -1490,96 +1370,104 @@ find_max (GSequenceNode *node)
   return node;
 }
 
-static GSequenceNode *
-node_get_first (GSequenceNode *node)
-{
-  return splay (find_min (node));
-}
+#define NODE_LEFT_CHILD(n)  (((n)->parent) && ((n)->parent->left) == (n))
+#define NODE_RIGHT_CHILD(n) (((n)->parent) && ((n)->parent->right) == (n))
 
 static GSequenceNode *
-node_get_last (GSequenceNode *node)
+node_get_next (GSequenceNode *node)
 {
-  return splay (find_max (node));
-}
+  GSequenceNode *n = node;
 
-static gint
-get_n_nodes (GSequenceNode *node)
-{
-  if (node)
-    return node->n_nodes;
+  if (n->right)
+    {
+      n = n->right;
+      while (n->left)
+       n = n->left;
+    }
   else
-    return 0;
+    {
+      while (NODE_RIGHT_CHILD (n))
+       n = n->parent;
+      
+      if (n->parent)
+       n = n->parent;
+      else
+       n = node;
+    }
+  
+  return n;
 }
 
 static GSequenceNode *
-node_get_by_pos (GSequenceNode *node,
-                gint           pos)
+node_get_prev (GSequenceNode *node)
 {
-  gint i;
-  
-  g_assert (node != NULL);
+  GSequenceNode *n = node;
   
-  splay (node);
-  
-  while ((i = get_n_nodes (node->left)) != pos)
+  if (n->left)
     {
-      if (i < pos)
-        {
-          node = node->right;
-          pos -= (i + 1);
-        }
+      n = n->left;
+      while (n->right)
+       n = n->right;
+    }
+  else
+    {
+      while (NODE_LEFT_CHILD (n))
+       n = n->parent;
+      
+      if (n->parent)
+       n = n->parent;
       else
-        {
-          node = node->left;
-          g_assert (node->parent != NULL);
-        }
+       n = node;
     }
   
-  return splay (node);
+  return n;
 }
 
-static GSequenceNode *
-node_get_prev (GSequenceNode *node)
+#define N_NODES(n) ((n)? (n)->n_nodes : 0)
+
+static gint
+node_get_pos (GSequenceNode *node)
 {
-  splay (node);
+  int n_smaller = 0;
   
   if (node->left)
+    n_smaller = node->left->n_nodes;
+  
+  while (node)
     {
-      node = node->left;
-      while (node->right)
-        node = node->right;
+      if (NODE_RIGHT_CHILD (node))
+       n_smaller += N_NODES (node->parent->left) + 1;
+      
+      node = node->parent;
     }
   
-  return splay (node);
+  return n_smaller;
 }
 
 static GSequenceNode *
-node_get_next (GSequenceNode *node)
+node_get_by_pos (GSequenceNode *node,
+                gint           pos)
 {
-  splay (node);
+  int i;
   
-  if (node->right)
-    {
-      node = node->right;
-      while (node->left)
-        node = node->left;
-   }
+  node = find_root (node);
   
-  return splay (node);
-}
-
-static gint
-node_get_pos (GSequenceNode *node)
-{
-  splay (node);
+  while ((i = N_NODES (node->left)) != pos)
+    {
+      if (i < pos)
+        {
+         node = node->right;
+         pos -= (i + 1);
+        }
+      else
+        {
+         node = node->left;
+       }
+    }
   
-  return get_n_nodes (node->left);
+  return node;
 }
 
-/* Return closest node _strictly_ bigger than @needle. This node
- * always exists because the tree has an explicit end node).
- * This end node of @haystack must be passed in @end.
- */
 static GSequenceNode *
 node_find_closest (GSequenceNode            *haystack,
                    GSequenceNode            *needle,
@@ -1590,9 +1478,7 @@ node_find_closest (GSequenceNode            *haystack,
   GSequenceNode *best;
   gint c;
   
-  g_assert (haystack);
-  
-  haystack = splay (haystack);
+  haystack = find_root (haystack);
   
   do
     {
@@ -1626,140 +1512,211 @@ node_find_closest (GSequenceNode            *haystack,
   return best;
 }
 
-static void
-node_free (GSequenceNode *node,
-           GSequence     *seq)
+static gint
+node_get_length    (GSequenceNode            *node)
 {
-  GPtrArray *stack = g_ptr_array_new ();
+  node = find_root (node);
   
-  splay (node);
+  return node->n_nodes;
+}
 
-  g_ptr_array_add (stack, node);
-  
-  while (stack->len > 0)
+static void
+real_node_free (GSequenceNode *node,
+               GSequence     *seq)
+{
+  if (node)
     {
-      node = g_ptr_array_remove_index (stack, stack->len - 1);
+      real_node_free (node->left, seq);
+      real_node_free (node->right, seq);
       
-      if (node)
-        {
-         g_ptr_array_add (stack, node->right);
-         g_ptr_array_add (stack, node->left);
-          
-          if (seq && seq->data_destroy_notify && node != seq->end_node)
-            seq->data_destroy_notify (node->data);
-          
-          g_slice_free (GSequenceNode, node);
-        }
+      if (seq && seq->data_destroy_notify && node != seq->end_node)
+       seq->data_destroy_notify (node->data);
+      
+      g_slice_free (GSequenceNode, node);
     }
-  
-  g_ptr_array_free (stack, TRUE);
 }
 
-/* Splits into two trees. @node will be part of the right tree
- */
 static void
-node_cut (GSequenceNode *node)
+node_free (GSequenceNode *node,
+          GSequence *seq)
 {
-  splay (node);
+  node = find_root (node);
   
-  g_assert (node->parent == NULL);
+  real_node_free (node, seq);
+}
+
+static void
+node_update_fields (GSequenceNode *node)
+{
+  int n_nodes = 1;
   
-  if (node->left)
-    node->left->parent = NULL;
+  n_nodes += N_NODES (node->left);
+  n_nodes += N_NODES (node->right);
   
-  node->left = NULL;
-  node_update_fields (node);
+  node->n_nodes = n_nodes;
 }
 
 static void
-node_insert_before (GSequenceNode *node,
-                    GSequenceNode *new)
+node_rotate (GSequenceNode *node)
 {
-  g_assert (node != NULL);
-  g_assert (new != NULL);
+  GSequenceNode *tmp, *old;
+  
+  g_assert (node->parent);
+  g_assert (node->parent != node);
   
-  splay (node);
+  if (NODE_LEFT_CHILD (node))
+    {
+      /* rotate right */
+      tmp = node->right;
   
-  new = splay (find_min (new));
-  g_assert (new->left == NULL);
+      node->right = node->parent;
+      node->parent = node->parent->parent;
+      if (node->parent)
+        {
+          if (node->parent->left == node->right)
+            node->parent->left = node;
+          else
+            node->parent->right = node;
+        }
   
-  if (node->left)
-    node->left->parent = new;
+      g_assert (node->right);
   
-  new->left = node->left;
-  new->parent = node;
+      node->right->parent = node;
+      node->right->left = tmp;
   
-  node->left = new;
+      if (node->right->left)
+        node->right->left->parent = node->right;
+      
+      old = node->right;
+    }
+  else
+    {
+      /* rotate left */
+      tmp = node->left;
+
+      node->left = node->parent;
+      node->parent = node->parent->parent;
+      if (node->parent)
+       {
+          if (node->parent->right == node->left)
+            node->parent->right = node;
+          else
+            node->parent->left = node;
+        }
+  
+      g_assert (node->left);
+  
+      node->left->parent = node;
+      node->left->right = tmp;
   
-  node_update_fields (new);
+      if (node->left->right)
+        node->left->right->parent = node->left;
+  
+      old = node->left;
+    }
+  
+  node_update_fields (old);
   node_update_fields (node);
 }
 
 static void
-node_insert_after (GSequenceNode *node,
-                   GSequenceNode *new)
+node_update_fields_deep (GSequenceNode *node)
 {
-  g_assert (node != NULL);
-  g_assert (new != NULL);
-  
-  splay (node);
+  if (node)
+    {
+      node_update_fields (node);
+      
+      node_update_fields_deep (node->parent);
+    }
+}
+
+static void
+rotate_down (GSequenceNode *node,
+            guint          priority)
+{
+  guint left, right;
   
-  new = splay (find_max (new));
-  g_assert (new->right == NULL);
-  g_assert (node->parent == NULL);
+  left = node->left ? get_priority (node->left)  : 0;
+  right = node->right ? get_priority (node->right) : 0;
   
-  if (node->right)
-    node->right->parent = new;
+  while (priority < left || priority < right)
+    {
+      if (left > right)
+       node_rotate (node->left);
+      else
+       node_rotate (node->right);
   
-  new->right = node->right;
-  new->parent = node;
+      left = node->left ? get_priority (node->left)  : 0;
+      right = node->right ? get_priority (node->right) : 0;
+    }
+}
+
+static void
+node_cut (GSequenceNode *node)
+{
+  while (node->parent)
+    node_rotate (node);
   
-  node->right = new;
+  if (node->left)
+    node->left->parent = NULL;
   
-  node_update_fields (new);
+  node->left = NULL;
   node_update_fields (node);
+  
+  rotate_down (node, get_priority (node));
 }
 
-static gint
-node_get_length (GSequenceNode    *node)
+static void
+node_join (GSequenceNode *left,
+          GSequenceNode *right)
 {
-  g_assert (node != NULL);
+  GSequenceNode *fake = node_new (NULL);
+      
+  fake->left = find_root (left);
+  fake->right = find_root (right);
+  fake->left->parent = fake;
+  fake->right->parent = fake;
+      
+  node_update_fields (fake);
   
-  splay (node);
-  return node->n_nodes;
+  node_unlink (fake);
+  
+  node_free (fake, NULL);
 }
 
 static void
-node_unlink (GSequenceNode *node)
+node_insert_before (GSequenceNode *node,
+                   GSequenceNode *new)
 {
-  GSequenceNode *right, *left;
+  new->left = node->left;
+  if (new->left)
+    new->left->parent = new;
   
-  splay (node);
+  new->parent = node;
+  node->left = new;
   
-  left = node->left;
-  right = node->right;
+  node_update_fields_deep (new);
   
-  node->parent = node->left = node->right = NULL;
-  node_update_fields (node);
+  while (new->parent && get_priority (new) > get_priority (new->parent))
+    node_rotate (new);
   
-  if (right)
-    {
-      right->parent = NULL;
-      
-      right = node_get_first (right);
-      g_assert (right->left == NULL);
-      
-      right->left = left;
-      if (left)
-        {
-          left->parent = right;
-          node_update_fields (right);
-        }
-    }
-  else if (left)
-    {
-      left->parent = NULL;
-    }
+  rotate_down (new, get_priority (new));
+}
+
+static void
+node_unlink (GSequenceNode *node)
+{
+  rotate_down (node, 0);
+  
+  if (NODE_RIGHT_CHILD (node))
+    node->parent->right = NULL;
+  else if (NODE_LEFT_CHILD (node))
+    node->parent->left = NULL;
+  
+  if (node->parent)
+    node_update_fields_deep (node->parent);
+  
+  node->parent = NULL;
 }
 
 static void
@@ -1778,49 +1735,60 @@ node_insert_sorted (GSequenceNode            *node,
   node_insert_before (closest, new);
 }
 
-static gint
-node_calc_height (GSequenceNode *node)
+/* Self-test function */
+static int
+count_nodes (GSequenceNode *node)
 {
-  gint left_height;
-  gint right_height;
-  
-  if (node)
-    {
-      left_height = 0;
-      right_height = 0;
-      
-      if (node->left)
-        left_height = node_calc_height (node->left);
-      
-      if (node->right)
-        right_height = node_calc_height (node->right);
-      
-      return MAX (left_height, right_height) + 1;
-    }
+  if (!node)
+    return 0;
   
-  return 0;
+  return count_nodes (node->left) + count_nodes (node->right) + 1;
 }
-
-/* Self-test function */
+  
 static void
 check_node (GSequenceNode *node)
 {
   if (node)
     {
       g_assert (node->parent != node);
-      g_assert (node->n_nodes ==
-                1 + get_n_nodes (node->left) + get_n_nodes (node->right));
+      if (node->parent)
+       g_assert (node->parent->left == node || node->parent->right == node);
+      g_assert (node->n_nodes == count_nodes (node));
+      if (node->left)
+         g_assert (get_priority (node) >= get_priority (node->left));
+      if (node->right)
+         g_assert (get_priority (node) >= get_priority (node->right));
       check_node (node->left);
       check_node (node->right);
     }
 }
 
+static gint
+compute_height (GSequenceNode *node)
+{
+  int left, right;
+  
+  if (!node)
+    return 0;
+
+  left = compute_height (node->left);
+  right = compute_height (node->right);
+
+  return MAX (left, right) + 1;
+}
+
 void
 g_sequence_self_test_internal_to_glib_dont_use (GSequence *seq)
 {
-  GSequenceNode *node = splay (seq->end_node);
+  GSequenceNode *node = find_root (seq->end_node);
   
   check_node (node);
+   
+  node = node_get_last (node);
+  
+  g_assert (seq->end_node == node);
+  g_assert (node->data == seq);
+
 }
 
 #define __G_SEQUENCE_C__
index 50e7d95..2458f88 100644 (file)
@@ -2,26 +2,25 @@
 #include <glib.h>
 #include <stdlib.h>
 
-enum
-  {
-    NEW, FREE, GET_LENGTH, FOREACH, FOREACH_RANGE, SORT, SORT_ITER,
-    
-    /* Getting iters */
-    GET_BEGIN_ITER, GET_END_ITER, GET_ITER_AT_POS, APPEND, PREPEND,
-    INSERT_BEFORE, MOVE, INSERT_SORTED, INSERT_SORTED_ITER, SORT_CHANGED,
-    SORT_CHANGED_ITER, REMOVE, REMOVE_RANGE, MOVE_RANGE, SEARCH, SEARCH_ITER,
-    
-    /* dereferencing */
-    GET, SET,
-    
-    /* operations on GSequenceIter * */
-    ITER_IS_BEGIN, ITER_IS_END, ITER_NEXT, ITER_PREV, ITER_GET_POSITION,
-    ITER_MOVE, ITER_GET_SEQUENCE,
-    
-    /* search */
-    ITER_COMPARE, RANGE_GET_MIDPOINT,
-    N_OPS
-  } Op;
+enum {
+  NEW, FREE, GET_LENGTH, FOREACH, FOREACH_RANGE, SORT, SORT_ITER,
+  
+  /* Getting iters */
+  GET_BEGIN_ITER, GET_END_ITER, GET_ITER_AT_POS, APPEND, PREPEND,
+  INSERT_BEFORE, MOVE, SWAP, INSERT_SORTED, INSERT_SORTED_ITER, SORT_CHANGED,
+  SORT_CHANGED_ITER, REMOVE, REMOVE_RANGE, MOVE_RANGE, SEARCH, SEARCH_ITER,
+  
+  /* dereferencing */
+  GET, SET,
+  
+  /* operations on GSequenceIter * */
+  ITER_IS_BEGIN, ITER_IS_END, ITER_NEXT, ITER_PREV, ITER_GET_POSITION,
+  ITER_MOVE, ITER_GET_SEQUENCE,
+  
+  /* search */
+  ITER_COMPARE, RANGE_GET_MIDPOINT,
+  N_OPS
+};
 
 typedef struct SequenceInfo
 {
@@ -70,7 +69,10 @@ check_integrity (SequenceInfo *info)
   i = 0;
   while (iter != g_sequence_get_end_iter (info->sequence))
     {
+      Item *item;
       g_assert (list->data == iter);
+      item = get_item (list->data);
+      g_assert (item->seq == info);
       
       iter = g_sequence_iter_next (iter);
       list = list->next;
@@ -312,7 +314,8 @@ run_random_tests (guint32 seed)
 {
 #define N_ITERATIONS 60000
 #define N_SEQUENCES 8
-  
+#define N_TIMES 24
+    
   SequenceInfo sequences[N_SEQUENCES];
   int k;
   
@@ -501,8 +504,10 @@ run_random_tests (guint32 seed)
        case MOVE:
          {
            GList *link1, *link2;
-           GSequenceIter *iter1 = get_random_iter (seq, &link1);
-           GSequenceIter *iter2 = get_random_iter (seq, &link2);
+           SequenceInfo *seq1 = RANDOM_SEQUENCE();
+           SequenceInfo *seq2 = RANDOM_SEQUENCE();
+           GSequenceIter *iter1 = get_random_iter (seq1, &link1);
+           GSequenceIter *iter2 = get_random_iter (seq2, &link2);
            
            if (!g_sequence_iter_is_end (iter1))
              {
@@ -511,9 +516,14 @@ run_random_tests (guint32 seed)
                if (!link2)
                  g_assert (g_sequence_iter_is_end (iter2));
                
-               queue_insert_before (seq, link2, link1->data);
+               queue_insert_before (seq2, link2, link1->data);
                
-               g_queue_delete_link (seq->queue, link1);
+               g_queue_delete_link (seq1->queue, link1);
+
+               get_item (iter1)->seq = seq2;
+               
+               seq1->n_items--;
+               seq2->n_items++;
              }
            
            check_integrity (seq);
@@ -525,6 +535,30 @@ run_random_tests (guint32 seed)
              g_sequence_move (iter1, iter1);
          }
          break;
+       case SWAP:
+         {
+           GList *link1, *link2;
+           SequenceInfo *seq1 = RANDOM_SEQUENCE();
+           SequenceInfo *seq2 = RANDOM_SEQUENCE();
+           GSequenceIter *iter1 = get_random_iter (seq1, &link1);
+           GSequenceIter *iter2 = get_random_iter (seq2, &link2);
+           
+           if (!g_sequence_iter_is_end (iter1) &&
+               !g_sequence_iter_is_end (iter2))
+             {
+               gpointer tmp;
+
+               g_sequence_swap (iter1, iter2);
+
+               get_item (iter1)->seq = seq2;
+               get_item (iter2)->seq = seq1;
+               
+               tmp = link1->data;
+               link1->data = link2->data;
+               link2->data = tmp;
+             }
+         }
+         break;
        case INSERT_SORTED:
          {
            int i;
@@ -535,7 +569,7 @@ run_random_tests (guint32 seed)
            
            check_sorted (seq);
            
-           for (i = 0; i < 15; ++i)
+           for (i = 0; i < N_TIMES; ++i)
              {
                GSequenceIter *iter =
                  g_sequence_insert_sorted (seq->sequence, new_item(seq), compare_items, NULL);
@@ -558,7 +592,7 @@ run_random_tests (guint32 seed)
            
            check_sorted (seq);
            
-           for (i = 0; i < 15; ++i)
+           for (i = 0; i < N_TIMES; ++i)
              {
                GSequenceIter *iter;
 
@@ -584,7 +618,7 @@ run_random_tests (guint32 seed)
            
            check_sorted (seq);
            
-           for (i = 0; i < 15; ++i)
+           for (i = 0; i < N_TIMES; ++i)
              {
                GList *link;
                GSequenceIter *iter = get_random_iter (seq, &link);
@@ -611,7 +645,7 @@ run_random_tests (guint32 seed)
            
            check_sorted (seq);
            
-           for (i = 0; i < 15; ++i)
+           for (i = 0; i < N_TIMES; ++i)
              {
                GList *link;
                GSequenceIter *iter = get_random_iter (seq, &link);
@@ -634,7 +668,7 @@ run_random_tests (guint32 seed)
          {
            int i;
            
-           for (i = 0; i < 15; ++i)
+           for (i = 0; i < N_TIMES; ++i)
              {
                GList *link;
                GSequenceIter *iter = get_random_iter (seq, &link);
@@ -796,7 +830,7 @@ run_random_tests (guint32 seed)
                g_assert (g_sequence_get (iter) == item);
                
                /* Make sure that existing items are freed */
-               for (i = 0; i < 15; ++i)
+               for (i = 0; i < N_TIMES; ++i)
                  g_sequence_set (iter, new_item (seq));
                
                check_integrity (seq);
@@ -1113,6 +1147,8 @@ test_insert_sorted_non_pointer (void)
          g_sequence_insert_sorted_iter (seq, GINT_TO_POINTER (g_random_int()),
                                         compare_iter, NULL);
        }
+
+      g_sequence_self_test_internal_to_glib_dont_use (seq);
       
       g_sequence_free (seq);
     }
@@ -1130,15 +1166,23 @@ test_stable_sort (void)
   GSequenceIter *iter;
   
   for (i = 0; i < N_ITEMS; ++i)
-    iters[i] = g_sequence_append (seq, GINT_TO_POINTER (3000));
-  
+    {
+      iters[i] = g_sequence_append (seq, GINT_TO_POINTER (3000)); 
+      g_sequence_self_test_internal_to_glib_dont_use (seq);
+      g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
+   }
+
   i = 0;
   iter = g_sequence_get_begin_iter (seq);
+  g_assert (g_sequence_iter_get_sequence (iter) == seq);
+  g_sequence_self_test_internal_to_glib_dont_use (seq);
   while (!g_sequence_iter_is_end (iter))
     {
+      g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
       g_assert (iters[i++] == iter);
       
       iter = g_sequence_iter_next (iter);
+      g_sequence_self_test_internal_to_glib_dont_use (seq);
     }
   
   g_sequence_sort (seq, compare, NULL);
@@ -1147,13 +1191,22 @@ test_stable_sort (void)
   iter = g_sequence_get_begin_iter (seq);
   while (!g_sequence_iter_is_end (iter))
     {
-      g_assert (iters[i++] == iter);
+      g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
+      g_assert (iters[i] == iter);
       
       iter = g_sequence_iter_next (iter);
+      g_sequence_self_test_internal_to_glib_dont_use (seq);
+
+      i++;
     }
   
   for (i = N_ITEMS - 1; i >= 0; --i)
-    g_sequence_sort_changed (iters[i], compare, NULL);
+    {
+      g_sequence_self_test_internal_to_glib_dont_use (seq);
+      g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
+      g_assert (g_sequence_get_end_iter (seq) != iters[i]);
+      g_sequence_sort_changed (iters[i], compare, NULL);
+    }
   
   i = 0;
   iter = g_sequence_get_begin_iter (seq);
@@ -1162,6 +1215,7 @@ test_stable_sort (void)
       g_assert (iters[i++] == iter);
       
       iter = g_sequence_iter_next (iter);
+      g_sequence_self_test_internal_to_glib_dont_use (seq);
     }
 }