Coverage Report

Created: 2025-08-03 06:57

/src/glib/glib/gsequence.c
Line
Count
Source (jump to first uncovered line)
1
/* GLIB - Library of useful routines for C programming
2
 * Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007
3
 * Soeren Sandmann (sandmann@daimi.au.dk)
4
 *
5
 * This library is free software; you can redistribute it and/or
6
 * modify it under the terms of the GNU Lesser General Public
7
 * License as published by the Free Software Foundation; either
8
 * version 2.1 of the License, or (at your option) any later version.
9
 *
10
 * This library is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
 * Lesser General Public License for more details.
14
 *
15
 * You should have received a copy of the GNU Lesser General Public
16
 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
17
 */
18
19
#include "config.h"
20
21
#include "gsequence.h"
22
23
#include "gmem.h"
24
#include "gtestutils.h"
25
#include "gslice.h"
26
/**
27
 * SECTION:sequence
28
 * @title: Sequences
29
 * @short_description: scalable lists
30
 *
31
 * The #GSequence data structure has the API of a list, but is
32
 * implemented internally with a balanced binary tree. This means that
33
 * most of the operations  (access, search, insertion, deletion, ...) on
34
 * #GSequence are O(log(n)) in average and O(n) in worst case for time
35
 * complexity. But, note that maintaining a balanced sorted list of n
36
 * elements is done in time O(n log(n)).
37
 * The data contained in each element can be either integer values, by using
38
 * of the [Type Conversion Macros][glib-Type-Conversion-Macros], or simply
39
 * pointers to any type of data.
40
 *
41
 * A #GSequence is accessed through "iterators", represented by a
42
 * #GSequenceIter. An iterator represents a position between two
43
 * elements of the sequence. For example, the "begin" iterator
44
 * represents the gap immediately before the first element of the
45
 * sequence, and the "end" iterator represents the gap immediately
46
 * after the last element. In an empty sequence, the begin and end
47
 * iterators are the same.
48
 *
49
 * Some methods on #GSequence operate on ranges of items. For example
50
 * g_sequence_foreach_range() will call a user-specified function on
51
 * each element with the given range. The range is delimited by the
52
 * gaps represented by the passed-in iterators, so if you pass in the
53
 * begin and end iterators, the range in question is the entire
54
 * sequence.
55
 *
56
 * The function g_sequence_get() is used with an iterator to access the
57
 * element immediately following the gap that the iterator represents.
58
 * The iterator is said to "point" to that element.
59
 *
60
 * Iterators are stable across most operations on a #GSequence. For
61
 * example an iterator pointing to some element of a sequence will
62
 * continue to point to that element even after the sequence is sorted.
63
 * Even moving an element to another sequence using for example
64
 * g_sequence_move_range() will not invalidate the iterators pointing
65
 * to it. The only operation that will invalidate an iterator is when
66
 * the element it points to is removed from any sequence.
67
 *
68
 * To sort the data, either use g_sequence_insert_sorted() or
69
 * g_sequence_insert_sorted_iter() to add data to the #GSequence or, if
70
 * you want to add a large amount of data, it is more efficient to call
71
 * g_sequence_sort() or g_sequence_sort_iter() after doing unsorted
72
 * insertions.
73
 */
74
75
/**
76
 * GSequenceIter:
77
 *
78
 * The #GSequenceIter struct is an opaque data type representing an
79
 * iterator pointing into a #GSequence.
80
 */
81
82
/**
83
 * GSequenceIterCompareFunc:
84
 * @a: a #GSequenceIter
85
 * @b: a #GSequenceIter
86
 * @data: user data
87
 *
88
 * A #GSequenceIterCompareFunc is a function used to compare iterators.
89
 * It must return zero if the iterators compare equal, a negative value
90
 * if @a comes before @b, and a positive value if @b comes before @a.
91
 *
92
 * Returns: zero if the iterators are equal, a negative value if @a
93
 *     comes before @b, and a positive value if @b comes before @a.
94
 */
95
96
typedef struct _GSequenceNode GSequenceNode;
97
98
/**
99
 * GSequence:
100
 *
101
 * The #GSequence struct is an opaque data type representing a
102
 * [sequence][glib-Sequences] data type.
103
 */
104
struct _GSequence
105
{
106
  GSequenceNode *       end_node;
107
  GDestroyNotify        data_destroy_notify;
108
  gboolean              access_prohibited;
109
110
  /* The 'real_sequence' is used when temporary sequences are created
111
   * to hold nodes that are being rearranged. The 'real_sequence' of such
112
   * a temporary sequence points to the sequence that is actually being
113
   * manipulated. The only reason we need this is so that when the
114
   * sort/sort_changed/search_iter() functions call out to the application
115
   * g_sequence_iter_get_sequence() will return the correct sequence.
116
   */
117
  GSequence *           real_sequence;
118
};
119
120
struct _GSequenceNode
121
{
122
  gint                  n_nodes;
123
  GSequenceNode *       parent;
124
  GSequenceNode *       left;
125
  GSequenceNode *       right;
126
  gpointer              data;   /* For the end node, this field points
127
                                 * to the sequence
128
                                 */
129
};
130
131
/*
132
 * Declaration of GSequenceNode methods
133
 */
134
static GSequenceNode *node_new           (gpointer                  data);
135
static GSequenceNode *node_get_first     (GSequenceNode            *node);
136
static GSequenceNode *node_get_last      (GSequenceNode            *node);
137
static GSequenceNode *node_get_prev      (GSequenceNode            *node);
138
static GSequenceNode *node_get_next      (GSequenceNode            *node);
139
static gint           node_get_pos       (GSequenceNode            *node);
140
static GSequenceNode *node_get_by_pos    (GSequenceNode            *node,
141
                                          gint                      pos);
142
static GSequenceNode *node_find          (GSequenceNode            *haystack,
143
                                          GSequenceNode            *needle,
144
                                          GSequenceNode            *end,
145
                                          GSequenceIterCompareFunc  cmp,
146
                                          gpointer                  user_data);
147
static GSequenceNode *node_find_closest  (GSequenceNode            *haystack,
148
                                          GSequenceNode            *needle,
149
                                          GSequenceNode            *end,
150
                                          GSequenceIterCompareFunc  cmp,
151
                                          gpointer                  user_data);
152
static gint           node_get_length    (GSequenceNode            *node);
153
static void           node_free          (GSequenceNode            *node,
154
                                          GSequence                *seq);
155
static void           node_cut           (GSequenceNode            *split);
156
static void           node_insert_before (GSequenceNode            *node,
157
                                          GSequenceNode            *new);
158
static void           node_unlink        (GSequenceNode            *node);
159
static void           node_join          (GSequenceNode            *left,
160
                                          GSequenceNode            *right);
161
static void           node_insert_sorted (GSequenceNode            *node,
162
                                          GSequenceNode            *new,
163
                                          GSequenceNode            *end,
164
                                          GSequenceIterCompareFunc  cmp_func,
165
                                          gpointer                  cmp_data);
166
167
168
/*
169
 * Various helper functions
170
 */
171
static void
172
check_seq_access (GSequence *seq)
173
0
{
174
0
  if (G_UNLIKELY (seq->access_prohibited))
175
0
    {
176
0
      g_warning ("Accessing a sequence while it is "
177
0
                 "being sorted or searched is not allowed");
178
0
    }
179
0
}
180
181
static GSequence *
182
get_sequence (GSequenceNode *node)
183
0
{
184
0
  return (GSequence *)node_get_last (node)->data;
185
0
}
186
187
static gboolean
188
seq_is_end (GSequence     *seq,
189
            GSequenceIter *iter)
190
0
{
191
0
  return seq->end_node == iter;
192
0
}
193
194
static gboolean
195
is_end (GSequenceIter *iter)
196
0
{
197
0
  GSequenceIter *parent = iter->parent;
198
199
0
  if (iter->right)
200
0
    return FALSE;
201
202
0
  if (!parent)
203
0
    return TRUE;
204
205
0
  while (parent->right == iter)
206
0
    {
207
0
      iter = parent;
208
0
      parent = iter->parent;
209
210
0
      if (!parent)
211
0
        return TRUE;
212
0
    }
213
214
0
  return FALSE;
215
0
}
216
217
typedef struct
218
{
219
  GCompareDataFunc  cmp_func;
220
  gpointer          cmp_data;
221
  GSequenceNode    *end_node;
222
} SortInfo;
223
224
/* This function compares two iters using a normal compare
225
 * function and user_data passed in in a SortInfo struct
226
 */
227
static gint
228
iter_compare (GSequenceIter *node1,
229
              GSequenceIter *node2,
230
              gpointer       data)
