Coverage Report

Created: 2025-09-05 06:29

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