For move, test moving between two sequences. Add test for swap.

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
This commit is contained in:
Soren Sandmann 2007-02-16 06:00:08 +00:00 committed by Søren Sandmann Pedersen
parent c6efde4f62
commit f13d070e20
3 changed files with 427 additions and 397 deletions

View File

@ -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> 2007-02-10 Hans Breuer <hans@breuer.org>
* glib/makefile.msc.in : added gsequence.obj * glib/makefile.msc.in : added gsequence.obj

View File

@ -72,17 +72,18 @@ static gint node_get_length (GSequenceNode *node);
static void node_free (GSequenceNode *node, static void node_free (GSequenceNode *node,
GSequence *seq); GSequence *seq);
static void node_cut (GSequenceNode *split); static void node_cut (GSequenceNode *split);
static void node_insert_after (GSequenceNode *node,
GSequenceNode *second);
static void node_insert_before (GSequenceNode *node, static void node_insert_before (GSequenceNode *node,
GSequenceNode *new); GSequenceNode *new);
static void node_unlink (GSequenceNode *node); static void node_unlink (GSequenceNode *node);
static void node_join (GSequenceNode *left,
GSequenceNode *right);
static void node_insert_sorted (GSequenceNode *node, static void node_insert_sorted (GSequenceNode *node,
GSequenceNode *new, GSequenceNode *new,
GSequenceNode *end, GSequenceNode *end,
GSequenceIterCompareFunc cmp_func, GSequenceIterCompareFunc cmp_func,
gpointer cmp_data); gpointer cmp_data);
/* /*
* Various helper functions * Various helper functions
*/ */
@ -551,12 +552,23 @@ g_sequence_move_range (GSequenceIter *dest,
node_cut (end); node_cut (end);
if (first != begin) if (first != begin)
node_insert_after (node_get_last (first), end); node_join (first, end);
if (dest) 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 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; 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 = g_sequence_new (NULL);
tmp_seq->real_sequence = seq; tmp_seq->real_sequence = seq;
@ -1055,6 +1055,7 @@ GSequenceIter *
g_sequence_get_begin_iter (GSequence *seq) g_sequence_get_begin_iter (GSequence *seq)
{ {
g_return_val_if_fail (seq != NULL, NULL); g_return_val_if_fail (seq != NULL, NULL);
return node_get_first (seq->end_node); 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. * 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 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 * Since: 2.14
**/ **/
@ -1253,7 +1255,8 @@ g_sequence_iter_move (GSequenceIter *iter,
* @a: a #GSequenceIter * @a: a #GSequenceIter
* @b: 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 * Since: 2.14
**/ **/
@ -1296,158 +1299,37 @@ g_sequence_swap (GSequenceIter *a,
} }
/* /*
* Implementation of the splay tree. * Implementation of a treap
*/
/* Splay Tree vs. Other Kinds of Trees
* *
* 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 guint
static void get_priority (GSequenceNode *node)
node_update_fields (GSequenceNode *node)
{ {
int n_nodes = 1; guint key = GPOINTER_TO_UINT (node);
g_assert (node != NULL);
if (node->left) /* This hash function is based on one found on Thomas Wang's
n_nodes += node->left->n_nodes; * 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);
if (node->right) /* We rely on 0 being less than all other priorities */
n_nodes += node->right->n_nodes; return key? key : 1;
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))
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);
} }
static GSequenceNode * static GSequenceNode *
splay (GSequenceNode *node) find_root (GSequenceNode *node)
{ {
while (node->parent) while (node->parent)
{ node = 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);
}
}
return node; return node;
} }
@ -1457,21 +1339,19 @@ node_new (gpointer data)
{ {
GSequenceNode *node = g_slice_new0 (GSequenceNode); GSequenceNode *node = g_slice_new0 (GSequenceNode);
node->parent = NULL; node->n_nodes = 1;
node->parent = NULL; node->data = data;
node->left = NULL; node->left = NULL;
node->right = NULL; node->right = NULL;
node->parent = NULL;
node->data = data;
node->n_nodes = 1;
return node; return node;
} }
static GSequenceNode * static GSequenceNode *
find_min (GSequenceNode *node) node_get_first (GSequenceNode *node)
{ {
splay (node); node = find_root (node);
while (node->left) while (node->left)
node = node->left; node = node->left;
@ -1480,9 +1360,9 @@ find_min (GSequenceNode *node)
} }
static GSequenceNode * static GSequenceNode *
find_max (GSequenceNode *node) node_get_last (GSequenceNode *node)
{ {
splay (node); node = find_root (node);
while (node->right) while (node->right)
node = node->right; node = node->right;
@ -1490,96 +1370,104 @@ find_max (GSequenceNode *node)
return node; return 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 * static GSequenceNode *
node_get_first (GSequenceNode *node) node_get_next (GSequenceNode *node)
{ {
return splay (find_min (node)); GSequenceNode *n = node;
if (n->right)
{
n = n->right;
while (n->left)
n = n->left;
}
else
{
while (NODE_RIGHT_CHILD (n))
n = n->parent;
if (n->parent)
n = n->parent;
else
n = node;
}
return n;
} }
static GSequenceNode * static GSequenceNode *
node_get_last (GSequenceNode *node) node_get_prev (GSequenceNode *node)
{ {
return splay (find_max (node)); GSequenceNode *n = node;
if (n->left)
{
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
n = node;
}
return n;
} }
#define N_NODES(n) ((n)? (n)->n_nodes : 0)
static gint static gint
get_n_nodes (GSequenceNode *node) node_get_pos (GSequenceNode *node)
{ {
if (node) int n_smaller = 0;
return node->n_nodes;
else if (node->left)
return 0; n_smaller = node->left->n_nodes;
while (node)
{
if (NODE_RIGHT_CHILD (node))
n_smaller += N_NODES (node->parent->left) + 1;
node = node->parent;
}
return n_smaller;
} }
static GSequenceNode * static GSequenceNode *
node_get_by_pos (GSequenceNode *node, node_get_by_pos (GSequenceNode *node,
gint pos) gint pos)
{ {
gint i; int i;
g_assert (node != NULL); node = find_root (node);
splay (node); while ((i = N_NODES (node->left)) != pos)
while ((i = get_n_nodes (node->left)) != pos)
{ {
if (i < pos) if (i < pos)
{ {
node = node->right; node = node->right;
pos -= (i + 1); pos -= (i + 1);
} }
else else
{ {
node = node->left; node = node->left;
g_assert (node->parent != NULL); }
}
} }
return splay (node); return node;
} }
static GSequenceNode *
node_get_prev (GSequenceNode *node)
{
splay (node);
if (node->left)
{
node = node->left;
while (node->right)
node = node->right;
}
return splay (node);
}
static GSequenceNode *
node_get_next (GSequenceNode *node)
{
splay (node);
if (node->right)
{
node = node->right;
while (node->left)
node = node->left;
}
return splay (node);
}
static gint
node_get_pos (GSequenceNode *node)
{
splay (node);
return get_n_nodes (node->left);
}
/* 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 * static GSequenceNode *
node_find_closest (GSequenceNode *haystack, node_find_closest (GSequenceNode *haystack,
GSequenceNode *needle, GSequenceNode *needle,
@ -1590,9 +1478,7 @@ node_find_closest (GSequenceNode *haystack,
GSequenceNode *best; GSequenceNode *best;
gint c; gint c;
g_assert (haystack); haystack = find_root (haystack);
haystack = splay (haystack);
do do
{ {
@ -1626,140 +1512,211 @@ node_find_closest (GSequenceNode *haystack,
return best; return best;
} }
static void static gint
node_free (GSequenceNode *node, node_get_length (GSequenceNode *node)
GSequence *seq)
{ {
GPtrArray *stack = g_ptr_array_new (); node = find_root (node);
splay (node); return node->n_nodes;
}
g_ptr_array_add (stack, node);
static void
while (stack->len > 0) real_node_free (GSequenceNode *node,
{ GSequence *seq)
node = g_ptr_array_remove_index (stack, stack->len - 1); {
if (node)
if (node) {
{ real_node_free (node->left, seq);
g_ptr_array_add (stack, node->right); real_node_free (node->right, seq);
g_ptr_array_add (stack, node->left);
if (seq && seq->data_destroy_notify && node != seq->end_node)
if (seq && seq->data_destroy_notify && node != seq->end_node) seq->data_destroy_notify (node->data);
seq->data_destroy_notify (node->data);
g_slice_free (GSequenceNode, node);
g_slice_free (GSequenceNode, node); }
} }
}
static void
g_ptr_array_free (stack, TRUE); node_free (GSequenceNode *node,
GSequence *seq)
{
node = find_root (node);
real_node_free (node, seq);
}
static void
node_update_fields (GSequenceNode *node)
{
int n_nodes = 1;
n_nodes += N_NODES (node->left);
n_nodes += N_NODES (node->right);
node->n_nodes = n_nodes;
}
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);
}
static void
node_update_fields_deep (GSequenceNode *node)
{
if (node)
{
node_update_fields (node);
node_update_fields_deep (node->parent);
}
}
static void
rotate_down (GSequenceNode *node,
guint priority)
{
guint left, right;
left = node->left ? get_priority (node->left) : 0;
right = node->right ? get_priority (node->right) : 0;
while (priority < left || priority < right)
{
if (left > right)
node_rotate (node->left);
else
node_rotate (node->right);
left = node->left ? get_priority (node->left) : 0;
right = node->right ? get_priority (node->right) : 0;
}
} }
/* Splits into two trees. @node will be part of the right tree
*/
static void static void
node_cut (GSequenceNode *node) node_cut (GSequenceNode *node)
{ {
splay (node); while (node->parent)
node_rotate (node);
g_assert (node->parent == NULL);
if (node->left) if (node->left)
node->left->parent = NULL; node->left->parent = NULL;
node->left = NULL; node->left = NULL;
node_update_fields (node); node_update_fields (node);
rotate_down (node, get_priority (node));
}
static void
node_join (GSequenceNode *left,
GSequenceNode *right)
{
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);
node_unlink (fake);
node_free (fake, NULL);
} }
static void static void
node_insert_before (GSequenceNode *node, node_insert_before (GSequenceNode *node,
GSequenceNode *new) GSequenceNode *new)
{ {
g_assert (node != NULL);
g_assert (new != NULL);
splay (node);
new = splay (find_min (new));
g_assert (new->left == NULL);
if (node->left)
node->left->parent = new;
new->left = node->left; new->left = node->left;
new->parent = node; if (new->left)
new->left->parent = new;
new->parent = node;
node->left = new; node->left = new;
node_update_fields (new); node_update_fields_deep (new);
node_update_fields (node);
}
static void
node_insert_after (GSequenceNode *node,
GSequenceNode *new)
{
g_assert (node != NULL);
g_assert (new != NULL);
splay (node); while (new->parent && get_priority (new) > get_priority (new->parent))
node_rotate (new);
new = splay (find_max (new)); rotate_down (new, get_priority (new));
g_assert (new->right == NULL);
g_assert (node->parent == NULL);
if (node->right)
node->right->parent = new;
new->right = node->right;
new->parent = node;
node->right = new;
node_update_fields (new);
node_update_fields (node);
}
static gint
node_get_length (GSequenceNode *node)
{
g_assert (node != NULL);
splay (node);
return node->n_nodes;
} }
static void static void
node_unlink (GSequenceNode *node) node_unlink (GSequenceNode *node)
{ {
GSequenceNode *right, *left; rotate_down (node, 0);
splay (node); if (NODE_RIGHT_CHILD (node))
node->parent->right = NULL;
else if (NODE_LEFT_CHILD (node))
node->parent->left = NULL;
left = node->left; if (node->parent)
right = node->right; node_update_fields_deep (node->parent);
node->parent = node->left = node->right = NULL; node->parent = NULL;
node_update_fields (node);
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;
}
} }
static void static void
@ -1778,49 +1735,60 @@ node_insert_sorted (GSequenceNode *node,
node_insert_before (closest, new); node_insert_before (closest, new);
} }
static gint
node_calc_height (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;
}
return 0;
}
/* Self-test function */ /* Self-test function */
static int
count_nodes (GSequenceNode *node)
{
if (!node)
return 0;
return count_nodes (node->left) + count_nodes (node->right) + 1;
}
static void static void
check_node (GSequenceNode *node) check_node (GSequenceNode *node)
{ {
if (node) if (node)
{ {
g_assert (node->parent != node); g_assert (node->parent != node);
g_assert (node->n_nodes == if (node->parent)
1 + get_n_nodes (node->left) + get_n_nodes (node->right)); 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->left);
check_node (node->right); 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 void
g_sequence_self_test_internal_to_glib_dont_use (GSequence *seq) 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); check_node (node);
node = node_get_last (node);
g_assert (seq->end_node == node);
g_assert (node->data == seq);
} }
#define __G_SEQUENCE_C__ #define __G_SEQUENCE_C__