231
0
{
232
0
  const SortInfo *info = data;
233
0
  gint retval;
234
235
0
  if (node1 == info->end_node)
236
0
    return 1;
237
238
0
  if (node2 == info->end_node)
239
0
    return -1;
240
241
0
  retval = info->cmp_func (node1->data, node2->data, info->cmp_data);
242
243
0
  return retval;
244
0
}
245
246
/*
247
 * Public API
248
 */
249
250
/**
251
 * g_sequence_new:
252
 * @data_destroy: (nullable): a #GDestroyNotify function, or %NULL
253
 *
254
 * Creates a new GSequence. The @data_destroy function, if non-%NULL will
255
 * be called on all items when the sequence is destroyed and on items that
256
 * are removed from the sequence.
257
 *
258
 * Returns: (transfer full): a new #GSequence
259
 *
260
 * Since: 2.14
261
 **/
262
GSequence *
263
g_sequence_new (GDestroyNotify data_destroy)
264
0
{
265
0
  GSequence *seq = g_new (GSequence, 1);
266
0
  seq->data_destroy_notify = data_destroy;
267
268
0
  seq->end_node = node_new (seq);
269
270
0
  seq->access_prohibited = FALSE;
271
272
0
  seq->real_sequence = seq;
273
274
0
  return seq;
275
0
}
276
277
/**
278
 * g_sequence_free:
279
 * @seq: a #GSequence
280
 *
281
 * Frees the memory allocated for @seq. If @seq has a data destroy
282
 * function associated with it, that function is called on all items
283
 * in @seq.
284
 *
285
 * Since: 2.14
286
 */
287
void
288
g_sequence_free (GSequence *seq)
289
0
{
290
0
  g_return_if_fail (seq != NULL);
291
292
0
  check_seq_access (seq);
293
294
0
  node_free (seq->end_node, seq);
295
296
0
  g_free (seq);
297
0
}
298
299
/**
300
 * g_sequence_foreach_range:
301
 * @begin: a #GSequenceIter
302
 * @end: a #GSequenceIter
303
 * @func: a #GFunc
304
 * @user_data: user data passed to @func
305
 *
306
 * Calls @func for each item in the range (@begin, @end) passing
307
 * @user_data to the function. @func must not modify the sequence
308
 * itself.
309
 *
310
 * Since: 2.14
311
 */
312
void
313
g_sequence_foreach_range (GSequenceIter *begin,
314
                          GSequenceIter *end,
315
                          GFunc          func,
316
                          gpointer       user_data)
317
0
{
318
0
  GSequence *seq;
319
0
  GSequenceIter *iter;
320
321
0
  g_return_if_fail (func != NULL);
322
0
  g_return_if_fail (begin != NULL);
323
0
  g_return_if_fail (end != NULL);
324
325
0
  seq = get_sequence (begin);
326
327
0
  seq->access_prohibited = TRUE;
328
329
0
  iter = begin;
330
0
  while (iter != end)
331
0
    {
332
0
      GSequenceIter *next = node_get_next (iter);
333
334
0
      func (iter->data, user_data);
335
336
0
      iter = next;
337
0
    }
338
339
0
  seq->access_prohibited = FALSE;
340
0
}
341
342
/**
343
 * g_sequence_foreach:
344
 * @seq: a #GSequence
345
 * @func: the function to call for each item in @seq
346
 * @user_data: user data passed to @func
347
 *
348
 * Calls @func for each item in the sequence passing @user_data
349
 * to the function. @func must not modify the sequence itself.
350
 *
351
 * Since: 2.14
352
 */
353
void
354
g_sequence_foreach (GSequence *seq,
355
                    GFunc      func,
356
                    gpointer   user_data)
357
0
{
358
0
  GSequenceIter *begin, *end;
359
360
0
  check_seq_access (seq);
361
362
0
  begin = g_sequence_get_begin_iter (seq);
363
0
  end   = g_sequence_get_end_iter (seq);
364
365
0
  g_sequence_foreach_range (begin, end, func, user_data);
366
0
}
367
368
/**
369
 * g_sequence_range_get_midpoint:
370
 * @begin: a #GSequenceIter
371
 * @end: a #GSequenceIter
372
 *
373
 * Finds an iterator somewhere in the range (@begin, @end). This
374
 * iterator will be close to the middle of the range, but is not
375
 * guaranteed to be exactly in the middle.
376
 *
377
 * The @begin and @end iterators must both point to the same sequence
378
 * and @begin must come before or be equal to @end in the sequence.
379
 *
380
 * Returns: (transfer none): a #GSequenceIter pointing somewhere in the
381
 *    (@begin, @end) range
382
 *
383
 * Since: 2.14
384
 */
385
GSequenceIter *
386
g_sequence_range_get_midpoint (GSequenceIter *begin,
387
                               GSequenceIter *end)
388
0
{
389
0
  int begin_pos, end_pos, mid_pos;
390
391
0
  g_return_val_if_fail (begin != NULL, NULL);
392
0
  g_return_val_if_fail (end != NULL, NULL);
393
0
  g_return_val_if_fail (get_sequence (begin) == get_sequence (end), NULL);
394
395
0
  begin_pos = node_get_pos (begin);
396
0
  end_pos = node_get_pos (end);
397
398
0
  g_return_val_if_fail (end_pos >= begin_pos, NULL);
399
400
0
  mid_pos = begin_pos + (end_pos - begin_pos) / 2;
401
402
0
  return node_get_by_pos (begin, mid_pos);
403
0
}
404
405
/**
406
 * g_sequence_iter_compare:
407
 * @a: a #GSequenceIter
408
 * @b: a #GSequenceIter
409
 *
410
 * Returns a negative number if @a comes before @b, 0 if they are equal,
411
 * and a positive number if @a comes after @b.
412
 *
413
 * The @a and @b iterators must point into the same sequence.
414
 *
415
 * Returns: a negative number if @a comes before @b, 0 if they are
416
 *     equal, and a positive number if @a comes after @b
417
 *
418
 * Since: 2.14
419
 */
420
gint
421
g_sequence_iter_compare (GSequenceIter *a,
422
                         GSequenceIter *b)
423
0
{
424
0
  gint a_pos, b_pos;
425
0
  GSequence *seq_a, *seq_b;
426
427
0
  g_return_val_if_fail (a != NULL, 0);
428
0
  g_return_val_if_fail (b != NULL, 0);
429
430
0
  seq_a = get_sequence (a);
431
0
  seq_b = get_sequence (b);
432
0
  g_return_val_if_fail (seq_a == seq_b, 0);
433
434
0
  check_seq_access (seq_a);
435
0
  check_seq_access (seq_b);
436
437
0
  a_pos = node_get_pos (a);
438
0
  b_pos = node_get_pos (b);
439
440
0
  if (a_pos == b_pos)
441
0
    return 0;
442
0
  else if (a_pos > b_pos)
443
0
    return 1;
444
0
  else
445
0
    return -1;
446
0
}
447
448
/**
449
 * g_sequence_append:
450
 * @seq: a #GSequence
451
 * @data: the data for the new item
452
 *
453
 * Adds a new item to the end of @seq.
454
 *
455
 * Returns: (transfer none): an iterator pointing to the new item
456
 *
457
 * Since: 2.14
458
 */
459
GSequenceIter *
460
g_sequence_append (GSequence *seq,
461
                   gpointer   data)
462
0
{
463
0
  GSequenceNode *node;
464
465
0
  g_return_val_if_fail (seq != NULL, NULL);
466
467
0
  check_seq_access (seq);
468
469
0
  node = node_new (data);
470
0
  node_insert_before (seq->end_node, node);
471
472
0
  return node;
473
0
}
474
475
/**
476
 * g_sequence_prepend:
477
 * @seq: a #GSequence
478
 * @data: the data for the new item
479
 *
480
 * Adds a new item to the front of @seq
481
 *
482
 * Returns: (transfer none): an iterator pointing to the new item
483
 *
484
 * Since: 2.14
485
 */
486
GSequenceIter *
487
g_sequence_prepend (GSequence *seq,
488
                    gpointer   data)
489
0
{
490
0
  GSequenceNode *node, *first;
491
492
0
  g_return_val_if_fail (seq != NULL, NULL);
493
494
0
  check_seq_access (seq);
495
496
0
  node = node_new (data);
497
0
  first = node_get_first (seq->end_node);
498
499
0
  node_insert_before (first, node);
500
501
0
  return node;
502
0
}
503
504
/**
505
 * g_sequence_insert_before:
506
 * @iter: a #GSequenceIter
507
 * @data: the data for the new item
508
 *
509
 * Inserts a new item just before the item pointed to by @iter.
510
 *
511
 * Returns: (transfer none): an iterator pointing to the new item
512
 *
513
 * Since: 2.14
514
 */
