Change LGPL-2.1+ to LGPL-2.1-or-later
[platform/upstream/glib.git] / glib / tests / sequence.c
1 #include <stdio.h>
2 #include <glib.h>
3 #include <stdlib.h>
4
5 /* Keep this in sync with gsequence.c !!! */
6 typedef struct _GSequenceNode GSequenceNode;
7
8 struct _GSequence
9 {
10   GSequenceNode *       end_node;
11   GDestroyNotify        data_destroy_notify;
12   gboolean              access_prohibited;
13   GSequence *           real_sequence;
14 };
15
16 struct _GSequenceNode
17 {
18   gint                  n_nodes;
19   guint32               priority;
20   GSequenceNode *       parent;
21   GSequenceNode *       left;
22   GSequenceNode *       right;
23   gpointer              data;
24 };
25
26 static guint
27 get_priority (GSequenceNode *node)
28 {
29   guint key = node->priority;
30
31   /* We rely on 0 being less than all other priorities */
32   return key? key : 1;
33 }
34
35 static void
36 check_node (GSequenceNode *node)
37 {
38   if (node)
39     {
40       g_assert (node->parent != node);
41       if (node->parent)
42         g_assert (node->parent->left == node || node->parent->right == node);
43       g_assert (node->n_nodes == 1 + (node->left ? node->left->n_nodes : 0) + (node->right ? node->right->n_nodes : 0));
44       if (node->left)
45           g_assert (get_priority (node) >= get_priority (node->left));
46       if (node->right)
47           g_assert (get_priority (node) >= get_priority (node->right));
48       check_node (node->left);
49       check_node (node->right);
50     }
51 }
52
53 static void
54 g_sequence_check (GSequence *seq)
55 {
56   GSequenceNode *node = seq->end_node;
57
58   while (node->parent)
59     node = node->parent;
60
61   check_node (node);
62
63   while (node->right)
64     node = node->right;
65
66   g_assert (seq->end_node == node);
67   g_assert (node->data == seq);
68
69 }
70
71
72 enum {
73   NEW, FREE, GET_LENGTH, FOREACH, FOREACH_RANGE, SORT, SORT_ITER,
74
75   /* Getting iters */
76   GET_BEGIN_ITER, GET_END_ITER, GET_ITER_AT_POS, APPEND, PREPEND,
77   INSERT_BEFORE, MOVE, SWAP, INSERT_SORTED, INSERT_SORTED_ITER, SORT_CHANGED,
78   SORT_CHANGED_ITER, REMOVE, REMOVE_RANGE, MOVE_RANGE, SEARCH, SEARCH_ITER,
79   LOOKUP, LOOKUP_ITER,
80
81   /* dereferencing */
82   GET, SET,
83
84   /* operations on GSequenceIter * */
85   ITER_IS_BEGIN, ITER_IS_END, ITER_NEXT, ITER_PREV, ITER_GET_POSITION,
86   ITER_MOVE, ITER_GET_SEQUENCE,
87
88   /* search */
89   ITER_COMPARE, RANGE_GET_MIDPOINT,
90   N_OPS
91 };
92
93 typedef struct SequenceInfo
94 {
95   GQueue *      queue;
96   GSequence *   sequence;
97   guint         n_items;
98 } SequenceInfo;
99
100 typedef struct
101 {
102   SequenceInfo *seq;
103   int             number;
104 } Item;
105
106 void g_sequence_check (GSequence *sequence);
107
108 static Item *
109 fix_pointer (gconstpointer data)
110 {
111   return (Item *)((char *)data - 1);
112 }
113
114 static Item *
115 get_item (GSequenceIter *iter)
116 {
117   return fix_pointer (g_sequence_get (iter));
118 }
119
120 static void
121 check_integrity (SequenceInfo *info)
122 {
123   GList *list;
124   GSequenceIter *iter;
125   unsigned int i;
126
127   g_sequence_check (info->sequence);
128
129 #if 0
130   if (g_sequence_get_length (info->sequence) != info->n_items)
131     g_printerr ("%d %d\n",
132              g_sequence_get_length (info->sequence), info->n_items);
133 #endif
134   g_assert (info->n_items == g_queue_get_length (info->queue));
135   g_assert ((guint) g_sequence_get_length (info->sequence) == info->n_items);
136
137   iter = g_sequence_get_begin_iter (info->sequence);
138   list = info->queue->head;
139   i = 0;
140   while (iter != g_sequence_get_end_iter (info->sequence))
141     {
142       Item *item;
143       g_assert (list->data == iter);
144       item = get_item (list->data);
145       g_assert (item->seq == info);
146
147       iter = g_sequence_iter_next (iter);
148       list = list->next;
149       i++;
150     }
151
152   g_assert_cmpuint (i, ==, info->n_items);
153   g_assert (info->n_items == g_queue_get_length (info->queue));
154   g_assert ((guint) g_sequence_get_length (info->sequence) == info->n_items);
155 }
156
157 static gpointer
158 new_item (SequenceInfo *seq)
159 {
160   Item *item = g_new (Item, 1);
161   seq->n_items++;
162   item->seq = seq;
163   item->number = g_random_int ();
164
165   /* There have been bugs in the past where the GSequence would
166    * dereference the user pointers. This will make sure such
167    * behavior causes crashes
168    */
169   return ((char *)item + 1);
170 }
171
172 static void
173 free_item (gpointer data)
174 {
175   Item *item = fix_pointer (data);
176   item->seq->n_items--;
177   g_free (item);
178 }
179
180 static void
181 seq_foreach (gpointer data,
182              gpointer user_data)
183 {
184   Item *item = fix_pointer (data);
185   GList **link = user_data;
186   GSequenceIter *iter;
187
188   g_assert (*link != NULL);
189
190   iter = (*link)->data;
191
192   g_assert (get_item (iter) == item);
193
194   item->number = g_random_int();
195
196   *link = (*link)->next;
197 }
198
199 static gint
200 simple_items_cmp (gconstpointer a,
201                   gconstpointer b,
202                   gpointer data)
203 {
204   const Item *item_a = fix_pointer (a);
205   const Item *item_b = fix_pointer (b);
206
207   if (item_a->number > item_b->number)
208     return +1;
209   else if (item_a->number < item_b->number)
210     return -1;
211   else
212     return 0;
213 }
214
215 static gint
216 simple_iters_cmp (gconstpointer a,
217                   gconstpointer b,
218                   gpointer data)
219 {
220   GSequence *seq = data;
221   GSequenceIter *iter_a = (GSequenceIter *)a;
222   GSequenceIter *iter_b = (GSequenceIter *)b;
223   gpointer item_a = g_sequence_get (iter_a);
224   gpointer item_b = g_sequence_get (iter_b);
225
226   if (seq)
227     {
228       g_assert (g_sequence_iter_get_sequence (iter_a) == seq);
229       g_assert (g_sequence_iter_get_sequence (iter_b) == seq);
230     }
231
232   return simple_items_cmp (item_a, item_b, data);
233 }
234
235 static gint
236 compare_items (gconstpointer a,
237                gconstpointer b,
238                gpointer      data)
239 {
240   const Item *item_a = fix_pointer (a);
241   const Item *item_b = fix_pointer (b);
242
243   if (item_a->number < item_b->number)
244     {
245       return -1;
246     }
247   else if (item_a->number == item_b->number)
248     {
249       /* Force an arbitrary order on the items
250        * We have to do this, since g_queue_insert_sorted() and
251        * g_sequence_insert_sorted() do not agree on the exact
252        * position the item is inserted if the new item is
253        * equal to an existing one.
254        */
255       if (item_a < item_b)
256         return -1;
257       else if (item_a == item_b)
258         return 0;
259       else
260         return 1;
261     }
262   else
263     {
264       return 1;
265     }
266 }
267
268 static void
269 check_sorted (SequenceInfo *info)
270 {
271   GList *list;
272   int last;
273   GSequenceIter *last_iter;
274
275   check_integrity (info);
276
277   last = G_MININT;
278   last_iter = NULL;
279   for (list = info->queue->head; list != NULL; list = list->next)
280     {
281       GSequenceIter *iter = list->data;
282       Item *item = get_item (iter);
283
284       g_assert (item->number >= last);
285       /* Check that the ordering is the same as that of the queue,
286        * ie. that the sort is stable
287        */
288       if (last_iter)
289         g_assert (iter == g_sequence_iter_next (last_iter));
290
291       last = item->number;
292       last_iter = iter;
293     }
294 }
295
296 static gint
297 compare_iters (gconstpointer a,
298                gconstpointer b,
299                gpointer      data)
300 {
301   GSequence *seq = data;
302   GSequenceIter *iter_a = (GSequenceIter *)a;
303   GSequenceIter *iter_b = (GSequenceIter *)b;
304   /* compare_items() will fix up the pointers */
305   Item *item_a = g_sequence_get (iter_a);
306   Item *item_b = g_sequence_get (iter_b);
307
308   if (seq)
309     {
310       g_assert (g_sequence_iter_get_sequence (iter_a) == seq);
311       g_assert (g_sequence_iter_get_sequence (iter_b) == seq);
312     }
313
314   return compare_items (item_a, item_b, data);
315 }
316
317 /* A version of g_queue_link_index() that treats NULL as just
318  * beyond the queue
319  */
320 static int
321 queue_link_index (SequenceInfo *seq, GList *link)
322 {
323   if (link)
324     return g_queue_link_index (seq->queue, link);
325   else
326     return g_queue_get_length (seq->queue);
327 }
328
329 static void
330 get_random_range (SequenceInfo *seq,
331                   GSequenceIter **begin_iter,
332                   GSequenceIter **end_iter,
333                   GList **begin_link,
334                   GList **end_link)
335 {
336   int length = g_queue_get_length (seq->queue);
337   int b = g_random_int_range (0, length + 1);
338   int e = g_random_int_range (b, length + 1);
339
340   g_assert (length == g_sequence_get_length (seq->sequence));
341
342   if (begin_iter)
343     *begin_iter = g_sequence_get_iter_at_pos (seq->sequence, b);
344   if (end_iter)
345     *end_iter = g_sequence_get_iter_at_pos (seq->sequence, e);
346   if (begin_link)
347     *begin_link = g_queue_peek_nth_link (seq->queue, b);
348   if (end_link)
349     *end_link = g_queue_peek_nth_link (seq->queue, e);
350   if (begin_iter && begin_link)
351     {
352       g_assert (
353                 queue_link_index (seq, *begin_link) ==
354                 g_sequence_iter_get_position (*begin_iter));
355     }
356   if (end_iter && end_link)
357     {
358       g_assert (
359                 queue_link_index (seq, *end_link) ==
360                 g_sequence_iter_get_position (*end_iter));
361     }
362 }
363
364 static gint
365 get_random_position (SequenceInfo *seq)
366 {
367   int length = g_queue_get_length (seq->queue);
368
369   g_assert (length == g_sequence_get_length (seq->sequence));
370
371   return g_random_int_range (-2, length + 5);
372 }
373
374 static GSequenceIter *
375 get_random_iter (SequenceInfo  *seq,
376                  GList        **link)
377 {
378   GSequenceIter *iter;
379   int pos = get_random_position (seq);
380   if (link)
381     *link = g_queue_peek_nth_link (seq->queue, pos);
382   iter = g_sequence_get_iter_at_pos (seq->sequence, pos);
383   if (link)
384     g_assert (queue_link_index (seq, *link) == g_sequence_iter_get_position (iter));
385   return iter;
386 }
387
388 static void
389 dump_info (SequenceInfo *seq)
390 {
391 #if 0
392   GSequenceIter *iter;
393   GList *list;
394
395   iter = g_sequence_get_begin_iter (seq->sequence);
396   list = seq->queue->head;
397
398   while (iter != g_sequence_get_end_iter (seq->sequence))
399     {
400       Item *item = get_item (iter);
401       g_printerr ("%p  %p    %d\n", list->data, iter, item->number);
402
403       iter = g_sequence_iter_next (iter);
404       list = list->next;
405     }
406 #endif
407 }
408
409 static void
410 run_random_tests (gconstpointer d)
411 {
412   guint32 seed = GPOINTER_TO_UINT (d);
413 #define N_ITERATIONS 60000
414 #define N_SEQUENCES 8
415 #define N_TIMES 24
416
417   SequenceInfo sequences[N_SEQUENCES];
418   int k;
419
420 #if 0
421   g_printerr ("    seed: %u\n", seed);
422 #endif
423
424   g_random_set_seed (seed);
425
426   for (k = 0; k < N_SEQUENCES; ++k)
427     {
428       sequences[k].queue = g_queue_new ();
429       sequences[k].sequence = g_sequence_new (free_item);
430       sequences[k].n_items = 0;
431     }
432
433 #define RANDOM_SEQUENCE() &(sequences[g_random_int_range (0, N_SEQUENCES)])
434
435   for (k = 0; k < N_ITERATIONS; ++k)
436     {
437       int i;
438       SequenceInfo *seq = RANDOM_SEQUENCE();
439       int op = g_random_int_range (0, N_OPS);
440
441 #if 0
442       g_printerr ("%d on %p\n", op, seq);
443 #endif
444
445       switch (op)
446         {
447         case NEW:
448         case FREE:
449           {
450             g_queue_free (seq->queue);
451             g_sequence_free (seq->sequence);
452
453             g_assert (seq->n_items == 0);
454
455             seq->queue = g_queue_new ();
456             seq->sequence = g_sequence_new (free_item);
457
458             check_integrity (seq);
459           }
460           break;
461         case GET_LENGTH:
462           {
463             int slen = g_sequence_get_length (seq->sequence);
464             int qlen = g_queue_get_length (seq->queue);
465
466             g_assert (slen == qlen);
467           }
468           break;
469         case FOREACH:
470           {
471             GList *link = seq->queue->head;
472             g_sequence_foreach (seq->sequence, seq_foreach, &link);
473             g_assert (link == NULL);
474           }
475           break;
476         case FOREACH_RANGE:
477           {
478             GSequenceIter *begin_iter, *end_iter;
479             GList *begin_link, *end_link;
480
481             get_random_range (seq, &begin_iter, &end_iter, &begin_link, &end_link);
482
483             check_integrity (seq);
484
485             g_sequence_foreach_range (begin_iter, end_iter, seq_foreach, &begin_link);
486
487             g_assert (begin_link == end_link);
488           }
489           break;
490         case SORT:
491           {
492             dump_info (seq);
493
494             g_sequence_sort (seq->sequence, compare_items, NULL);
495             g_queue_sort (seq->queue, compare_iters, NULL);
496
497             check_sorted (seq);
498
499             dump_info (seq);
500           }
501           break;
502         case SORT_ITER:
503           {
504             check_integrity (seq);
505             g_sequence_sort_iter (seq->sequence,
506                                   (GSequenceIterCompareFunc)compare_iters, seq->sequence);
507             g_queue_sort (seq->queue, compare_iters, NULL);
508             check_sorted (seq);
509           }
510           break;
511
512           /* Getting iters */
513         case GET_END_ITER:
514         case GET_BEGIN_ITER:
515           {
516             GSequenceIter *begin_iter;
517             GSequenceIter *end_iter;
518             GSequenceIter *penultimate_iter;
519
520             begin_iter = g_sequence_get_begin_iter (seq->sequence);
521             check_integrity (seq);
522
523             end_iter = g_sequence_get_end_iter (seq->sequence);
524             check_integrity (seq);
525
526             penultimate_iter = g_sequence_iter_prev (end_iter);
527             check_integrity (seq);
528
529             if (g_sequence_get_length (seq->sequence) > 0)
530               {
531                 g_assert (seq->queue->head);
532                 g_assert (seq->queue->head->data == begin_iter);
533                 g_assert (seq->queue->tail);
534                 g_assert (seq->queue->tail->data == penultimate_iter);
535               }
536             else
537               {
538                 g_assert (penultimate_iter == end_iter);
539                 g_assert (begin_iter == end_iter);
540                 g_assert (penultimate_iter == begin_iter);
541                 g_assert (seq->queue->head == NULL);
542                 g_assert (seq->queue->tail == NULL);
543               }
544           }
545           break;
546         case GET_ITER_AT_POS:
547           {
548             g_assert (g_queue_get_length (seq->queue) == (guint) g_sequence_get_length (seq->sequence));
549
550             for (i = 0; i < 10; ++i)
551               {
552                 int pos = get_random_position (seq);
553                 GSequenceIter *iter = g_sequence_get_iter_at_pos (seq->sequence, pos);
554                 GList *link = g_queue_peek_nth_link (seq->queue, pos);
555                 check_integrity (seq);
556                 if (pos >= g_sequence_get_length (seq->sequence) || pos < 0)
557                   {
558                     g_assert (iter == g_sequence_get_end_iter (seq->sequence));
559                     g_assert (link == NULL);
560                   }
561                 else
562                   {
563                     g_assert (link);
564                     g_assert (link->data == iter);
565                   }
566               }
567           }
568           break;
569         case APPEND:
570           {
571             for (i = 0; i < 10; ++i)
572               {
573                 GSequenceIter *iter = g_sequence_append (seq->sequence, new_item (seq));
574                 g_queue_push_tail (seq->queue, iter);
575               }
576           }
577           break;
578         case PREPEND:
579           {
580             for (i = 0; i < 10; ++i)
581               {
582                 GSequenceIter *iter = g_sequence_prepend (seq->sequence, new_item (seq));
583                 g_queue_push_head (seq->queue, iter);
584               }
585           }
586           break;
587         case INSERT_BEFORE:
588           {
589             for (i = 0; i < 10; ++i)
590               {
591                 GList *link;
592                 GSequenceIter *iter = get_random_iter (seq, &link);
593                 GSequenceIter *new_iter;
594                 check_integrity (seq);
595
596                 new_iter = g_sequence_insert_before (iter, new_item (seq));
597
598                 g_queue_insert_before (seq->queue, link, new_iter);
599               }
600           }
601           break;
602         case MOVE:
603           {
604             GList *link1, *link2;
605             SequenceInfo *seq1 = RANDOM_SEQUENCE();
606             SequenceInfo *seq2 = RANDOM_SEQUENCE();
607             GSequenceIter *iter1 = get_random_iter (seq1, &link1);
608             GSequenceIter *iter2 = get_random_iter (seq2, &link2);
609
610             if (!g_sequence_iter_is_end (iter1))
611               {
612                 g_sequence_move (iter1, iter2);
613
614                 if (!link2)
615                   g_assert (g_sequence_iter_is_end (iter2));
616
617                 g_queue_insert_before (seq2->queue, link2, link1->data);
618
619                 g_queue_delete_link (seq1->queue, link1);
620
621                 get_item (iter1)->seq = seq2;
622
623                 seq1->n_items--;
624                 seq2->n_items++;
625               }
626
627             check_integrity (seq);
628
629             iter1 = get_random_iter (seq, NULL);
630
631             /* Moving an iter to itself should have no effect */
632             if (!g_sequence_iter_is_end (iter1))
633               g_sequence_move (iter1, iter1);
634           }
635           break;
636         case SWAP:
637           {
638             GList *link1, *link2;
639             SequenceInfo *seq1 = RANDOM_SEQUENCE();
640             SequenceInfo *seq2 = RANDOM_SEQUENCE();
641             GSequenceIter *iter1 = get_random_iter (seq1, &link1);
642             GSequenceIter *iter2 = get_random_iter (seq2, &link2);
643
644             if (!g_sequence_iter_is_end (iter1) &&
645                 !g_sequence_iter_is_end (iter2))
646               {
647                 gpointer tmp;
648
649                 g_sequence_swap (iter1, iter2);
650
651                 get_item (iter1)->seq = seq2;
652                 get_item (iter2)->seq = seq1;
653
654                 tmp = link1->data;
655                 link1->data = link2->data;
656                 link2->data = tmp;
657               }
658           }
659           break;
660         case INSERT_SORTED:
661           {
662             dump_info (seq);
663
664             g_sequence_sort (seq->sequence, compare_items, NULL);
665             g_queue_sort (seq->queue, compare_iters, NULL);
666
667             check_sorted (seq);
668
669             for (i = 0; i < N_TIMES; ++i)
670               {
671                 GSequenceIter *iter =
672                   g_sequence_insert_sorted (seq->sequence, new_item(seq), compare_items, NULL);
673
674                 g_queue_insert_sorted (seq->queue, iter, compare_iters, NULL);
675               }
676
677             check_sorted (seq);
678
679             dump_info (seq);
680           }
681           break;
682         case INSERT_SORTED_ITER:
683           {
684             dump_info (seq);
685
686             g_sequence_sort (seq->sequence, compare_items, NULL);
687             g_queue_sort (seq->queue, compare_iters, NULL);
688
689             check_sorted (seq);
690
691             for (i = 0; i < N_TIMES; ++i)
692               {
693                 GSequenceIter *iter;
694
695                 iter = g_sequence_insert_sorted_iter (seq->sequence,
696                                                       new_item (seq),
697                                                       (GSequenceIterCompareFunc)compare_iters,
698                                                       seq->sequence);
699
700                 g_queue_insert_sorted (seq->queue, iter, compare_iters, NULL);
701               }
702
703             check_sorted (seq);
704
705             dump_info (seq);
706           }
707           break;
708         case SORT_CHANGED:
709           {
710             g_sequence_sort (seq->sequence, compare_items, NULL);
711             g_queue_sort (seq->queue, compare_iters, NULL);
712
713             check_sorted (seq);
714
715             for (i = 0; i < N_TIMES; ++i)
716               {
717                 GList *link;
718                 GSequenceIter *iter = get_random_iter (seq, &link);
719
720                 if (!g_sequence_iter_is_end (iter))
721                   {
722                     g_sequence_set (iter, new_item (seq));
723                     g_sequence_sort_changed (iter, compare_items, NULL);
724
725                     g_queue_delete_link (seq->queue, link);
726                     g_queue_insert_sorted (seq->queue, iter, compare_iters, NULL);
727                   }
728
729                 check_sorted (seq);
730               }
731           }
732           break;
733         case SORT_CHANGED_ITER:
734           {
735             g_sequence_sort (seq->sequence, compare_items, NULL);
736             g_queue_sort (seq->queue, compare_iters, NULL);
737
738             check_sorted (seq);
739
740             for (i = 0; i < N_TIMES; ++i)
741               {
742                 GList *link;
743                 GSequenceIter *iter = get_random_iter (seq, &link);
744
745                 if (!g_sequence_iter_is_end (iter))
746                   {
747                     g_sequence_set (iter, new_item (seq));
748                     g_sequence_sort_changed_iter (iter,
749                                                   (GSequenceIterCompareFunc)compare_iters, seq->sequence);
750
751                     g_queue_delete_link (seq->queue, link);
752                     g_queue_insert_sorted (seq->queue, iter, compare_iters, NULL);
753                   }
754
755                 check_sorted (seq);
756               }
757           }
758           break;
759         case REMOVE:
760           {
761             for (i = 0; i < N_TIMES; ++i)
762               {
763                 GList *link;
764                 GSequenceIter *iter = get_random_iter (seq, &link);
765
766                 if (!g_sequence_iter_is_end (iter))
767                   {
768                     g_sequence_remove (iter);
769                     g_queue_delete_link (seq->queue, link);
770                   }
771               }
772           }
773           break;
774         case REMOVE_RANGE:
775           {
776             GSequenceIter *begin_iter, *end_iter;
777             GList *begin_link, *end_link;
778             GList *list;
779
780             get_random_range (seq, &begin_iter, &end_iter, &begin_link, &end_link);
781
782             g_sequence_remove_range (begin_iter, end_iter);
783
784             list = begin_link;
785             while (list != end_link)
786               {
787                 GList *next = list->next;
788
789                 g_queue_delete_link (seq->queue, list);
790
791                 list = next;
792               }
793           }
794           break;
795         case MOVE_RANGE:
796           {
797             SequenceInfo *src = RANDOM_SEQUENCE();
798             SequenceInfo *dst = RANDOM_SEQUENCE();
799
800             GSequenceIter *begin_iter, *end_iter;
801             GList *begin_link, *end_link;
802
803             GSequenceIter *dst_iter;
804             GList *dst_link;
805
806             GList *list;
807
808             g_assert (src->queue);
809             g_assert (dst->queue);
810
811             get_random_range (src, &begin_iter, &end_iter, &begin_link, &end_link);
812             dst_iter = get_random_iter (dst, &dst_link);
813
814             g_sequence_move_range (dst_iter, begin_iter, end_iter);
815
816             if (dst_link == begin_link || (src == dst && dst_link == end_link))
817               {
818                 check_integrity (src);
819                 check_integrity (dst);
820                 break;
821               }
822
823             if (queue_link_index (src, begin_link) >=
824                 queue_link_index (src, end_link))
825               {
826                 break;
827               }
828
829             if (src == dst &&
830                 queue_link_index (src, dst_link) >= queue_link_index (src, begin_link) &&
831                 queue_link_index (src, dst_link) <= queue_link_index (src, end_link))
832               {
833                 break;
834               }
835
836             list = begin_link;
837             while (list != end_link)
838               {
839                 GList *next = list->next;
840                 Item *item = get_item (list->data);
841
842                 g_assert (dst->queue);
843                 g_queue_insert_before (dst->queue, dst_link, list->data);
844                 g_queue_delete_link (src->queue, list);
845
846                 g_assert (item->seq == src);
847
848                 src->n_items--;
849                 dst->n_items++;
850                 item->seq = dst;
851
852                 list = next;
853               }
854           }
855           break;
856         case SEARCH:
857           {
858             Item *item;
859             GSequenceIter *search_iter;
860             GSequenceIter *insert_iter;
861
862             g_sequence_sort (seq->sequence, compare_items, NULL);
863             g_queue_sort (seq->queue, compare_iters, NULL);
864
865             check_sorted (seq);
866
867             item = new_item (seq);
868             search_iter = g_sequence_search (seq->sequence, item, compare_items, NULL);
869
870             insert_iter = g_sequence_insert_sorted (seq->sequence, item, compare_items, NULL);
871
872             g_assert (search_iter == g_sequence_iter_next (insert_iter));
873
874             g_queue_insert_sorted (seq->queue, insert_iter, compare_iters, NULL);
875           }
876           break;
877         case SEARCH_ITER:
878           {
879             Item *item;
880             GSequenceIter *search_iter;
881             GSequenceIter *insert_iter;
882
883             g_sequence_sort (seq->sequence, compare_items, NULL);
884             g_queue_sort (seq->queue, compare_iters, NULL);
885
886             check_sorted (seq);
887
888             item = new_item (seq);
889             search_iter = g_sequence_search_iter (seq->sequence,
890                                                   item,
891                                                   (GSequenceIterCompareFunc)compare_iters, seq->sequence);
892
893             insert_iter = g_sequence_insert_sorted (seq->sequence, item, compare_items, NULL);
894
895             g_assert (search_iter == g_sequence_iter_next (insert_iter));
896
897             g_queue_insert_sorted (seq->queue, insert_iter, compare_iters, NULL);
898           }
899           break;
900         case LOOKUP:
901           {
902             Item *item;
903             GSequenceIter *lookup_iter;
904             GSequenceIter *insert_iter;
905
906             g_sequence_sort (seq->sequence, compare_items, NULL);
907             g_queue_sort (seq->queue, compare_iters, NULL);
908
909             check_sorted (seq);
910
911             item = new_item (seq);
912             insert_iter = g_sequence_insert_sorted (seq->sequence, item, compare_items, NULL);
913             g_queue_insert_sorted (seq->queue, insert_iter, compare_iters, NULL);
914
915             lookup_iter = g_sequence_lookup (seq->sequence, item, simple_items_cmp, NULL);
916             g_assert (simple_iters_cmp (insert_iter, lookup_iter, NULL) == 0);
917           }
918           break;
919         case LOOKUP_ITER:
920           {
921             Item *item;
922             GSequenceIter *lookup_iter;
923             GSequenceIter *insert_iter;
924
925             g_sequence_sort (seq->sequence, compare_items, NULL);
926             g_queue_sort (seq->queue, compare_iters, NULL);
927
928             check_sorted (seq);
929
930             item = new_item (seq);
931             insert_iter = g_sequence_insert_sorted (seq->sequence, item, compare_items, NULL);
932             g_queue_insert_sorted (seq->queue, insert_iter, compare_iters, NULL);
933
934             lookup_iter = g_sequence_lookup_iter (seq->sequence, item,
935                 (GSequenceIterCompareFunc) simple_iters_cmp, NULL);
936             g_assert (simple_iters_cmp (insert_iter, lookup_iter, NULL) == 0);
937           }
938           break;
939
940           /* dereferencing */
941         case GET:
942         case SET:
943           {
944             GSequenceIter *iter;
945             GList *link;
946
947             iter = get_random_iter (seq, &link);
948
949             if (!g_sequence_iter_is_end (iter))
950               {
951                 Item *item;
952
953                 check_integrity (seq);
954
955                 /* Test basic functionality */
956                 item = new_item (seq);
957                 g_sequence_set (iter, item);
958                 g_assert (g_sequence_get (iter) == item);
959
960                 /* Make sure that existing items are freed */
961                 for (i = 0; i < N_TIMES; ++i)
962                   g_sequence_set (iter, new_item (seq));
963
964                 check_integrity (seq);
965
966                 g_sequence_set (iter, new_item (seq));
967               }
968           }
969           break;
970
971           /* operations on GSequenceIter * */
972         case ITER_IS_BEGIN:
973           {
974             GSequenceIter *iter;
975
976             iter = g_sequence_get_iter_at_pos (seq->sequence, 0);
977
978             g_assert (g_sequence_iter_is_begin (iter));
979
980             check_integrity (seq);
981
982             if (g_sequence_get_length (seq->sequence) > 0)
983               {
984                 g_assert (!g_sequence_iter_is_begin (g_sequence_get_end_iter (seq->sequence)));
985               }
986             else
987               {
988                 g_assert (g_sequence_iter_is_begin (g_sequence_get_end_iter (seq->sequence)));
989               }
990
991             g_assert (g_sequence_iter_is_begin (g_sequence_get_begin_iter (seq->sequence)));
992           }
993           break;
994         case ITER_IS_END:
995           {
996             GSequenceIter *iter;
997             int len = g_sequence_get_length (seq->sequence);
998
999             iter = g_sequence_get_iter_at_pos (seq->sequence, len);
1000
1001             g_assert (g_sequence_iter_is_end (iter));
1002
1003             if (len > 0)
1004               {
1005                 g_assert (!g_sequence_iter_is_end (g_sequence_get_begin_iter (seq->sequence)));
1006               }
1007             else
1008               {
1009                 g_assert (g_sequence_iter_is_end (g_sequence_get_begin_iter (seq->sequence)));
1010               }
1011
1012             g_assert (g_sequence_iter_is_end (g_sequence_get_end_iter (seq->sequence)));
1013           }
1014           break;
1015         case ITER_NEXT:
1016           {
1017             GSequenceIter *iter1, *iter2, *iter3, *end;
1018
1019             iter1 = g_sequence_append (seq->sequence, new_item (seq));
1020             iter2 = g_sequence_append (seq->sequence, new_item (seq));
1021             iter3 = g_sequence_append (seq->sequence, new_item (seq));
1022
1023             end = g_sequence_get_end_iter (seq->sequence);
1024
1025             g_assert (g_sequence_iter_next (iter1) == iter2);
1026             g_assert (g_sequence_iter_next (iter2) == iter3);
1027             g_assert (g_sequence_iter_next (iter3) == end);
1028             g_assert (g_sequence_iter_next (end) == end);
1029
1030             g_queue_push_tail (seq->queue, iter1);
1031             g_queue_push_tail (seq->queue, iter2);
1032             g_queue_push_tail (seq->queue, iter3);
1033           }
1034           break;
1035         case ITER_PREV:
1036           {
1037             GSequenceIter *iter1, *iter2, *iter3, *begin;
1038
1039             iter1 = g_sequence_prepend (seq->sequence, new_item (seq));
1040             iter2 = g_sequence_prepend (seq->sequence, new_item (seq));
1041             iter3 = g_sequence_prepend (seq->sequence, new_item (seq));
1042
1043             begin = g_sequence_get_begin_iter (seq->sequence);
1044
1045             g_assert (g_sequence_iter_prev (iter1) == iter2);
1046             g_assert (g_sequence_iter_prev (iter2) == iter3);
1047             g_assert (iter3 == begin);
1048             g_assert (g_sequence_iter_prev (iter3) == begin);
1049             g_assert (g_sequence_iter_prev (begin) == begin);
1050
1051             g_queue_push_head (seq->queue, iter1);
1052             g_queue_push_head (seq->queue, iter2);
1053             g_queue_push_head (seq->queue, iter3);
1054           }
1055           break;
1056         case ITER_GET_POSITION:
1057           {
1058             GList *link;
1059             GSequenceIter *iter = get_random_iter (seq, &link);
1060
1061             g_assert (g_sequence_iter_get_position (iter) ==
1062                       queue_link_index (seq, link));
1063           }
1064           break;
1065         case ITER_MOVE:
1066           {
1067             int len = g_sequence_get_length (seq->sequence);
1068             GSequenceIter *iter;
1069             int pos;
1070
1071             iter = get_random_iter (seq, NULL);
1072             pos = g_sequence_iter_get_position (iter);
1073             iter = g_sequence_iter_move (iter, len - pos);
1074             g_assert (g_sequence_iter_is_end (iter));
1075
1076
1077             iter = get_random_iter (seq, NULL);
1078             pos = g_sequence_iter_get_position (iter);
1079             while (pos < len)
1080               {
1081                 g_assert (!g_sequence_iter_is_end (iter));
1082                 pos++;
1083                 iter = g_sequence_iter_move (iter, 1);
1084               }
1085             g_assert (g_sequence_iter_is_end (iter));
1086           }
1087           break;
1088         case ITER_GET_SEQUENCE:
1089           {
1090             GSequenceIter *iter = get_random_iter (seq, NULL);
1091
1092             g_assert (g_sequence_iter_get_sequence (iter) == seq->sequence);
1093           }
1094           break;
1095
1096           /* search */
1097         case ITER_COMPARE:
1098           {
1099             GList *link1, *link2;
1100             GSequenceIter *iter1 = get_random_iter (seq, &link1);
1101             GSequenceIter *iter2 = get_random_iter (seq, &link2);
1102
1103             int cmp = g_sequence_iter_compare (iter1, iter2);
1104             int pos1 = queue_link_index (seq, link1);
1105             int pos2 = queue_link_index (seq, link2);
1106
1107             if (cmp == 0)
1108               {
1109                 g_assert (pos1 == pos2);
1110               }
1111             else if (cmp < 0)
1112               {
1113                 g_assert (pos1 < pos2);
1114               }
1115             else
1116               {
1117                 g_assert (pos1 > pos2);
1118               }
1119           }
1120           break;
1121         case RANGE_GET_MIDPOINT:
1122           {
1123             GSequenceIter *iter1 = get_random_iter (seq, NULL);
1124             GSequenceIter *iter2 = get_random_iter (seq, NULL);
1125             GSequenceIter *iter3;
1126             int cmp;
1127
1128             cmp = g_sequence_iter_compare (iter1, iter2);
1129
1130             if (cmp > 0)
1131               {
1132                 GSequenceIter *tmp;
1133
1134                 tmp = iter1;
1135                 iter1 = iter2;
1136                 iter2 = tmp;
1137               }
1138
1139             iter3 = g_sequence_range_get_midpoint (iter1, iter2);
1140
1141             if (cmp == 0)
1142               {
1143                 g_assert (iter3 == iter1);
1144                 g_assert (iter3 == iter2);
1145               }
1146
1147             g_assert (g_sequence_iter_get_position (iter3) >=
1148                       g_sequence_iter_get_position (iter1));
1149             g_assert (g_sequence_iter_get_position (iter2) >=
1150                       g_sequence_iter_get_position (iter3));
1151           }
1152           break;
1153
1154         }
1155
1156       check_integrity (seq);
1157     }
1158
1159   for (k = 0; k < N_SEQUENCES; ++k)
1160     {
1161       g_queue_free (sequences[k].queue);
1162       g_sequence_free (sequences[k].sequence);
1163       sequences[k].n_items = 0;
1164     }
1165 }
1166
1167 /* Random seeds known to have failed at one point
1168  */
1169 static gulong seeds[] =
1170   {
1171     825541564u,
1172     801678400u,
1173     1477639090u,
1174     3369132895u,
1175     1192944867u,
1176     770458294u,
1177     1099575817u,
1178     590523467u,
1179     3583571454u,
1180     579241222u
1181   };
1182
1183 /* Single, stand-alone tests */
1184
1185 static void
1186 test_out_of_range_jump (void)
1187 {
1188   GSequence *seq = g_sequence_new (NULL);
1189   GSequenceIter *iter = g_sequence_get_begin_iter (seq);
1190
1191   g_sequence_iter_move (iter, 5);
1192
1193   g_assert (g_sequence_iter_is_begin (iter));
1194   g_assert (g_sequence_iter_is_end (iter));
1195
1196   g_sequence_free (seq);
1197 }
1198
1199 static void
1200 test_iter_move (void)
1201 {
1202   GSequence *seq = g_sequence_new (NULL);
1203   GSequenceIter *iter;
1204   gint i;
1205
1206   for (i = 0; i < 10; ++i)
1207     g_sequence_append (seq, GINT_TO_POINTER (i));
1208
1209   iter = g_sequence_get_begin_iter (seq);
1210   iter = g_sequence_iter_move (iter, 5);
1211   g_assert_cmpint (GPOINTER_TO_INT (g_sequence_get (iter)), ==, 5);
1212
1213   iter = g_sequence_iter_move (iter, -10);
1214   g_assert (g_sequence_iter_is_begin (iter));
1215
1216   iter = g_sequence_get_end_iter (seq);
1217   iter = g_sequence_iter_move (iter, -5);
1218   g_assert_cmpint (GPOINTER_TO_INT (g_sequence_get (iter)), ==, 5);
1219
1220   iter = g_sequence_iter_move (iter, 10);
1221   g_assert (g_sequence_iter_is_end (iter));
1222
1223   g_sequence_free (seq);
1224 }
1225
1226 static int
1227 compare (gconstpointer a, gconstpointer b, gpointer userdata)
1228 {
1229   int ai, bi;
1230
1231   ai = GPOINTER_TO_INT (a);
1232   bi = GPOINTER_TO_INT (b);
1233
1234   if (ai < bi)
1235     return -1;
1236   else if (ai > bi)
1237     return 1;
1238   else
1239     return 0;
1240 }
1241
1242 static int
1243 compare_iter (GSequenceIter *a,
1244               GSequenceIter *b,
1245               gpointer data)
1246 {
1247   return compare (g_sequence_get (a),
1248                   g_sequence_get (b),
1249                   data);
1250 }
1251
1252 static void
1253 test_insert_sorted_non_pointer (void)
1254 {
1255   int i;
1256
1257   for (i = 0; i < 10; i++)
1258     {
1259       GSequence *seq = g_sequence_new (NULL);
1260       int j;
1261
1262       for (j = 0; j < 10000; j++)
1263         {
1264           g_sequence_insert_sorted (seq, GINT_TO_POINTER (g_random_int()),
1265                                     compare, NULL);
1266
1267           g_sequence_insert_sorted_iter (seq, GINT_TO_POINTER (g_random_int()),
1268                                          compare_iter, NULL);
1269         }
1270
1271       g_sequence_check (seq);
1272
1273       g_sequence_free (seq);
1274     }
1275 }
1276
1277 static void
1278 test_stable_sort (void)
1279 {
1280   int i;
1281   GSequence *seq = g_sequence_new (NULL);
1282
1283 #define N_ITEMS 1000
1284
1285   GSequenceIter *iters[N_ITEMS];
1286   GSequenceIter *iter;
1287
1288   for (i = 0; i < N_ITEMS; ++i)
1289     {
1290       iters[i] = g_sequence_append (seq, GINT_TO_POINTER (3000));
1291       g_sequence_check (seq);
1292       g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
1293    }
1294
1295   i = 0;
1296   iter = g_sequence_get_begin_iter (seq);
1297   g_assert (g_sequence_iter_get_sequence (iter) == seq);
1298   g_sequence_check (seq);
1299   while (!g_sequence_iter_is_end (iter))
1300     {
1301       g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
1302       g_assert (iters[i++] == iter);
1303
1304       iter = g_sequence_iter_next (iter);
1305       g_sequence_check (seq);
1306     }
1307
1308   g_sequence_sort (seq, compare, NULL);
1309
1310   i = 0;
1311   iter = g_sequence_get_begin_iter (seq);
1312   while (!g_sequence_iter_is_end (iter))
1313     {
1314       g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
1315       g_assert (iters[i] == iter);
1316
1317       iter = g_sequence_iter_next (iter);
1318       g_sequence_check (seq);
1319
1320       i++;
1321     }
1322
1323   for (i = N_ITEMS - 1; i >= 0; --i)
1324     {
1325       g_sequence_check (seq);
1326       g_assert (g_sequence_iter_get_sequence (iters[i]) == seq);
1327       g_assert (g_sequence_get_end_iter (seq) != iters[i]);
1328       g_sequence_sort_changed (iters[i], compare, NULL);
1329     }
1330
1331   i = 0;
1332   iter = g_sequence_get_begin_iter (seq);
1333   while (!g_sequence_iter_is_end (iter))
1334     {
1335       g_assert (iters[i++] == iter);
1336
1337       iter = g_sequence_iter_next (iter);
1338       g_sequence_check (seq);
1339     }
1340
1341   g_sequence_free (seq);
1342 }
1343
1344 static void
1345 test_empty (void)
1346 {
1347   GSequence *seq;
1348   int i;
1349
1350   seq = g_sequence_new (NULL);
1351   g_assert_true (g_sequence_is_empty (seq));
1352
1353   for (i = 0; i < 1000; i++)
1354     {
1355       g_sequence_append (seq, GINT_TO_POINTER (i));
1356       g_assert_false (g_sequence_is_empty (seq));
1357     }
1358
1359   for (i = 0; i < 1000; i++)
1360     {
1361       GSequenceIter *end = g_sequence_get_end_iter (seq);
1362       g_assert_false (g_sequence_is_empty (seq));
1363       g_sequence_remove (g_sequence_iter_prev (end));
1364     }
1365
1366   g_assert_true (g_sequence_is_empty (seq));
1367
1368   g_sequence_free (seq);
1369 }
1370
1371 int
1372 main (int argc,
1373       char **argv)
1374 {
1375   gsize i;
1376   guint32 seed;
1377   gchar *path;
1378
1379   g_test_init (&argc, &argv, NULL);
1380
1381   /* Standalone tests */
1382   g_test_add_func ("/sequence/out-of-range-jump", test_out_of_range_jump);
1383   g_test_add_func ("/sequence/iter-move", test_iter_move);
1384   g_test_add_func ("/sequence/insert-sorted-non-pointer", test_insert_sorted_non_pointer);
1385   g_test_add_func ("/sequence/stable-sort", test_stable_sort);
1386   g_test_add_func ("/sequence/is_empty", test_empty);
1387
1388   /* Regression tests */
1389   for (i = 0; i < G_N_ELEMENTS (seeds); ++i)
1390     {
1391       path = g_strdup_printf ("/sequence/random/seed:%lu", seeds[i]);
1392       g_test_add_data_func (path, GUINT_TO_POINTER (seeds[i]), run_random_tests);
1393       g_free (path);
1394     }
1395
1396   /* New random seed */
1397   seed = g_test_rand_int_range (0, G_MAXINT);
1398   path = g_strdup_printf ("/sequence/random/seed:%u", seed);
1399   g_test_add_data_func (path, GUINT_TO_POINTER (seed), run_random_tests);
1400   g_free (path);
1401
1402   return g_test_run ();
1403 }