mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-03 22:52:09 +01:00
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:
parent
c6efde4f62
commit
f13d070e20
@ -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
|
||||||
|
746
glib/gsequence.c
746
glib/gsequence.c
@ -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,71 +1299,263 @@ g_sequence_swap (GSequenceIter *a,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implementation of the splay tree.
|
* Implementation of a treap
|
||||||
|
*
|
||||||
|
*
|
||||||
*/
|
*/
|
||||||
|
static guint
|
||||||
|
get_priority (GSequenceNode *node)
|
||||||
|
{
|
||||||
|
guint key = GPOINTER_TO_UINT (node);
|
||||||
|
|
||||||
/* Splay Tree vs. Other Kinds of Trees
|
/* This hash function is based on one found on Thomas Wang's
|
||||||
*
|
* web page at
|
||||||
* 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.
|
* http://www.concentric.net/~Ttwang/tech/inthash.htm
|
||||||
*
|
*
|
||||||
* Advantages of splay trees
|
*/
|
||||||
*
|
key = (key << 15) - key - 1;
|
||||||
* - They are very simple to implement, especially things like move_range or concatenate
|
key = key ^ (key >> 12);
|
||||||
* are easy to do for splay trees. The algorithm to split a red/black tree, while still O(log n),
|
key = key + (key << 2);
|
||||||
* is much more complicated
|
key = key ^ (key >> 4);
|
||||||
*
|
key = key + (key << 3) + (key << 11);
|
||||||
* - If we add aggregates at some point, splay trees make it easy to compute the aggregate
|
key = key ^ (key >> 16);
|
||||||
* 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.
|
/* We rely on 0 being less than all other priorities */
|
||||||
* On the other hand, for a splay tree, aggregates would be invalidated on lookups, so you
|
return key? key : 1;
|
||||||
* 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.
|
static GSequenceNode *
|
||||||
*
|
find_root (GSequenceNode *node)
|
||||||
* - 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
|
while (node->parent)
|
||||||
* not that interesting in practice since the O(log n) of a BTree is actually very fast.
|
node = node->parent;
|
||||||
*
|
|
||||||
* The disadvantages
|
return node;
|
||||||
*
|
}
|
||||||
* - Splay trees are only amortized O(log n) which means individual operations could take a long
|
|
||||||
* time, which is undesirable in GUI applications
|
static GSequenceNode *
|
||||||
*
|
node_new (gpointer data)
|
||||||
* - Red/black trees are more widely known since they are tought in CS101 courses.
|
{
|
||||||
*
|
GSequenceNode *node = g_slice_new0 (GSequenceNode);
|
||||||
* - 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
|
node->n_nodes = 1;
|
||||||
* system will have to launder.
|
node->data = data;
|
||||||
*
|
node->left = NULL;
|
||||||
* - Splay trees are not necessarily balanced at all which means straight-forward recursive
|
node->right = NULL;
|
||||||
* algorithms can use lots of stack.
|
node->parent = NULL;
|
||||||
*
|
|
||||||
* It is likely worth investigating whether a BTree would be a better choice, in particular the
|
return node;
|
||||||
* algorithm to split a BTree may not be all that complicated given that split/join for nodes
|
}
|
||||||
* will have to be implemented anyway.
|
|
||||||
*
|
static GSequenceNode *
|
||||||
*/
|
node_get_first (GSequenceNode *node)
|
||||||
|
{
|
||||||
|
node = find_root (node);
|
||||||
|
|
||||||
|
while (node->left)
|
||||||
|
node = node->left;
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSequenceNode *
|
||||||
|
node_get_last (GSequenceNode *node)
|
||||||
|
{
|
||||||
|
node = find_root (node);
|
||||||
|
|
||||||
|
while (node->right)
|
||||||
|
node = node->right;
|
||||||
|
|
||||||
|
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 *
|
||||||
|
node_get_next (GSequenceNode *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 *
|
||||||
|
node_get_prev (GSequenceNode *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
|
||||||
|
node_get_pos (GSequenceNode *node)
|
||||||
|
{
|
||||||
|
int n_smaller = 0;
|
||||||
|
|
||||||
|
if (node->left)
|
||||||
|
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 *
|
||||||
|
node_get_by_pos (GSequenceNode *node,
|
||||||
|
gint pos)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
node = find_root (node);
|
||||||
|
|
||||||
|
while ((i = N_NODES (node->left)) != pos)
|
||||||
|
{
|
||||||
|
if (i < pos)
|
||||||
|
{
|
||||||
|
node = node->right;
|
||||||
|
pos -= (i + 1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
node = node->left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return node;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GSequenceNode *
|
||||||
|
node_find_closest (GSequenceNode *haystack,
|
||||||
|
GSequenceNode *needle,
|
||||||
|
GSequenceNode *end,
|
||||||
|
GSequenceIterCompareFunc iter_cmp,
|
||||||
|
gpointer cmp_data)
|
||||||
|
{
|
||||||
|
GSequenceNode *best;
|
||||||
|
gint c;
|
||||||
|
|
||||||
|
haystack = find_root (haystack);
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
best = haystack;
|
||||||
|
|
||||||
|
/* iter_cmp can't be passed the end node, since the function may
|
||||||
|
* be user-supplied
|
||||||
|
*/
|
||||||
|
if (haystack == end)
|
||||||
|
c = 1;
|
||||||
|
else
|
||||||
|
c = iter_cmp (haystack, needle, cmp_data);
|
||||||
|
|
||||||
|
/* In the following we don't break even if c == 0. Instaed we go on
|
||||||
|
* searching along the 'bigger' nodes, so that we find the last one
|
||||||
|
* that is equal to the needle.
|
||||||
|
*/
|
||||||
|
if (c > 0)
|
||||||
|
haystack = haystack->left;
|
||||||
|
else
|
||||||
|
haystack = haystack->right;
|
||||||
|
}
|
||||||
|
while (haystack != NULL);
|
||||||
|
|
||||||
|
/* If the best node is smaller or equal to the data, then move one step
|
||||||
|
* to the right to make sure the best one is strictly bigger than the data
|
||||||
|
*/
|
||||||
|
if (best != end && c <= 0)
|
||||||
|
best = node_get_next (best);
|
||||||
|
|
||||||
|
return best;
|
||||||
|
}
|
||||||
|
|
||||||
|
static gint
|
||||||
|
node_get_length (GSequenceNode *node)
|
||||||
|
{
|
||||||
|
node = find_root (node);
|
||||||
|
|
||||||
|
return node->n_nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
real_node_free (GSequenceNode *node,
|
||||||
|
GSequence *seq)
|
||||||
|
{
|
||||||
|
if (node)
|
||||||
|
{
|
||||||
|
real_node_free (node->left, seq);
|
||||||
|
real_node_free (node->right, seq);
|
||||||
|
|
||||||
|
if (seq && seq->data_destroy_notify && node != seq->end_node)
|
||||||
|
seq->data_destroy_notify (node->data);
|
||||||
|
|
||||||
|
g_slice_free (GSequenceNode, node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
node_free (GSequenceNode *node,
|
||||||
|
GSequence *seq)
|
||||||
|
{
|
||||||
|
node = find_root (node);
|
||||||
|
|
||||||
|
real_node_free (node, seq);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
node_update_fields (GSequenceNode *node)
|
node_update_fields (GSequenceNode *node)
|
||||||
{
|
{
|
||||||
int n_nodes = 1;
|
int n_nodes = 1;
|
||||||
|
|
||||||
g_assert (node != NULL);
|
n_nodes += N_NODES (node->left);
|
||||||
|
n_nodes += N_NODES (node->right);
|
||||||
if (node->left)
|
|
||||||
n_nodes += node->left->n_nodes;
|
|
||||||
|
|
||||||
if (node->right)
|
|
||||||
n_nodes += node->right->n_nodes;
|
|
||||||
|
|
||||||
node->n_nodes = 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))
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
node_rotate (GSequenceNode *node)
|
node_rotate (GSequenceNode *node)
|
||||||
{
|
{
|
||||||
@ -1402,7 +1597,7 @@ node_rotate (GSequenceNode *node)
|
|||||||
node->left = node->parent;
|
node->left = node->parent;
|
||||||
node->parent = node->parent->parent;
|
node->parent = node->parent->parent;
|
||||||
if (node->parent)
|
if (node->parent)
|
||||||
{
|
{
|
||||||
if (node->parent->right == node->left)
|
if (node->parent->right == node->left)
|
||||||
node->parent->right = node;
|
node->parent->right = node;
|
||||||
else
|
else
|
||||||
@ -1424,342 +1619,104 @@ node_rotate (GSequenceNode *node)
|
|||||||
node_update_fields (node);
|
node_update_fields (node);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GSequenceNode *
|
static void
|
||||||
splay (GSequenceNode *node)
|
node_update_fields_deep (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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GSequenceNode *
|
|
||||||
node_new (gpointer data)
|
|
||||||
{
|
|
||||||
GSequenceNode *node = g_slice_new0 (GSequenceNode);
|
|
||||||
|
|
||||||
node->parent = NULL;
|
|
||||||
node->parent = NULL;
|
|
||||||
node->left = NULL;
|
|
||||||
node->right = NULL;
|
|
||||||
|
|
||||||
node->data = data;
|
|
||||||
node->n_nodes = 1;
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GSequenceNode *
|
|
||||||
find_min (GSequenceNode *node)
|
|
||||||
{
|
|
||||||
splay (node);
|
|
||||||
|
|
||||||
while (node->left)
|
|
||||||
node = node->left;
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GSequenceNode *
|
|
||||||
find_max (GSequenceNode *node)
|
|
||||||
{
|
|
||||||
splay (node);
|
|
||||||
|
|
||||||
while (node->right)
|
|
||||||
node = node->right;
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GSequenceNode *
|
|
||||||
node_get_first (GSequenceNode *node)
|
|
||||||
{
|
|
||||||
return splay (find_min (node));
|
|
||||||
}
|
|
||||||
|
|
||||||
static GSequenceNode *
|
|
||||||
node_get_last (GSequenceNode *node)
|
|
||||||
{
|
|
||||||
return splay (find_max (node));
|
|
||||||
}
|
|
||||||
|
|
||||||
static gint
|
|
||||||
get_n_nodes (GSequenceNode *node)
|
|
||||||
{
|
{
|
||||||
if (node)
|
if (node)
|
||||||
return node->n_nodes;
|
|
||||||
else
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static GSequenceNode *
|
|
||||||
node_get_by_pos (GSequenceNode *node,
|
|
||||||
gint pos)
|
|
||||||
{
|
|
||||||
gint i;
|
|
||||||
|
|
||||||
g_assert (node != NULL);
|
|
||||||
|
|
||||||
splay (node);
|
|
||||||
|
|
||||||
while ((i = get_n_nodes (node->left)) != pos)
|
|
||||||
{
|
{
|
||||||
if (i < pos)
|
node_update_fields (node);
|
||||||
{
|
|
||||||
node = node->right;
|
node_update_fields_deep (node->parent);
|
||||||
pos -= (i + 1);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
node = node->left;
|
|
||||||
g_assert (node->parent != NULL);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return splay (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 *
|
|
||||||
node_find_closest (GSequenceNode *haystack,
|
|
||||||
GSequenceNode *needle,
|
|
||||||
GSequenceNode *end,
|
|
||||||
GSequenceIterCompareFunc iter_cmp,
|
|
||||||
gpointer cmp_data)
|
|
||||||
{
|
|
||||||
GSequenceNode *best;
|
|
||||||
gint c;
|
|
||||||
|
|
||||||
g_assert (haystack);
|
|
||||||
|
|
||||||
haystack = splay (haystack);
|
|
||||||
|
|
||||||
do
|
|
||||||
{
|
|
||||||
best = haystack;
|
|
||||||
|
|
||||||
/* iter_cmp can't be passed the end node, since the function may
|
|
||||||
* be user-supplied
|
|
||||||
*/
|
|
||||||
if (haystack == end)
|
|
||||||
c = 1;
|
|
||||||
else
|
|
||||||
c = iter_cmp (haystack, needle, cmp_data);
|
|
||||||
|
|
||||||
/* In the following we don't break even if c == 0. Instaed we go on
|
|
||||||
* searching along the 'bigger' nodes, so that we find the last one
|
|
||||||
* that is equal to the needle.
|
|
||||||
*/
|
|
||||||
if (c > 0)
|
|
||||||
haystack = haystack->left;
|
|
||||||
else
|
|
||||||
haystack = haystack->right;
|
|
||||||
}
|
|
||||||
while (haystack != NULL);
|
|
||||||
|
|
||||||
/* If the best node is smaller or equal to the data, then move one step
|
|
||||||
* to the right to make sure the best one is strictly bigger than the data
|
|
||||||
*/
|
|
||||||
if (best != end && c <= 0)
|
|
||||||
best = node_get_next (best);
|
|
||||||
|
|
||||||
return best;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
node_free (GSequenceNode *node,
|
rotate_down (GSequenceNode *node,
|
||||||
GSequence *seq)
|
guint priority)
|
||||||
{
|
{
|
||||||
GPtrArray *stack = g_ptr_array_new ();
|
guint left, right;
|
||||||
|
|
||||||
splay (node);
|
left = node->left ? get_priority (node->left) : 0;
|
||||||
|
right = node->right ? get_priority (node->right) : 0;
|
||||||
|
|
||||||
g_ptr_array_add (stack, node);
|
while (priority < left || priority < right)
|
||||||
|
|
||||||
while (stack->len > 0)
|
|
||||||
{
|
{
|
||||||
node = g_ptr_array_remove_index (stack, stack->len - 1);
|
if (left > right)
|
||||||
|
node_rotate (node->left);
|
||||||
|
else
|
||||||
|
node_rotate (node->right);
|
||||||
|
|
||||||
if (node)
|
left = node->left ? get_priority (node->left) : 0;
|
||||||
{
|
right = node->right ? get_priority (node->right) : 0;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
g_ptr_array_free (stack, TRUE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 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
|
while (new->parent && get_priority (new) > get_priority (new->parent))
|
||||||
node_insert_after (GSequenceNode *node,
|
node_rotate (new);
|
||||||
GSequenceNode *new)
|
|
||||||
{
|
|
||||||
g_assert (node != NULL);
|
|
||||||
g_assert (new != NULL);
|
|
||||||
|
|
||||||
splay (node);
|
rotate_down (new, get_priority (new));
|
||||||
|
|
||||||
new = splay (find_max (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
|
/* Self-test function */
|
||||||
node_calc_height (GSequenceNode *node)
|
static int
|
||||||
|
count_nodes (GSequenceNode *node)
|
||||||
{
|
{
|
||||||
gint left_height;
|
if (!node)
|
||||||
gint right_height;
|
return 0;
|
||||||
|
|
||||||
if (node)
|
return count_nodes (node->left) + count_nodes (node->right) + 1;
|
||||||
{
|
|
||||||
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 */
|
|
||||||
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__
|
||||||
|
@ -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, INSERT_SORTED, INSERT_SORTED_ITER, SORT_CHANGED,
|
INSERT_BEFORE, MOVE, SWAP, 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,6 +314,7 @@ 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);
|
||||||
@ -1114,6 +1148,8 @@ test_insert_sorted_non_pointer (void)
|
|||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user