515
GSequenceIter *
516
g_sequence_insert_before (GSequenceIter *iter,
517
                          gpointer       data)
518
0
{
519
0
  GSequence *seq;
520
0
  GSequenceNode *node;
521
522
0
  g_return_val_if_fail (iter != NULL, NULL);
523
524
0
  seq = get_sequence (iter);
525
0
  check_seq_access (seq);
526
527
0
  node = node_new (data);
528
529
0
  node_insert_before (iter, node);
530
531
0
  return node;
532
0
}
533
534
/**
535
 * g_sequence_remove:
536
 * @iter: a #GSequenceIter
537
 *
538
 * Removes the item pointed to by @iter. It is an error to pass the
539
 * end iterator to this function.
540
 *
541
 * If the sequence has a data destroy function associated with it, this
542
 * function is called on the data for the removed item.
543
 *
544
 * Since: 2.14
545
 */
546
void
547
g_sequence_remove (GSequenceIter *iter)
548
0
{
549
0
  GSequence *seq;
550
551
0
  g_return_if_fail (iter != NULL);
552
553
0
  seq = get_sequence (iter);
554
0
  g_return_if_fail (!seq_is_end (seq, iter));
555
556
0
  check_seq_access (seq);
557
558
0
  node_unlink (iter);
559
0
  node_free (iter, seq);
560
0
}
561
562
/**
563
 * g_sequence_remove_range:
564
 * @begin: a #GSequenceIter
565
 * @end: a #GSequenceIter
566
 *
567
 * Removes all items in the (@begin, @end) range.
568
 *
569
 * If the sequence has a data destroy function associated with it, this
570
 * function is called on the data for the removed items.
571
 *
572
 * Since: 2.14
573
 */
574
void
575
g_sequence_remove_range (GSequenceIter *begin,
576
                         GSequenceIter *end)
577
0
{
578
0
  GSequence *seq_begin, *seq_end;
579
580
0
  seq_begin = get_sequence (begin);
581
0
  seq_end = get_sequence (end);
582
0
  g_return_if_fail (seq_begin == seq_end);
583
  /* check_seq_access() calls are done by g_sequence_move_range() */
584
585
0
  g_sequence_move_range (NULL, begin, end);
586
0
}
587
588
/**
589
 * g_sequence_move_range:
590
 * @dest: a #GSequenceIter
591
 * @begin: a #GSequenceIter
592
 * @end: a #GSequenceIter
593
 *
594
 * Inserts the (@begin, @end) range at the destination pointed to by @dest.
595
 * The @begin and @end iters must point into the same sequence. It is
596
 * allowed for @dest to point to a different sequence than the one pointed
597
 * into by @begin and @end.
598
 *
599
 * If @dest is %NULL, the range indicated by @begin and @end is
600
 * removed from the sequence. If @dest points to a place within
601
 * the (@begin, @end) range, the range does not move.
602
 *
603
 * Since: 2.14
604
 */
605
void
606
g_sequence_move_range (GSequenceIter *dest,
607
                       GSequenceIter *begin,
608
                       GSequenceIter *end)
609
0
{
610
0
  GSequence *src_seq, *end_seq, *dest_seq;
611
0
  GSequenceNode *first;
612
613
0
  g_return_if_fail (begin != NULL);
614
0
  g_return_if_fail (end != NULL);
615
616
0
  src_seq = get_sequence (begin);
617
0
  check_seq_access (src_seq);
618
619
0
  end_seq = get_sequence (end);
620
0
  check_seq_access (end_seq);
621
622
0
  if (dest)
623
0
    {
624
0
      dest_seq = get_sequence (dest);
625
0
      check_seq_access (dest_seq);
626
0
    }
627
628
0
  g_return_if_fail (src_seq == end_seq);
629
630
  /* Dest points to begin or end? */
631
0
  if (dest == begin || dest == end)
632
0
    return;
633
634
  /* begin comes after end? */
635
0
  if (g_sequence_iter_compare (begin, end) >= 0)
636
0
    return;
637
638
  /* dest points somewhere in the (begin, end) range? */
639
0
  if (dest && dest_seq == src_seq &&
640
0
      g_sequence_iter_compare (dest, begin) > 0 &&
641
0
      g_sequence_iter_compare (dest, end) < 0)
642
0
    {
643
0
      return;
644
0
    }
645
646
0
  first = node_get_first (begin);
647
648
0
  node_cut (begin);
649
650
0
  node_cut (end);
651
652
0
  if (first != begin)
653
0
    node_join (first, end);
654
655
0
  if (dest)
656
0
    {
657
0
      first = node_get_first (dest);
658
659
0
      node_cut (dest);
660
661
0
      node_join (begin, dest);
662
663
0
      if (dest != first)
664
0
        node_join (first, begin);
665
0
    }
666
0
  else
667
0
    {
668
0
      node_free (begin, src_seq);
669
0
    }
670
0
}
671
672
/**
673
 * g_sequence_sort:
674
 * @seq: a #GSequence
675
 * @cmp_func: the function used to sort the sequence
676
 * @cmp_data: user data passed to @cmp_func
677
 *
678
 * Sorts @seq using @cmp_func.
679
 *
680
 * @cmp_func is passed two items of @seq and should
681
 * return 0 if they are equal, a negative value if the
682
 * first comes before the second, and a positive value
683
 * if the second comes before the first.
684
 *
685
 * Since: 2.14
686
 */
687
void
688
g_sequence_sort (GSequence        *seq,
689
                 GCompareDataFunc  cmp_func,
690
                 gpointer          cmp_data)
691
0
{
692
0
  SortInfo info;
693
694
0
  info.cmp_func = cmp_func;
695
0
  info.cmp_data = cmp_data;
696
0
  info.end_node = seq->end_node;
697
698
0
  check_seq_access (seq);
699
700
0
  g_sequence_sort_iter (seq, iter_compare, &info);
701
0
}
702
703
/**
704
 * g_sequence_insert_sorted:
705
 * @seq: a #GSequence
706
 * @data: the data to insert
707
 * @cmp_func: the function used to compare items in the sequence
708
 * @cmp_data: user data passed to @cmp_func.
709
 *
710
 * Inserts @data into @seq using @cmp_func to determine the new
711
 * position. The sequence must already be sorted according to @cmp_func;
712
 * otherwise the new position of @data is undefined.
713
 *
714
 * @cmp_func is called with two items of the @seq, and @cmp_data.
715
 * It should return 0 if the items are equal, a negative value
716
 * if the first item comes before the second, and a positive value
717
 * if the second item comes before the first.
718
 *
719
 * Note that when adding a large amount of data to a #GSequence,
720
 * it is more efficient to do unsorted insertions and then call
721
 * g_sequence_sort() or g_sequence_sort_iter().
722
 *
723
 * Returns: (transfer none): a #GSequenceIter pointing to the new item.
724
 *
725
 * Since: 2.14
726
 */
727
GSequenceIter *
728
g_sequence_insert_sorted (GSequence        *seq,
729
                          gpointer          data,
730
                          GCompareDataFunc  cmp_func,
731
                          gpointer          cmp_data)
732
0
{
733
0
  SortInfo info;
734
735
0
  g_return_val_if_fail (seq != NULL, NULL);
736
0
  g_return_val_if_fail (cmp_func != NULL, NULL);
737
738
0
  info.cmp_func = cmp_func;
739
0
  info.cmp_data = cmp_data;
740
0
  info.end_node = seq->end_node;
741
0
  check_seq_access (seq);
742
743
0
  return g_sequence_insert_sorted_iter (seq, data, iter_compare, &info);
744
0
}
745
746
/**
747
 * g_sequence_sort_changed:
748
 * @iter: A #GSequenceIter
749
 * @cmp_func: the function used to compare items in the sequence
750
 * @cmp_data: user data passed to @cmp_func.
751
 *
752
 * Moves the data pointed to by @iter to a new position as indicated by
753
 * @cmp_func. This
754
 * function should be called for items in a sequence already sorted according
755
 * to @cmp_func whenever some aspect of an item changes so that @cmp_func
756
 * may return different values for that item.
757
 *
758
 * @cmp_func is called with two items of the @seq, and @cmp_data.
759
 * It should return 0 if the items are equal, a negative value if
760
 * the first item comes before the second, and a positive value if
761
 * the second item comes before the first.
762
 *
763
 * Since: 2.14
764
 */
765
void
766
g_sequence_sort_changed (GSequenceIter    *iter,
767
                         GCompareDataFunc  cmp_func,
768
                         gpointer          cmp_data)