View File

@ -2,26 +2,25 @@
#include <glib.h> #include <glib.h>
#include <stdlib.h> #include <stdlib.h>
enum enum {
{ NEW, FREE, GET_LENGTH, FOREACH, FOREACH_RANGE, SORT, SORT_ITER,
NEW, FREE, GET_LENGTH, FOREACH, FOREACH_RANGE, SORT, SORT_ITER,
/* Getting iters */
/* Getting iters */ GET_BEGIN_ITER, GET_END_ITER, GET_ITER_AT_POS, APPEND, PREPEND,
GET_BEGIN_ITER, GET_END_ITER, GET_ITER_AT_POS, APPEND, PREPEND, INSERT_BEFORE, MOVE, SWAP, INSERT_SORTED, INSERT_SORTED_ITER, SORT_CHANGED,
INSERT_BEFORE, MOVE, INSERT_SORTED, INSERT_SORTED_ITER, SORT_CHANGED, SORT_CHANGED_ITER, REMOVE, REMOVE_RANGE, MOVE_RANGE, SEARCH, SEARCH_ITER,
SORT_CHANGED_ITER, REMOVE, REMOVE_RANGE, MOVE_RANGE, SEARCH, SEARCH_ITER,
/* dereferencing */
/* dereferencing */ GET, SET,
GET, SET,
/* operations on GSequenceIter * */
/* operations on GSequenceIter * */ ITER_IS_BEGIN, ITER_IS_END, ITER_NEXT, ITER_PREV, ITER_GET_POSITION,
ITER_IS_BEGIN, ITER_IS_END, ITER_NEXT, ITER_PREV, ITER_GET_POSITION, ITER_MOVE, ITER_GET_SEQUENCE,
ITER_MOVE, ITER_GET_SEQUENCE,
/* search */
/* search */ ITER_COMPARE, RANGE_GET_MIDPOINT,
ITER_COMPARE, RANGE_GET_MIDPOINT, N_OPS
N_OPS };
} Op;
typedef struct SequenceInfo typedef struct SequenceInfo
{ {
@ -70,7 +69,10 @@ check_integrity (SequenceInfo *info)
i = 0; i = 0;
while (iter != g_sequence_get_end_iter (info->sequence)) while (iter != g_sequence_get_end_iter (info->sequence))
{ {
Item *item;
g_assert (list->data == iter); g_assert (list->data == iter);
item = get_item (list->data);
g_assert (item->seq == info);
iter = g_sequence_iter_next (iter); iter = g_sequence_iter_next (iter);
list = list->next; list = list->next;
@ -312,7 +314,8 @@ run_random_tests (guint32 seed)
{ {
#define N_ITERATIONS 60000 #define N_ITERATIONS 60000
#define N_SEQUENCES 8 #define N_SEQUENCES 8
#define N_TIMES 24
SequenceInfo sequences[N_SEQUENCES]; SequenceInfo sequences[N_SEQUENCES];
int k; int k;
@ -501,8 +504,10 @@ run_random_tests (guint32 seed)
case MOVE: case MOVE:
{ {
GList *link1, *link2; GList *link1, *link2;
GSequenceIter *iter1 = get_random_iter (seq, &link1); SequenceInfo *seq1 = RANDOM_SEQUENCE();
GSequenceIter *iter2 = get_random_iter (seq, &link2); 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)) if (!g_sequence_iter_is_end (iter1))
{ {
@ -511,9 +516,14 @@ run_random_tests (guint32 seed)
if (!link2) if (!link2)
g_assert (g_sequence_iter_is_end (iter2)); 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); check_integrity (seq);
@ -525,6 +535,30 @@ run_random_tests (guint32 seed)
g_sequence_move (iter1, iter1); g_sequence_move (iter1, iter1);
} }
break; 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: case INSERT_SORTED:
{ {
int i; int i;
@ -535,7 +569,7 @@ run_random_tests (guint32 seed)
check_sorted (seq); check_sorted (seq);
for (i = 0; i < 15; ++i) for (i = 0; i < N_TIMES; ++i)
{ {
GSequenceIter *iter = GSequenceIter *iter =
g_sequence_insert_sorted (seq->sequence, new_item(seq), compare_items, NULL); g_sequence_insert_sorted (seq->sequence, new_item(seq), compare_items, NULL);
@ -558,7 +592,7 @@ run_random_tests (guint32 seed)
check_sorted (seq); check_sorted (seq);
for (i = 0; i < 15; ++i) for (i = 0; i < N_TIMES; ++i)
{ {
GSequenceIter *iter; GSequenceIter *iter;
@ -584,7 +618,7 @@ run_random_tests (guint32 seed)
check_sorted (seq); check_sorted (seq);
for (i = 0; i < 15; ++i) for (i = 0; i < N_TIMES; ++i)
{ {
GList *link; GList *link;
GSequenceIter *iter = get_random_iter (seq, &link); GSequenceIter *iter = get_random_iter (seq, &link);
@ -611,7 +645,7 @@ run_random_tests (guint32 seed)
check_sorted (seq); check_sorted (seq);
for (i = 0; i < 15; ++i) for (i = 0; i < N_TIMES; ++i)
{ {
GList *link; GList *link;
GSequenceIter *iter = get_random_iter (seq, &link); GSequenceIter *iter = get_random_iter (seq, &link);
@ -634,7 +668,7 @@ run_random_tests (guint32 seed)
{ {
int i; int i;
for (i = 0; i < 15; ++i) for (i = 0; i < N_TIMES; ++i)
{ {
GList *link; GList *link;
GSequenceIter *iter = get_random_iter (seq, &link); GSequenceIter *iter = get_random_iter (seq, &link);
@ -796,7 +830,7 @@ run_random_tests (guint32 seed)
g_assert (g_sequence_get (iter) == item); g_assert (g_sequence_get (iter) == item);
/* Make sure that existing items are freed */ /* 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)); g_sequence_set (iter, new_item (seq));
check_integrity (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()), g_sequence_insert_sorted_iter (seq, GINT_TO_POINTER (g_random_int()),
compare_iter, NULL); compare_iter, NULL);
} }
g_sequence_self_test_internal_to_glib_dont_use (seq);
g_sequence_free (seq); g_sequence_free (seq);
} }
@ -1130,15 +1166,23 @@ test_stable_sort (void)
GSequenceIter *iter; GSequenceIter *iter;
for (i = 0; i < N_ITEMS; ++i) 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; i = 0;
iter = g_sequence_get_begin_iter (seq); 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)) while (!g_sequence_iter_is_end (iter))
{ {
g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
g_assert (iters[i++] == iter); g_assert (iters[i++] == iter);
iter = g_sequence_iter_next (iter); iter = g_sequence_iter_next (iter);
g_sequence_self_test_internal_to_glib_dont_use (seq);
} }
g_sequence_sort (seq, compare, NULL); g_sequence_sort (seq, compare, NULL);
@ -1147,13 +1191,22 @@ test_stable_sort (void)
iter = g_sequence_get_begin_iter (seq); iter = g_sequence_get_begin_iter (seq);
while (!g_sequence_iter_is_end (iter)) 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); 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) 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; i = 0;
iter = g_sequence_get_begin_iter (seq); iter = g_sequence_get_begin_iter (seq);
@ -1162,6 +1215,7 @@ test_stable_sort (void)
g_assert (iters[i++] == iter); g_assert (iters[i++] == iter);
iter = g_sequence_iter_next (iter); iter = g_sequence_iter_next (iter);
g_sequence_self_test_internal_to_glib_dont_use (seq);
} }
} }