769
0
{
770
0
  GSequence *seq;
771
0
  SortInfo info;
772
773
0
  g_return_if_fail (iter != NULL);
774
775
0
  seq = get_sequence (iter);
776
  /* check_seq_access() call is done by g_sequence_sort_changed_iter() */
777
0
  g_return_if_fail (!seq_is_end (seq, iter));
778
779
0
  info.cmp_func = cmp_func;
780
0
  info.cmp_data = cmp_data;
781
0
  info.end_node = seq->end_node;
782
783
0
  g_sequence_sort_changed_iter (iter, iter_compare, &info);
784
0
}
785
786
/**
787
 * g_sequence_search:
788
 * @seq: a #GSequence
789
 * @data: data for the new item
790
 * @cmp_func: the function used to compare items in the sequence
791
 * @cmp_data: user data passed to @cmp_func
792
 *
793
 * Returns an iterator pointing to the position where @data would
794
 * be inserted according to @cmp_func and @cmp_data.
795
 *
796
 * @cmp_func is called with two items of the @seq, and @cmp_data.
797
 * It should return 0 if the items are equal, a negative value if
798
 * the first item comes before the second, and a positive value if
799
 * the second item comes before the first.
800
 *
801
 * If you are simply searching for an existing element of the sequence,
802
 * consider using g_sequence_lookup().
803
 *
804
 * This function will fail if the data contained in the sequence is
805
 * unsorted.
806
 *
807
 * Returns: (transfer none): an #GSequenceIter pointing to the position where @data
808
 *     would have been inserted according to @cmp_func and @cmp_data
809
 *
810
 * Since: 2.14
811
 */
812
GSequenceIter *
813
g_sequence_search (GSequence        *seq,
814
                   gpointer          data,
815
                   GCompareDataFunc  cmp_func,
816
                   gpointer          cmp_data)
817
0
{
818
0
  SortInfo info;
819
820
0
  g_return_val_if_fail (seq != NULL, NULL);
821
822
0
  info.cmp_func = cmp_func;
823
0
  info.cmp_data = cmp_data;
824
0
  info.end_node = seq->end_node;
825
0
  check_seq_access (seq);
826
827
0
  return g_sequence_search_iter (seq, data, iter_compare, &info);
828
0
}
829
830
/**
831
 * g_sequence_lookup:
832
 * @seq: a #GSequence
833
 * @data: data to look up
834
 * @cmp_func: the function used to compare items in the sequence
835
 * @cmp_data: user data passed to @cmp_func
836
 *
837
 * Returns an iterator pointing to the position of the first item found
838
 * equal to @data according to @cmp_func and @cmp_data. If more than one
839
 * item is equal, it is not guaranteed that it is the first which is
840
 * returned. In that case, you can use g_sequence_iter_next() and
841
 * g_sequence_iter_prev() to get others.
842
 *
843
 * @cmp_func is called with two items of the @seq, and @cmp_data.
844
 * It should return 0 if the items are equal, a negative value if
845
 * the first item comes before the second, and a positive value if
846
 * the second item comes before the first.
847
 *
848
 * This function will fail if the data contained in the sequence is
849
 * unsorted.
850
 *
851
 * Returns: (transfer none) (nullable): an #GSequenceIter pointing to the position of the
852
 *     first item found equal to @data according to @cmp_func and
853
 *     @cmp_data, or %NULL if no such item exists
854
 *
855
 * Since: 2.28
856
 */
857
GSequenceIter *
858
g_sequence_lookup (GSequence        *seq,
859
                   gpointer          data,
860
                   GCompareDataFunc  cmp_func,
861
                   gpointer          cmp_data)
862
0
{
863
0
  SortInfo info;
864
865
0
  g_return_val_if_fail (seq != NULL, NULL);
866
867
0
  info.cmp_func = cmp_func;
868
0
  info.cmp_data = cmp_data;
869
0
  info.end_node = seq->end_node;
870
0
  check_seq_access (seq);
871
872
0
  return g_sequence_lookup_iter (seq, data, iter_compare, &info);
873
0
}
874
875
/**
876
 * g_sequence_sort_iter:
877
 * @seq: a #GSequence
878
 * @cmp_func: the function used to compare iterators in the sequence
879
 * @cmp_data: user data passed to @cmp_func
880
 *
881
 * Like g_sequence_sort(), but uses a #GSequenceIterCompareFunc instead
882
 * of a #GCompareDataFunc as the compare function
883
 *
884
 * @cmp_func is called with two iterators pointing into @seq. It should
885
 * return 0 if the iterators are equal, a negative value if the first
886
 * iterator comes before the second, and a positive value if the second
887
 * iterator comes before the first.
888
 *
889
 * Since: 2.14
890
 */
891
void
892
g_sequence_sort_iter (GSequence                *seq,
893
                      GSequenceIterCompareFunc  cmp_func,
894
                      gpointer                  cmp_data)
895
0
{
896
0
  GSequence *tmp;
897
0
  GSequenceNode *begin, *end;
898
899
0
  g_return_if_fail (seq != NULL);
900
0
  g_return_if_fail (cmp_func != NULL);
901
902
0
  check_seq_access (seq);
903
904
0
  begin = g_sequence_get_begin_iter (seq);
905
0
  end   = g_sequence_get_end_iter (seq);
906
907
0
  tmp = g_sequence_new (NULL);
908
0
  tmp->real_sequence = seq;
909
910
0
  g_sequence_move_range (g_sequence_get_begin_iter (tmp), begin, end);
911
912
0
  seq->access_prohibited = TRUE;
913
0
  tmp->access_prohibited = TRUE;
914
915
0
  while (!g_sequence_is_empty (tmp))
916
0
    {
917
0
      GSequenceNode *node = g_sequence_get_begin_iter (tmp);
918
919
0
      node_insert_sorted (seq->end_node, node, seq->end_node,
920
0
                          cmp_func, cmp_data);
921
0
    }
922
923
0
  tmp->access_prohibited = FALSE;
924
0
  seq->access_prohibited = FALSE;
925
926
0
  g_sequence_free (tmp);
927
0
}
928
929
/**
930
 * g_sequence_sort_changed_iter:
931
 * @iter: a #GSequenceIter
932
 * @iter_cmp: the function used to compare iterators in the sequence
933
 * @cmp_data: user data passed to @cmp_func
934
 *
935
 * Like g_sequence_sort_changed(), but uses
936
 * a #GSequenceIterCompareFunc instead of a #GCompareDataFunc as
937
 * the compare function.
938
 *
939
 * @iter_cmp is called with two iterators pointing into the #GSequence that
940
 * @iter points into. It should
941
 * return 0 if the iterators are equal, a negative value if the first
942
 * iterator comes before the second, and a positive value if the second
943
 * iterator comes before the first.
944
 *
945
 * Since: 2.14
946
 */
947
void
948
g_sequence_sort_changed_iter (GSequenceIter            *iter,
949
                              GSequenceIterCompareFunc  iter_cmp,
950
                              gpointer                  cmp_data)
951
0
{
952
0
  GSequence *seq, *tmp_seq;
953
0
  GSequenceIter *next, *prev;
954
955
0
  g_return_if_fail (iter != NULL);
956
0
  g_return_if_fail (iter_cmp != NULL);
957
958
0
  seq = get_sequence (iter);
959
0
  g_return_if_fail (!seq_is_end (seq, iter));
960
961
0
  check_seq_access (seq);
962
963
  /* If one of the neighbours is equal to iter, then
964
   * don't move it. This ensures that sort_changed() is
965
   * a stable operation.
966
   */
967
968
0
  next = node_get_next (iter);
969
0
  prev = node_get_prev (iter);
970
971
0
  if (prev != iter && iter_cmp (prev, iter, cmp_data) == 0)
972
0
    return;
973
974
0
  if (!is_end (next) && iter_cmp (next, iter, cmp_data) == 0)
975
0
    return;
976
977
0
  seq->access_prohibited = TRUE;
978
979
0
  tmp_seq = g_sequence_new (NULL);
980
0
  tmp_seq->real_sequence = seq;
981
982
0
  node_unlink (iter);
983
0
  node_insert_before (tmp_seq->end_node, iter);
984
985
0
  node_insert_sorted (seq->end_node, iter, seq->end_node,
986
0
                      iter_cmp, cmp_data);
987
988
0
  g_sequence_free (tmp_seq);
989
990
0
  seq->access_prohibited = FALSE;
991
0
}
992
993
/**
994
 * g_sequence_insert_sorted_iter:
995
 * @seq: a #GSequence
996
 * @data: data for the new item
997
 * @iter_cmp: the function used to compare iterators in the sequence
998
 * @cmp_data: user data passed to @iter_cmp
999
 *
1000
 * Like g_sequence_insert_sorted(), but uses
1001
 * a #GSequenceIterCompareFunc instead of a #GCompareDataFunc as
1002
 * the compare function.
1003
 *
1004
 * @iter_cmp is called with two iterators pointing into @seq.
1005
 * It should return 0 if the iterators are equal, a negative
1006
 * value if the first iterator comes before the second, and a
1007
 * positive value if the second iterator comes before the first.
1008
 *
1009
 * Note that when adding a large amount of data to a #GSequence,
1010
 * it is more efficient to do unsorted insertions and then call
1011
 * g_sequence_sort() or g_sequence_sort_iter().
1012
 *
1013
 * Returns: (transfer none): a #GSequenceIter pointing to the new item
1014
 *
1015
 * Since: 2.14
1016
 */
1017
GSequenceIter *
1018
g_sequence_insert_sorted_iter (GSequence                *seq,
1019
                               gpointer                  data,
1020
                               GSequenceIterCompareFunc  iter_cmp,
1021
                               gpointer                  cmp_data)
1022
0
{
1023
0
  GSequenceNode *new_node;
1024
0
  GSequence *tmp_seq;
1025
1026
0
  g_return_val_if_fail (seq != NULL, NULL);
1027
0
  g_return_val_if_fail (iter_cmp != NULL, NULL);
1028
1029
0
  check_seq_access (seq);
1030
1031
0
  seq->access_prohibited = TRUE;
1032
1033
  /* Create a new temporary sequence and put the new node into
1034
   * that. The reason for this is that the user compare function
1035
   * will be called with the new node, and if it dereferences,
1036
   * "is_end" will be called on it. But that will crash if the
1037
   * node is not actually in a sequence.
1038
   *
1039
   * node_insert_sorted() makes sure the node is unlinked before
1040
   * it is inserted.
1041
   *
1042
   * The reason we need the "iter" versions at all is that that
1043
   * is the only kind of compare functions GtkTreeView can use.
1044
   */
1045
0
  tmp_seq = g_sequence_new (NULL);
1046
0
  tmp_seq->real_sequence = seq;
1047
1048
0
  new_node = g_sequence_append (tmp_seq, data);
1049
1050
0
  node_insert_sorted (seq->end_node, new_node,
1051
0
                      seq->end_node, iter_cmp, cmp_data);
1052
1053
0
  g_sequence_free (tmp_seq);
1054
1055
0
  seq->access_prohibited = FALSE;
1056
1057
0
  return new_node;
1058
0
}
1059
1060
/**
1061
 * g_sequence_search_iter:
1062
 * @seq: a #GSequence
1063
 * @data: data for the new item
1064
 * @iter_cmp: the function used to compare iterators in the sequence
1065
 * @cmp_data: user data passed to @iter_cmp
1066
 *
1067
 * Like g_sequence_search(), but uses a #GSequenceIterCompareFunc
1068
 * instead of a #GCompareDataFunc as the compare function.
1069
 *
1070
 * @iter_cmp is called with two iterators pointing into @seq.
1071
 * It should return 0 if the iterators are equal, a negative value
1072
 * if the first iterator comes before the second, and a positive
1073
 * value if the second iterator comes before the first.
1074
 *
1075
 * If you are simply searching for an existing element of the sequence,
1076
 * consider using g_sequence_lookup_iter().
1077
 *
1078
 * This function will fail if the data contained in the sequence is
1079
 * unsorted.
1080
 *
1081
 * Returns: (transfer none): a #GSequenceIter pointing to the position in @seq
1082
 *     where @data would have been inserted according to @iter_cmp
1083
 *     and @cmp_data
1084
 *
1085
 * Since: 2.14
1086
 */
1087
GSequenceIter *
1088
g_sequence_search_iter (GSequence                *seq,
1089
                        gpointer                  data,
1090
                        GSequenceIterCompareFunc  iter_cmp,
1091
                        gpointer                  cmp_data)
1092
0
{
1093
0
  GSequenceNode *node;
1094
0
  GSequenceNode *dummy;
1095
0
  GSequence *tmp_seq;
1096
1097
0
  g_return_val_if_fail (seq != NULL, NULL);
1098
1099
0
  check_seq_access (seq);
1100
1101
0
  seq->access_prohibited = TRUE;
1102
1103
0
  tmp_seq = g_sequence_new (NULL);
1104
0
  tmp_seq->real_sequence = seq;
1105
1106
0
  dummy = g_sequence_append (tmp_seq, data);
1107
1108
0
  node = node_find_closest (seq->end_node, dummy,
1109
0
                            seq->end_node, iter_cmp, cmp_data);
1110
1111
0
  g_sequence_free (tmp_seq);
1112
1113
0
  seq->access_prohibited = FALSE;
1114
1115
0
  return node;
1116
0
}
1117
1118
/**
1119
 * g_sequence_lookup_iter:
1120
 * @seq: a #GSequence
1121
 * @data: data to look up
1122
 * @iter_cmp: the function used to compare iterators in the sequence
1123
 * @cmp_data: user data passed to @iter_cmp
1124
 *
1125
 * Like g_sequence_lookup(), but uses a #GSequenceIterCompareFunc
1126
 * instead of a #GCompareDataFunc as the compare function.
1127
 *
1128
 * @iter_cmp is called with two iterators pointing into @seq.
1129
 * It should return 0 if the iterators are equal, a negative value
1130
 * if the first iterator comes before the second, and a positive
1131
 * value if the second iterator comes before the first.
1132
 *
1133
 * This function will fail if the data contained in the sequence is
1134
 * unsorted.
1135
 *
1136
 * Returns: (transfer none) (nullable): an #GSequenceIter pointing to the position of
1137
 *     the first item found equal to @data according to @iter_cmp
1138
 *     and @cmp_data, or %NULL if no such item exists
1139
 *
1140
 * Since: 2.28
1141
 */
1142
GSequenceIter *
1143
g_sequence_lookup_iter (GSequence                *seq,
1144
                        gpointer                  data,
1145
                        GSequenceIterCompareFunc  iter_cmp,
1146
                        gpointer                  cmp_data)
1147
0
{
1148
0
  GSequenceNode *node;
1149
0
  GSequenceNode *dummy;
1150
0
  GSequence *tmp_seq;
1151
1152
0
  g_return_val_if_fail (seq != NULL, NULL);
1153
1154
0
  check_seq_access (seq);
1155
1156
0
  seq->access_prohibited = TRUE;
1157
1158
0
  tmp_seq = g_sequence_new (NULL);
1159
0
  tmp_seq->real_sequence = seq;
1160
1161
0
  dummy = g_sequence_append (tmp_seq, data);
1162
1163
0
  node = node_find (seq->end_node, dummy,
1164
0
                    seq->end_node, iter_cmp, cmp_data);
1165
1166
0
  g_sequence_free (tmp_seq);
1167
1168
0
  seq->access_prohibited = FALSE;
1169
1170
0
  return node;
1171
0
}
1172
1173
/**
1174
 * g_sequence_iter_get_sequence:
1175
 * @iter: a #GSequenceIter
1176
 *
1177
 * Returns the #GSequence that @iter points into.
1178
 *
1179
 * Returns: (transfer none): the #GSequence that @iter points into
1180
 *
1181
 * Since: 2.14
1182
 */
1183
GSequence *
1184
g_sequence_iter_get_sequence (GSequenceIter *iter)
1185
0
{
1186
0
  GSequence *seq;
1187
1188
0
  g_return_val_if_fail (iter != NULL, NULL);
1189
1190
0
  seq = get_sequence (iter);
1191
1192
  /* For temporary sequences, this points to the sequence that
1193
   * is actually being manipulated
1194
   */
1195
0
  return seq->real_sequence;
1196
0
}
1197
1198
/**
1199
 * g_sequence_get:
1200
 * @iter: a #GSequenceIter
1201
 *
1202
 * Returns the data that @iter points to.
1203
 *
1204
 * Returns: (transfer none): the data that @iter points to
1205
 *
1206
 * Since: 2.14
1207
 */
1208
gpointer
1209
g_sequence_get (GSequenceIter *iter)
1210
0
{
1211
0
  g_return_val_if_fail (iter != NULL, NULL);
1212
0
  g_return_val_if_fail (!is_end (iter), NULL);
1213
1214
0
  return iter->data;
1215
0
}
1216
1217
/**
1218
 * g_sequence_set:
1219
 * @iter: a #GSequenceIter
1220
 * @data: new data for the item
1221
 *
1222
 * Changes the data for the item pointed to by @iter to be @data. If
1223
 * the sequence has a data destroy function associated with it, that
1224
 * function is called on the existing data that @iter pointed to.
1225
 *
1226
 * Since: 2.14
1227
 */
1228
void
1229
g_sequence_set (GSequenceIter *iter,
1230
                gpointer       data)
1231
0
{
1232
0
  GSequence *seq;
1233
1234
0
  g_return_if_fail (iter != NULL);
1235
1236
0
  seq = get_sequence (iter);
1237
0
  g_return_if_fail (!seq_is_end (seq, iter));
1238
1239
  /* If @data is identical to iter->data, it is destroyed
1240
   * here. This will work right in case of ref-counted objects. Also
1241
   * it is similar to what ghashtables do.
1242
   *
1243
   * For non-refcounted data it's a little less convenient, but
1244
   * code relying on self-setting not destroying would be
1245
   * pretty dubious anyway ...
1246
   */
1247
1248
0
  if (seq->data_destroy_notify)
1249
0
    seq->data_destroy_notify (iter->data);
1250
1251
0
  iter->data = data;
1252
0
}
1253
1254
/**
1255
 * g_sequence_get_length:
1256
 * @seq: a #GSequence
1257
 *
1258
 * Returns the positive length (>= 0) of @seq. Note that this method is
1259
 * O(h) where `h' is the height of the tree. It is thus more efficient
1260
 * to use g_sequence_is_empty() when comparing the length to zero.
1261
 *
1262
 * Returns: the length of @seq
1263
 *
1264
 * Since: 2.14
1265
 */
1266
gint
1267
g_sequence_get_length (GSequence *seq)
1268
0
{
1269
0
  return node_get_length (seq->end_node) - 1;
1270
0
}
1271
1272
/**
1273
 * g_sequence_is_empty:
1274
 * @seq: a #GSequence
1275
 *
1276
 * Returns %TRUE if the sequence contains zero items.
1277
 *
1278
 * This function is functionally identical to checking the result of
1279
 * g_sequence_get_length() being equal to zero. However this function is
1280
 * implemented in O(1) running time.
1281
 *
1282
 * Returns: %TRUE if the sequence is empty, otherwise %FALSE.
1283
 *
1284
 * Since: 2.48
1285
 */
1286
gboolean
1287
g_sequence_is_empty (GSequence *seq)
1288
0
{
1289
0
  return (seq->end_node->parent == NULL) && (seq->end_node->left == NULL);
1290
0
}
1291
1292
/**
1293
 * g_sequence_get_end_iter:
1294
 * @seq: a #GSequence
1295
 *
1296
 * Returns the end iterator for @seg
1297
 *
1298
 * Returns: (transfer none): the end iterator for @seq
1299
 *
1300
 * Since: 2.14
1301
 */
1302
GSequenceIter *
1303
g_sequence_get_end_iter (GSequence *seq)
1304
0
{
1305
0
  g_return_val_if_fail (seq != NULL, NULL);
1306
1307
0
  return seq->end_node;
1308
0
}
1309
1310
/**
1311
 * g_sequence_get_begin_iter:
1312
 * @seq: a #GSequence
1313
 *
1314
 * Returns the begin iterator for @seq.
1315
 *
1316
 * Returns: (transfer none): the begin iterator for @seq.
1317
 *
1318
 * Since: 2.14
1319
 */
1320
GSequenceIter *
1321
g_sequence_get_begin_iter (GSequence *seq)
1322
0
{
1323
0
  g_return_val_if_fail (seq != NULL, NULL);
1324
1325
0
  return node_get_first (seq->end_node);
1326
0
}
1327
1328
static int
1329
clamp_position (GSequence *seq,
1330
                int        pos)
1331
0
{
1332
0
  gint len = g_sequence_get_length (seq);
1333
1334
0
  if (pos > len || pos < 0)
1335
0
    pos = len;
1336
1337
0
  return pos;
1338
0
}
1339
1340
/**
1341
 * g_sequence_get_iter_at_pos:
1342
 * @seq: a #GSequence
1343
 * @pos: a position in @seq, or -1 for the end
1344
 *
1345
 * Returns the iterator at position @pos. If @pos is negative or larger
1346
 * than the number of items in @seq, the end iterator is returned.
1347
 *
1348
 * Returns: (transfer none): The #GSequenceIter at position @pos
1349
 *
1350
 * Since: 2.14
1351
 */
1352
GSequenceIter *
1353
g_sequence_get_iter_at_pos (GSequence *seq,
1354
                            gint       pos)
1355
0
{
1356
0
  g_return_val_if_fail (seq != NULL, NULL);
1357
1358
0
  pos = clamp_position (seq, pos);
1359
1360
0
  return node_get_by_pos (seq->end_node, pos);
1361
0
}
1362
1363
/**
1364
 * g_sequence_move:
1365
 * @src: a #GSequenceIter pointing to the item to move
1366
 * @dest: a #GSequenceIter pointing to the position to which
1367
 *     the item is moved
1368
 *
1369
 * Moves the item pointed to by @src to the position indicated by @dest.
1370
 * After calling this function @dest will point to the position immediately
1371
 * after @src. It is allowed for @src and @dest to point into different
1372
 * sequences.
1373
 *
1374
 * Since: 2.14
1375
 **/
1376
void
1377
g_sequence_move (GSequenceIter *src,
1378
                 GSequenceIter *dest)
1379
0
{
1380
0
  g_return_if_fail (src != NULL);
1381
0
  g_return_if_fail (dest != NULL);
1382
0
  g_return_if_fail (!is_end (src));
1383
1384
0
  if (src == dest)
1385
0
    return;
1386
1387
0
  node_unlink (src);
1388
0
  node_insert_before (dest, src);
1389
0
}
1390
1391
/* GSequenceIter */
1392
1393
/**
1394
 * g_sequence_iter_is_end:
1395
 * @iter: a #GSequenceIter
1396
 *
1397
 * Returns whether @iter is the end iterator
1398
 *
1399
 * Returns: Whether @iter is the end iterator
1400
 *
1401
 * Since: 2.14
1402
 */
1403
gboolean
1404
g_sequence_iter_is_end (GSequenceIter *iter)
1405
0
{
1406
0
  g_return_val_if_fail (iter != NULL, FALSE);
1407
1408
0
  return is_end (iter);
1409
0
}
1410
1411
/**
1412
 * g_sequence_iter_is_begin:
1413
 * @iter: a #GSequenceIter
1414
 *
1415
 * Returns whether @iter is the begin iterator
1416
 *
1417
 * Returns: whether @iter is the begin iterator
1418
 *
1419
 * Since: 2.14
1420
 */
1421
gboolean
1422
g_sequence_iter_is_begin (GSequenceIter *iter)
1423
0
{
1424
0
  g_return_val_if_fail (iter != NULL, FALSE);
1425
1426
0
  return (node_get_prev (iter) == iter);
1427
0
}
1428
1429
/**
1430
 * g_sequence_iter_get_position:
1431
 * @iter: a #GSequenceIter
1432
 *
1433
 * Returns the position of @iter
1434
 *
1435
 * Returns: the position of @iter
1436
 *
1437
 * Since: 2.14
1438
 */
1439
gint
1440
g_sequence_iter_get_position (GSequenceIter *iter)
1441
0
{
1442
0
  g_return_val_if_fail (iter != NULL, -1);
1443
1444
0
  return node_get_pos (iter);
1445
0
}
1446
1447
/**
1448
 * g_sequence_iter_next:
1449
 * @iter: a #GSequenceIter
1450
 *
1451
 * Returns an iterator pointing to the next position after @iter.
1452
 * If @iter is the end iterator, the end iterator is returned.
1453
 *
1454
 * Returns: (transfer none): a #GSequenceIter pointing to the next position after @iter
1455
 *
1456
 * Since: 2.14
1457
 */
1458
GSequenceIter *
1459
g_sequence_iter_next (GSequenceIter *iter)
1460
0
{
1461
0
  g_return_val_if_fail (iter != NULL, NULL);
1462
1463
0
  return node_get_next (iter);
1464
0
}
1465
1466
/**
1467
 * g_sequence_iter_prev:
1468
 * @iter: a #GSequenceIter
1469
 *
1470
 * Returns an iterator pointing to the previous position before @iter.
1471
 * If @iter is the begin iterator, the begin iterator is returned.
1472
 *
1473
 * Returns: (transfer none): a #GSequenceIter pointing to the previous position
1474
 *     before @iter
1475
 *
1476
 * Since: 2.14
1477
 */
1478
GSequenceIter *
1479
g_sequence_iter_prev (GSequenceIter *iter)
1480
0
{
1481
0
  g_return_val_if_fail (iter != NULL, NULL);
1482
1483
0
  return node_get_prev (iter);
1484
0
}
1485
1486
/**
1487
 * g_sequence_iter_move:
1488
 * @iter: a #GSequenceIter
1489
 * @delta: A positive or negative number indicating how many positions away
1490
 *    from @iter the returned #GSequenceIter will be
1491
 *
1492
 * Returns the #GSequenceIter which is @delta positions away from @iter.
1493
 * If @iter is closer than -@delta positions to the beginning of the sequence,
1494
 * the begin iterator is returned. If @iter is closer than @delta positions
1495
 * to the end of the sequence, the end iterator is returned.
1496
 *
1497
 * Returns: (transfer none): a #GSequenceIter which is @delta positions away from @iter
1498
 *
1499
 * Since: 2.14
1500
 */
1501
GSequenceIter *
1502
g_sequence_iter_move (GSequenceIter *iter,
1503
                      gint           delta)
1504
0
{
1505
0
  gint new_pos;
1506
0
  gint len;
1507
1508
0
  g_return_val_if_fail (iter != NULL, NULL);
1509
1510
0
  len = g_sequence_get_length (get_sequence (iter));
1511
1512
0
  new_pos = node_get_pos (iter) + delta;
1513
1514
0
  if (new_pos < 0)
1515
0
    new_pos = 0;
1516
0
  else if (new_pos > len)
1517
0
    new_pos = len;
1518
1519
0
  return node_get_by_pos (iter, new_pos);
1520
0
}
1521
1522
/**
1523
 * g_sequence_swap:
1524
 * @a: a #GSequenceIter
1525
 * @b: a #GSequenceIter
1526
 *
1527
 * Swaps the items pointed to by @a and @b. It is allowed for @a and @b
1528
 * to point into difference sequences.
1529
 *
1530
 * Since: 2.14
1531
 */
1532
void
1533
g_sequence_swap (GSequenceIter *a,
1534
                 GSequenceIter *b)
1535
0
{
1536
0
  GSequenceNode *leftmost, *rightmost, *rightmost_next;
1537
0
  int a_pos, b_pos;
1538
1539
0
  g_return_if_fail (!g_sequence_iter_is_end (a));
1540
0
  g_return_if_fail (!g_sequence_iter_is_end (b));
1541
1542
0
  if (a == b)
1543
0
    return;
1544
1545
0
  a_pos = g_sequence_iter_get_position (a);
1546
0
  b_pos = g_sequence_iter_get_position (b);
1547
1548
0
  if (a_pos > b_pos)
1549
0
    {
1550
0
      leftmost = b;
1551
0
      rightmost = a;
1552
0
    }
1553
0
  else
1554
0
    {
1555
0
      leftmost = a;
1556
0
      rightmost = b;
1557
0
    }
1558
1559
0
  rightmost_next = node_get_next (rightmost);
1560
1561
  /* The situation is now like this:
1562
   *
1563
   *     ..., leftmost, ......., rightmost, rightmost_next, ...
1564
   *
1565
   */
1566
0
  g_sequence_move (rightmost, leftmost);
1567
0
  g_sequence_move (leftmost, rightmost_next);
1568
0
}
1569
1570
/*
1571
 * Implementation of a treap
1572
 *
1573
 *
1574
 */
1575
static guint
1576
get_priority (GSequenceNode *node)
1577
0
{
1578
0
  guint key = GPOINTER_TO_UINT (node);
1579
1580
  /* This hash function is based on one found on Thomas Wang's
1581
   * web page at
1582
   *
1583
   *    http://www.concentric.net/~Ttwang/tech/inthash.htm
1584
   *
1585
   */
1586
0
  key = (key << 15) - key - 1;
1587
0
  key = key ^ (key >> 12);
1588
0
  key = key + (key << 2);
1589
0
  key = key ^ (key >> 4);
1590
0
  key = key + (key << 3) + (key << 11);
1591
0
  key = key ^ (key >> 16);
1592
1593
  /* We rely on 0 being less than all other priorities */
1594
0
  return key? key : 1;
1595
0
}
1596
1597
static GSequenceNode *
1598
find_root (GSequenceNode *node)
1599
0
{
1600
0
  while (node->parent)
1601
0
    node = node->parent;
1602
1603
0
  return node;
1604
0
}
1605
1606
static GSequenceNode *
1607
node_new (gpointer data)
1608
0
{
1609
0
  GSequenceNode *node = g_slice_new0 (GSequenceNode);
1610
1611
0
  node->n_nodes = 1;
1612
0
  node->data = data;
1613
0
  node->left = NULL;
1614
0
  node->right = NULL;
1615
0
  node->parent = NULL;
1616
1617
0
  return node;
1618
0
}
1619
1620
static GSequenceNode *
1621
node_get_first (GSequenceNode *node)
1622
0
{
1623
0
  node = find_root (node);
1624
1625
0
  while (node->left)
1626
0
    node = node->left;
1627
1628
0
  return node;
1629
0
}
1630
1631
static GSequenceNode *
1632
node_get_last (GSequenceNode *node)
1633
0
{
1634
0
  node = find_root (node);
1635
1636
0
  while (node->right)
1637
0
    node = node->right;
1638
1639
0
  return node;
1640
0
}
1641
1642
0
#define NODE_LEFT_CHILD(n)  (((n)->parent) && ((n)->parent->left) == (n))
1643
0
#define NODE_RIGHT_CHILD(n) (((n)->parent) && ((n)->parent->right) == (n))
1644
1645
static GSequenceNode *
1646
node_get_next (GSequenceNode *node)
1647
0
{
1648
0
  GSequenceNode *n = node;
1649
1650
0
  if (n->right)
1651
0
    {
1652
0
      n = n->right;
1653
0
      while (n->left)
1654
0
        n = n->left;
1655
0
    }
1656
0
  else
1657
0
    {
1658
0
      while (NODE_RIGHT_CHILD (n))
1659
0
        n = n->parent;
1660
1661
0
      if (n->parent)
1662
0
        n = n->parent;
1663
0
      else
1664
0
        n = node;
1665
0
    }
1666
1667
0
  return n;
1668
0
}
1669
1670
static GSequenceNode *
1671
node_get_prev (GSequenceNode *node)
1672
0
{
1673
0
  GSequenceNode *n = node;
1674
1675
0
  if (n->left)
1676
0
    {
1677
0
      n = n->left;
1678
0
      while (n->right)
1679
0
        n = n->right;
1680
0
    }
1681
0
  else
1682
0
    {
1683
0
      while (NODE_LEFT_CHILD (n))
1684
0
        n = n->parent;
1685
1686
0
      if (n->parent)
1687
0
        n = n->parent;
1688
0
      else
1689
0
        n = node;
1690
0
    }
1691
1692
0
  return n;
1693
0
}
1694
1695
0
#define N_NODES(n) ((n)? (n)->n_nodes : 0)
1696
1697
static gint
1698
node_get_pos (GSequenceNode *node)
1699
0
{
1700
0
  int n_smaller = 0;
1701
1702
0
  if (node->left)
1703
0
    n_smaller = node->left->n_nodes;
1704
1705
0
  while (node)
1706
0
    {
1707
0
      if (NODE_RIGHT_CHILD (node))
1708
0
        n_smaller += N_NODES (node->parent->left) + 1;
1709
1710
0
      node = node->parent;
1711
0
    }
1712
1713
0
  return n_smaller;
1714
0
}
1715
1716
static GSequenceNode *
1717
node_get_by_pos (GSequenceNode *node,
1718
                 gint           pos)
1719
0
{
1720
0
  int i;
1721
1722
0
  node = find_root (node);
1723
1724
0
  while ((i = N_NODES (node->left)) != pos)
1725
0
    {
1726
0
      if (i < pos)
1727
0
        {
1728
0
          node = node->right;
1729
0
          pos -= (i + 1);
1730
0
        }
1731
0
      else
1732
0
        {
1733
0
          node = node->left;
1734
0
        }
1735
0
    }
1736
1737
0
  return node;
1738
0
}
1739
1740
static GSequenceNode *
1741
node_find (GSequenceNode            *haystack,
1742
           GSequenceNode            *needle,
1743
           GSequenceNode            *end,
1744
           GSequenceIterCompareFunc  iter_cmp,
1745
           gpointer                  cmp_data)
1746
0
{
1747
0
  gint c;
1748
1749
0
  haystack = find_root (haystack);
1750
1751
0
  do
1752
0
    {
1753
      /* iter_cmp can't be passed the end node, since the function may
1754
       * be user-supplied
1755
       */
1756
0
      if (haystack == end)
1757
0
        c = 1;
1758
0
      else
1759
0
        c = iter_cmp (haystack, needle, cmp_data);
1760
1761
0
      if (c == 0)
1762
0
        break;
1763
1764
0
      if (c > 0)
1765
0
        haystack = haystack->left;
1766
0
      else
1767
0
        haystack = haystack->right;
1768
0
    }
1769
0
  while (haystack != NULL);
1770
1771
0
  return haystack;
1772
0
}
1773
1774
static GSequenceNode *
1775
node_find_closest (GSequenceNode            *haystack,
1776
                   GSequenceNode            *needle,
1777
                   GSequenceNode            *end,
1778
                   GSequenceIterCompareFunc  iter_cmp,
1779
                   gpointer                  cmp_data)
1780
0
{
1781
0
  GSequenceNode *best;
1782
0
  gint c;
1783
1784
0
  haystack = find_root (haystack);
1785
1786
0
  do
1787
0
    {
1788
0
      best = haystack;
1789
1790
      /* iter_cmp can't be passed the end node, since the function may
1791
       * be user-supplied
1792
       */
1793
0
      if (haystack == end)
1794
0
        c = 1;
1795
0
      else
1796
0
        c = iter_cmp (haystack, needle, cmp_data);
1797
1798
      /* In the following we don't break even if c == 0. Instead we go on
1799
       * searching along the 'bigger' nodes, so that we find the last one
1800
       * that is equal to the needle.
1801
       */
1802
0
      if (c > 0)
1803
0
        haystack = haystack->left;
1804
0
      else
1805
0
        haystack = haystack->right;
1806
0
    }
1807
0
  while (haystack != NULL);
1808
1809
  /* If the best node is smaller or equal to the data, then move one step
1810
   * to the right to make sure the best one is strictly bigger than the data
1811
   */
1812
0
  if (best != end && c <= 0)
1813
0
    best = node_get_next (best);
1814
1815
0
  return best;
1816
0
}
1817
1818
static gint
1819
node_get_length    (GSequenceNode            *node)
1820
0
{
1821
0
  node = find_root (node);
1822
1823
0
  return node->n_nodes;
1824
0
}
1825
1826
static void
1827
real_node_free (GSequenceNode *node,
1828
                GSequence     *seq)
1829
0
{
1830
0
  if (node)
1831
0
    {
1832
0
      real_node_free (node->left, seq);
1833
0
      real_node_free (node->right, seq);
1834
1835
0
      if (seq && seq->data_destroy_notify && node != seq->end_node)
1836
0
        seq->data_destroy_notify (node->data);
1837
1838
0
      g_slice_free (GSequenceNode, node);
1839
0
    }
1840
0
}
1841
1842
static void
1843
node_free (GSequenceNode *node,
1844
           GSequence *seq)
1845
0
{
1846
0
  node = find_root (node);
1847
1848
0
  real_node_free (node, seq);
1849
0
}
1850
1851
static void
1852
node_update_fields (GSequenceNode *node)
1853
0
{
1854
0
  int n_nodes = 1;
1855
1856
0
  n_nodes += N_NODES (node->left);
1857
0
  n_nodes += N_NODES (node->right);
1858
1859
0
  node->n_nodes = n_nodes;
1860
0
}
1861
1862
static void
1863
node_rotate (GSequenceNode *node)
1864
0
{
1865
0
  GSequenceNode *tmp, *old;
1866
1867
0
  g_assert (node->parent);
1868
0
  g_assert (node->parent != node);
1869
1870
0
  if (NODE_LEFT_CHILD (node))
1871
0
    {
1872
      /* rotate right */
1873
0
      tmp = node->right;
1874
1875
0
      node->right = node->parent;
1876
0
      node->parent = node->parent->parent;
1877
0
      if (node->parent)
1878
0
        {
1879
0
          if (node->parent->left == node->right)
1880
0
            node->parent->left = node;
1881
0
          else
1882
0
            node->parent->right = node;
1883
0
        }
1884
1885
0
      g_assert (node->right);
1886
1887
0
      node->right->parent = node;
1888
0
      node->right->left = tmp;
1889
1890
0
      if (node->right->left)
1891
0
        node->right->left->parent = node->right;
1892
1893
0
      old = node->right;
1894
0
    }
1895
0
  else
1896
0
    {
1897
      /* rotate left */
1898
0
      tmp = node->left;
1899
1900
0
      node->left = node->parent;
1901
0
      node->parent = node->parent->parent;
1902
0
      if (node->parent)
1903
0
        {
1904
0
          if (node->parent->right == node->left)
1905
0
            node->parent->right = node;
1906
0
          else
1907
0
            node->parent->left = node;
1908
0
        }
1909
1910
0
      g_assert (node->left);
1911
1912
0
      node->left->parent = node;
1913
0
      node->left->right = tmp;
1914
1915
0
      if (node->left->right)
1916
0
        node->left->right->parent = node->left;
1917
1918
0
      old = node->left;
1919
0
    }
1920
1921
0
  node_update_fields (old);
1922
0
  node_update_fields (node);
1923
0
}
1924
1925
static void
1926
node_update_fields_deep (GSequenceNode *node)
1927
0
{
1928
0
  if (node)
1929
0
    {
1930
0
      node_update_fields (node);
1931
1932
0
      node_update_fields_deep (node->parent);
1933
0
    }
1934
0
}
1935
1936
static void
1937
rotate_down (GSequenceNode *node,
1938
             guint          priority)
1939
0
{
1940
0
  guint left, right;
1941
1942
0
  left = node->left ? get_priority (node->left)  : 0;
1943
0
  right = node->right ? get_priority (node->right) : 0;
1944
1945
0
  while (priority < left || priority < right)
1946
0
    {
1947
0
      if (left > right)
1948
0
        node_rotate (node->left);
1949
0
      else
1950
0
        node_rotate (node->right);
1951
1952
0
      left = node->left ? get_priority (node->left)  : 0;
1953
0
      right = node->right ? get_priority (node->right) : 0;
1954
0
    }
1955
0
}
1956
1957
static void
1958
node_cut (GSequenceNode *node)
1959
0
{
1960
0
  while (node->parent)
1961
0
    node_rotate (node);
1962
1963
0
  if (node->left)
1964
0
    node->left->parent = NULL;
1965
1966
0
  node->left = NULL;
1967
0
  node_update_fields (node);
1968
1969
0
  rotate_down (node, get_priority (node));
1970
0
}
1971
1972
static void
1973
node_join (GSequenceNode *left,
1974
           GSequenceNode *right)
1975
0
{
1976
0
  GSequenceNode *fake = node_new (NULL);
1977
1978
0
  fake->left = find_root (left);
1979
0
  fake->right = find_root (right);
1980
0
  fake->left->parent = fake;
1981
0
  fake->right->parent = fake;
1982
1983
0
  node_update_fields (fake);
1984
1985
0
  node_unlink (fake);
1986
1987
0
  node_free (fake, NULL);
1988
0
}
1989
1990
static void
1991
node_insert_before (GSequenceNode *node,
1992
                    GSequenceNode *new)
1993
0
{
1994
0
  new->left = node->left;
1995
0
  if (new->left)
1996
0
    new->left->parent = new;
1997
1998
0
  new->parent = node;
1999
0
  node->left = new;
2000
2001
0
  node_update_fields_deep (new);
2002
2003
0
  while (new->parent && get_priority (new) > get_priority (new->parent))
2004
0
    node_rotate (new);
2005
2006
0
  rotate_down (new, get_priority (new));
2007
0
}
2008
2009
static void
2010
node_unlink (GSequenceNode *node)
2011
0
{
2012
0
  rotate_down (node, 0);
2013
2014
0
  if (NODE_RIGHT_CHILD (node))
2015
0
    node->parent->right = NULL;
2016
0
  else if (NODE_LEFT_CHILD (node))
2017
0
    node->parent->left = NULL;
2018
2019
0
  if (node->parent)
2020
0
    node_update_fields_deep (node->parent);
2021
2022
0
  node->parent = NULL;
2023
0
}
2024
2025
static void
2026
node_insert_sorted (GSequenceNode            *node,
2027
                    GSequenceNode            *new,
2028
                    GSequenceNode            *end,
2029
                    GSequenceIterCompareFunc  iter_cmp,
2030
                    gpointer                  cmp_data)
2031
0
{
2032
0
  GSequenceNode *closest;
2033
2034
0
  closest = node_find_closest (node, new, end, iter_cmp, cmp_data);
2035
2036
0
  node_unlink (new);
2037
2038
0
  node_insert_before (closest, new);
2039
0
}