Add some more cases to the app-id unit tests
[glib.git] / glib / gsequence.c
blobb813ee88ace9d5738561b9a3aa2598c84152860a
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)
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 of the License, or (at your option) any later version.
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.
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/>.
19 #include "config.h"
21 #include "gsequence.h"
23 #include "gmem.h"
24 #include "gtestutils.h"
25 #include "gslice.h"
26 /**
27 * SECTION:sequence
28 * @title: Sequences
29 * @short_description: scalable lists
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 * it is possible to maintain a sorted list of n elements in time O(n log n).
34 * The data contained in each element can be either integer values, by using
35 * of the [Type Conversion Macros][glib-Type-Conversion-Macros], or simply
36 * pointers to any type of data.
38 * A #GSequence is accessed through "iterators", represented by a
39 * #GSequenceIter. An iterator represents a position between two
40 * elements of the sequence. For example, the "begin" iterator
41 * represents the gap immediately before the first element of the
42 * sequence, and the "end" iterator represents the gap immediately
43 * after the last element. In an empty sequence, the begin and end
44 * iterators are the same.
46 * Some methods on #GSequence operate on ranges of items. For example
47 * g_sequence_foreach_range() will call a user-specified function on
48 * each element with the given range. The range is delimited by the
49 * gaps represented by the passed-in iterators, so if you pass in the
50 * begin and end iterators, the range in question is the entire
51 * sequence.
53 * The function g_sequence_get() is used with an iterator to access the
54 * element immediately following the gap that the iterator represents.
55 * The iterator is said to "point" to that element.
57 * Iterators are stable across most operations on a #GSequence. For
58 * example an iterator pointing to some element of a sequence will
59 * continue to point to that element even after the sequence is sorted.
60 * Even moving an element to another sequence using for example
61 * g_sequence_move_range() will not invalidate the iterators pointing
62 * to it. The only operation that will invalidate an iterator is when
63 * the element it points to is removed from any sequence.
66 /**
67 * GSequenceIter:
69 * The #GSequenceIter struct is an opaque data type representing an
70 * iterator pointing into a #GSequence.
73 /**
74 * GSequenceIterCompareFunc:
75 * @a: a #GSequenceIter
76 * @b: a #GSequenceIter
77 * @data: user data
79 * A #GSequenceIterCompareFunc is a function used to compare iterators.
80 * It must return zero if the iterators compare equal, a negative value
81 * if @a comes before @b, and a positive value if @b comes before @a.
83 * Returns: zero if the iterators are equal, a negative value if @a
84 * comes before @b, and a positive value if @b comes before @a.
87 typedef struct _GSequenceNode GSequenceNode;
89 /**
90 * GSequence:
92 * The #GSequence struct is an opaque data type representing a
93 * [sequence][glib-Sequences] data type.
95 struct _GSequence
97 GSequenceNode * end_node;
98 GDestroyNotify data_destroy_notify;
99 gboolean access_prohibited;
101 /* The 'real_sequence' is used when temporary sequences are created
102 * to hold nodes that are being rearranged. The 'real_sequence' of such
103 * a temporary sequence points to the sequence that is actually being
104 * manipulated. The only reason we need this is so that when the
105 * sort/sort_changed/search_iter() functions call out to the application
106 * g_sequence_iter_get_sequence() will return the correct sequence.
108 GSequence * real_sequence;
111 struct _GSequenceNode
113 gint n_nodes;
114 GSequenceNode * parent;
115 GSequenceNode * left;
116 GSequenceNode * right;
117 gpointer data; /* For the end node, this field points
118 * to the sequence
123 * Declaration of GSequenceNode methods
125 static GSequenceNode *node_new (gpointer data);
126 static GSequenceNode *node_get_first (GSequenceNode *node);
127 static GSequenceNode *node_get_last (GSequenceNode *node);
128 static GSequenceNode *node_get_prev (GSequenceNode *node);
129 static GSequenceNode *node_get_next (GSequenceNode *node);
130 static gint node_get_pos (GSequenceNode *node);
131 static GSequenceNode *node_get_by_pos (GSequenceNode *node,
132 gint pos);
133 static GSequenceNode *node_find (GSequenceNode *haystack,
134 GSequenceNode *needle,
135 GSequenceNode *end,
136 GSequenceIterCompareFunc cmp,
137 gpointer user_data);
138 static GSequenceNode *node_find_closest (GSequenceNode *haystack,
139 GSequenceNode *needle,
140 GSequenceNode *end,
141 GSequenceIterCompareFunc cmp,
142 gpointer user_data);
143 static gint node_get_length (GSequenceNode *node);
144 static void node_free (GSequenceNode *node,
145 GSequence *seq);
146 static void node_cut (GSequenceNode *split);
147 static void node_insert_before (GSequenceNode *node,
148 GSequenceNode *new);
149 static void node_unlink (GSequenceNode *node);
150 static void node_join (GSequenceNode *left,
151 GSequenceNode *right);
152 static void node_insert_sorted (GSequenceNode *node,
153 GSequenceNode *new,
154 GSequenceNode *end,
155 GSequenceIterCompareFunc cmp_func,
156 gpointer cmp_data);
160 * Various helper functions
162 static void
163 check_seq_access (GSequence *seq)
165 if (G_UNLIKELY (seq->access_prohibited))
167 g_warning ("Accessing a sequence while it is "
168 "being sorted or searched is not allowed");
172 static GSequence *
173 get_sequence (GSequenceNode *node)
175 return (GSequence *)node_get_last (node)->data;
178 static void
179 check_iter_access (GSequenceIter *iter)
181 check_seq_access (get_sequence (iter));
184 static gboolean
185 is_end (GSequenceIter *iter)
187 GSequenceIter *parent = iter->parent;
189 if (iter->right)
190 return FALSE;
192 if (!parent)
193 return TRUE;
195 while (parent->right == iter)
197 iter = parent;
198 parent = iter->parent;
200 if (!parent)
201 return TRUE;
204 return FALSE;
207 typedef struct
209 GCompareDataFunc cmp_func;
210 gpointer cmp_data;
211 GSequenceNode *end_node;
212 } SortInfo;
214 /* This function compares two iters using a normal compare
215 * function and user_data passed in in a SortInfo struct
217 static gint
218 iter_compare (GSequenceIter *node1,
219 GSequenceIter *node2,
220 gpointer data)
222 const SortInfo *info = data;
223 gint retval;
225 if (node1 == info->end_node)
226 return 1;
228 if (node2 == info->end_node)
229 return -1;
231 retval = info->cmp_func (node1->data, node2->data, info->cmp_data);
233 return retval;
237 * Public API
241 * g_sequence_new:
242 * @data_destroy: (nullable): a #GDestroyNotify function, or %NULL
244 * Creates a new GSequence. The @data_destroy function, if non-%NULL will
245 * be called on all items when the sequence is destroyed and on items that
246 * are removed from the sequence.
248 * Returns: a new #GSequence
250 * Since: 2.14
252 GSequence *
253 g_sequence_new (GDestroyNotify data_destroy)
255 GSequence *seq = g_new (GSequence, 1);
256 seq->data_destroy_notify = data_destroy;
258 seq->end_node = node_new (seq);
260 seq->access_prohibited = FALSE;
262 seq->real_sequence = seq;
264 return seq;
268 * g_sequence_free:
269 * @seq: a #GSequence
271 * Frees the memory allocated for @seq. If @seq has a data destroy
272 * function associated with it, that function is called on all items
273 * in @seq.
275 * Since: 2.14
277 void
278 g_sequence_free (GSequence *seq)
280 g_return_if_fail (seq != NULL);
282 check_seq_access (seq);
284 node_free (seq->end_node, seq);
286 g_free (seq);
290 * g_sequence_foreach_range:
291 * @begin: a #GSequenceIter
292 * @end: a #GSequenceIter
293 * @func: a #GFunc
294 * @user_data: user data passed to @func
296 * Calls @func for each item in the range (@begin, @end) passing
297 * @user_data to the function.
299 * Since: 2.14
301 void
302 g_sequence_foreach_range (GSequenceIter *begin,
303 GSequenceIter *end,
304 GFunc func,
305 gpointer user_data)
307 GSequence *seq;
308 GSequenceIter *iter;
310 g_return_if_fail (func != NULL);
311 g_return_if_fail (begin != NULL);
312 g_return_if_fail (end != NULL);
314 seq = get_sequence (begin);
316 seq->access_prohibited = TRUE;
318 iter = begin;
319 while (iter != end)
321 GSequenceIter *next = node_get_next (iter);
323 func (iter->data, user_data);
325 iter = next;
328 seq->access_prohibited = FALSE;
332 * g_sequence_foreach:
333 * @seq: a #GSequence
334 * @func: the function to call for each item in @seq
335 * @user_data: user data passed to @func
337 * Calls @func for each item in the sequence passing @user_data
338 * to the function.
340 * Since: 2.14
342 void
343 g_sequence_foreach (GSequence *seq,
344 GFunc func,
345 gpointer user_data)
347 GSequenceIter *begin, *end;
349 check_seq_access (seq);
351 begin = g_sequence_get_begin_iter (seq);
352 end = g_sequence_get_end_iter (seq);
354 g_sequence_foreach_range (begin, end, func, user_data);
358 * g_sequence_range_get_midpoint:
359 * @begin: a #GSequenceIter
360 * @end: a #GSequenceIter
362 * Finds an iterator somewhere in the range (@begin, @end). This
363 * iterator will be close to the middle of the range, but is not
364 * guaranteed to be exactly in the middle.
366 * The @begin and @end iterators must both point to the same sequence
367 * and @begin must come before or be equal to @end in the sequence.
369 * Returns: a #GSequenceIter pointing somewhere in the
370 * (@begin, @end) range
372 * Since: 2.14
374 GSequenceIter *
375 g_sequence_range_get_midpoint (GSequenceIter *begin,
376 GSequenceIter *end)
378 int begin_pos, end_pos, mid_pos;
380 g_return_val_if_fail (begin != NULL, NULL);
381 g_return_val_if_fail (end != NULL, NULL);
382 g_return_val_if_fail (get_sequence (begin) == get_sequence (end), NULL);
384 begin_pos = node_get_pos (begin);
385 end_pos = node_get_pos (end);
387 g_return_val_if_fail (end_pos >= begin_pos, NULL);
389 mid_pos = begin_pos + (end_pos - begin_pos) / 2;
391 return node_get_by_pos (begin, mid_pos);
395 * g_sequence_iter_compare:
396 * @a: a #GSequenceIter
397 * @b: a #GSequenceIter
399 * Returns a negative number if @a comes before @b, 0 if they are equal,
400 * and a positive number if @a comes after @b.
402 * The @a and @b iterators must point into the same sequence.
404 * Returns: a negative number if @a comes before @b, 0 if they are
405 * equal, and a positive number if @a comes after @b
407 * Since: 2.14
409 gint
410 g_sequence_iter_compare (GSequenceIter *a,
411 GSequenceIter *b)
413 gint a_pos, b_pos;
415 g_return_val_if_fail (a != NULL, 0);
416 g_return_val_if_fail (b != NULL, 0);
417 g_return_val_if_fail (get_sequence (a) == get_sequence (b), 0);
419 check_iter_access (a);
420 check_iter_access (b);
422 a_pos = node_get_pos (a);
423 b_pos = node_get_pos (b);
425 if (a_pos == b_pos)
426 return 0;
427 else if (a_pos > b_pos)
428 return 1;
429 else
430 return -1;
434 * g_sequence_append:
435 * @seq: a #GSequence
436 * @data: the data for the new item
438 * Adds a new item to the end of @seq.
440 * Returns: an iterator pointing to the new item
442 * Since: 2.14
444 GSequenceIter *
445 g_sequence_append (GSequence *seq,
446 gpointer data)
448 GSequenceNode *node;
450 g_return_val_if_fail (seq != NULL, NULL);
452 check_seq_access (seq);
454 node = node_new (data);
455 node_insert_before (seq->end_node, node);
457 return node;
461 * g_sequence_prepend:
462 * @seq: a #GSequence
463 * @data: the data for the new item
465 * Adds a new item to the front of @seq
467 * Returns: an iterator pointing to the new item
469 * Since: 2.14
471 GSequenceIter *
472 g_sequence_prepend (GSequence *seq,
473 gpointer data)
475 GSequenceNode *node, *first;
477 g_return_val_if_fail (seq != NULL, NULL);
479 check_seq_access (seq);
481 node = node_new (data);
482 first = node_get_first (seq->end_node);
484 node_insert_before (first, node);
486 return node;
490 * g_sequence_insert_before:
491 * @iter: a #GSequenceIter
492 * @data: the data for the new item
494 * Inserts a new item just before the item pointed to by @iter.
496 * Returns: an iterator pointing to the new item
498 * Since: 2.14
500 GSequenceIter *
501 g_sequence_insert_before (GSequenceIter *iter,
502 gpointer data)
504 GSequenceNode *node;
506 g_return_val_if_fail (iter != NULL, NULL);
508 check_iter_access (iter);
510 node = node_new (data);
512 node_insert_before (iter, node);
514 return node;
518 * g_sequence_remove:
519 * @iter: a #GSequenceIter
521 * Removes the item pointed to by @iter. It is an error to pass the
522 * end iterator to this function.
524 * If the sequence has a data destroy function associated with it, this
525 * function is called on the data for the removed item.
527 * Since: 2.14
529 void
530 g_sequence_remove (GSequenceIter *iter)
532 GSequence *seq;
534 g_return_if_fail (iter != NULL);
535 g_return_if_fail (!is_end (iter));
537 check_iter_access (iter);
539 seq = get_sequence (iter);
541 node_unlink (iter);
542 node_free (iter, seq);
546 * g_sequence_remove_range:
547 * @begin: a #GSequenceIter
548 * @end: a #GSequenceIter
550 * Removes all items in the (@begin, @end) range.
552 * If the sequence has a data destroy function associated with it, this
553 * function is called on the data for the removed items.
555 * Since: 2.14
557 void
558 g_sequence_remove_range (GSequenceIter *begin,
559 GSequenceIter *end)
561 g_return_if_fail (get_sequence (begin) == get_sequence (end));
563 check_iter_access (begin);
564 check_iter_access (end);
566 g_sequence_move_range (NULL, begin, end);
570 * g_sequence_move_range:
571 * @dest: a #GSequenceIter
572 * @begin: a #GSequenceIter
573 * @end: a #GSequenceIter
575 * Inserts the (@begin, @end) range at the destination pointed to by ptr.
576 * The @begin and @end iters must point into the same sequence. It is
577 * allowed for @dest to point to a different sequence than the one pointed
578 * into by @begin and @end.
580 * If @dest is NULL, the range indicated by @begin and @end is
581 * removed from the sequence. If @dest iter points to a place within
582 * the (@begin, @end) range, the range does not move.
584 * Since: 2.14
586 void
587 g_sequence_move_range (GSequenceIter *dest,
588 GSequenceIter *begin,
589 GSequenceIter *end)
591 GSequence *src_seq;
592 GSequenceNode *first;
594 g_return_if_fail (begin != NULL);
595 g_return_if_fail (end != NULL);
597 check_iter_access (begin);
598 check_iter_access (end);
599 if (dest)
600 check_iter_access (dest);
602 src_seq = get_sequence (begin);
604 g_return_if_fail (src_seq == get_sequence (end));
606 /* Dest points to begin or end? */
607 if (dest == begin || dest == end)
608 return;
610 /* begin comes after end? */
611 if (g_sequence_iter_compare (begin, end) >= 0)
612 return;
614 /* dest points somewhere in the (begin, end) range? */
615 if (dest && get_sequence (dest) == src_seq &&
616 g_sequence_iter_compare (dest, begin) > 0 &&
617 g_sequence_iter_compare (dest, end) < 0)
619 return;
622 src_seq = get_sequence (begin);
624 first = node_get_first (begin);
626 node_cut (begin);
628 node_cut (end);
630 if (first != begin)
631 node_join (first, end);
633 if (dest)
635 first = node_get_first (dest);
637 node_cut (dest);
639 node_join (begin, dest);
641 if (dest != first)
642 node_join (first, begin);
644 else
646 node_free (begin, src_seq);
651 * g_sequence_sort:
652 * @seq: a #GSequence
653 * @cmp_func: the function used to sort the sequence
654 * @cmp_data: user data passed to @cmp_func
656 * Sorts @seq using @cmp_func.
658 * @cmp_func is passed two items of @seq and should
659 * return 0 if they are equal, a negative value if the
660 * first comes before the second, and a positive value
661 * if the second comes before the first.
663 * Since: 2.14
665 void
666 g_sequence_sort (GSequence *seq,
667 GCompareDataFunc cmp_func,
668 gpointer cmp_data)
670 SortInfo info;
672 info.cmp_func = cmp_func;
673 info.cmp_data = cmp_data;
674 info.end_node = seq->end_node;
676 check_seq_access (seq);
678 g_sequence_sort_iter (seq, iter_compare, &info);
682 * g_sequence_insert_sorted:
683 * @seq: a #GSequence
684 * @data: the data to insert
685 * @cmp_func: the function used to compare items in the sequence
686 * @cmp_data: user data passed to @cmp_func.
688 * Inserts @data into @sequence using @func to determine the new
689 * position. The sequence must already be sorted according to @cmp_func;
690 * otherwise the new position of @data is undefined.
692 * @cmp_func is called with two items of the @seq and @user_data.
693 * It should return 0 if the items are equal, a negative value
694 * if the first item comes before the second, and a positive value
695 * if the second item comes before the first.
697 * Returns: a #GSequenceIter pointing to the new item.
699 * Since: 2.14
701 GSequenceIter *
702 g_sequence_insert_sorted (GSequence *seq,
703 gpointer data,
704 GCompareDataFunc cmp_func,
705 gpointer cmp_data)
707 SortInfo info;
709 g_return_val_if_fail (seq != NULL, NULL);
710 g_return_val_if_fail (cmp_func != NULL, NULL);
712 info.cmp_func = cmp_func;
713 info.cmp_data = cmp_data;
714 info.end_node = seq->end_node;
715 check_seq_access (seq);
717 return g_sequence_insert_sorted_iter (seq, data, iter_compare, &info);
721 * g_sequence_sort_changed:
722 * @iter: A #GSequenceIter
723 * @cmp_func: the function used to compare items in the sequence
724 * @cmp_data: user data passed to @cmp_func.
726 * Moves the data pointed to a new position as indicated by @cmp_func. This
727 * function should be called for items in a sequence already sorted according
728 * to @cmp_func whenever some aspect of an item changes so that @cmp_func
729 * may return different values for that item.
731 * @cmp_func is called with two items of the @seq and @user_data.
732 * It should return 0 if the items are equal, a negative value if
733 * the first item comes before the second, and a positive value if
734 * the second item comes before the first.
736 * Since: 2.14
738 void
739 g_sequence_sort_changed (GSequenceIter *iter,
740 GCompareDataFunc cmp_func,
741 gpointer cmp_data)
743 SortInfo info;
745 g_return_if_fail (!is_end (iter));
747 info.cmp_func = cmp_func;
748 info.cmp_data = cmp_data;
749 info.end_node = get_sequence (iter)->end_node;
750 check_iter_access (iter);
752 g_sequence_sort_changed_iter (iter, iter_compare, &info);
756 * g_sequence_search:
757 * @seq: a #GSequence
758 * @data: data for the new item
759 * @cmp_func: the function used to compare items in the sequence
760 * @cmp_data: user data passed to @cmp_func
762 * Returns an iterator pointing to the position where @data would
763 * be inserted according to @cmp_func and @cmp_data.
765 * @cmp_func is called with two items of the @seq and @user_data.
766 * It should return 0 if the items are equal, a negative value if
767 * the first item comes before the second, and a positive value if
768 * the second item comes before the first.
770 * If you are simply searching for an existing element of the sequence,
771 * consider using g_sequence_lookup().
773 * This function will fail if the data contained in the sequence is
774 * unsorted. Use g_sequence_insert_sorted() or
775 * g_sequence_insert_sorted_iter() to add data to your sequence or, if
776 * you want to add a large amount of data, call g_sequence_sort() after
777 * doing unsorted insertions.
779 * Returns: an #GSequenceIter pointing to the position where @data
780 * would have been inserted according to @cmp_func and @cmp_data
782 * Since: 2.14
784 GSequenceIter *
785 g_sequence_search (GSequence *seq,
786 gpointer data,
787 GCompareDataFunc cmp_func,
788 gpointer cmp_data)
790 SortInfo info;
792 g_return_val_if_fail (seq != NULL, NULL);
794 info.cmp_func = cmp_func;
795 info.cmp_data = cmp_data;
796 info.end_node = seq->end_node;
797 check_seq_access (seq);
799 return g_sequence_search_iter (seq, data, iter_compare, &info);
803 * g_sequence_lookup:
804 * @seq: a #GSequence
805 * @data: data to lookup
806 * @cmp_func: the function used to compare items in the sequence
807 * @cmp_data: user data passed to @cmp_func
809 * Returns an iterator pointing to the position of the first item found
810 * equal to @data according to @cmp_func and @cmp_data. If more than one
811 * item is equal, it is not guaranteed that it is the first which is
812 * returned. In that case, you can use g_sequence_iter_next() and
813 * g_sequence_iter_prev() to get others.
815 * @cmp_func is called with two items of the @seq and @user_data.
816 * It should return 0 if the items are equal, a negative value if
817 * the first item comes before the second, and a positive value if
818 * the second item comes before the first.
820 * This function will fail if the data contained in the sequence is
821 * unsorted. Use g_sequence_insert_sorted() or
822 * g_sequence_insert_sorted_iter() to add data to your sequence or, if
823 * you want to add a large amount of data, call g_sequence_sort() after
824 * doing unsorted insertions.
826 * Returns: an #GSequenceIter pointing to the position of the
827 * first item found equal to @data according to @cmp_func and
828 * @cmp_data, or %NULL if no such item exists
830 * Since: 2.28
832 GSequenceIter *
833 g_sequence_lookup (GSequence *seq,
834 gpointer data,
835 GCompareDataFunc cmp_func,
836 gpointer cmp_data)
838 SortInfo info;
840 g_return_val_if_fail (seq != NULL, NULL);
842 info.cmp_func = cmp_func;
843 info.cmp_data = cmp_data;
844 info.end_node = seq->end_node;
845 check_seq_access (seq);
847 return g_sequence_lookup_iter (seq, data, iter_compare, &info);
851 * g_sequence_sort_iter:
852 * @seq: a #GSequence
853 * @cmp_func: the function used to compare iterators in the sequence
854 * @cmp_data: user data passed to @cmp_func
856 * Like g_sequence_sort(), but uses a #GSequenceIterCompareFunc instead
857 * of a GCompareDataFunc as the compare function
859 * @cmp_func is called with two iterators pointing into @seq. It should
860 * return 0 if the iterators are equal, a negative value if the first
861 * iterator comes before the second, and a positive value if the second
862 * iterator comes before the first.
864 * Since: 2.14
866 void
867 g_sequence_sort_iter (GSequence *seq,
868 GSequenceIterCompareFunc cmp_func,
869 gpointer cmp_data)
871 GSequence *tmp;
872 GSequenceNode *begin, *end;
874 g_return_if_fail (seq != NULL);
875 g_return_if_fail (cmp_func != NULL);
877 check_seq_access (seq);
879 begin = g_sequence_get_begin_iter (seq);
880 end = g_sequence_get_end_iter (seq);
882 tmp = g_sequence_new (NULL);
883 tmp->real_sequence = seq;
885 g_sequence_move_range (g_sequence_get_begin_iter (tmp), begin, end);
887 seq->access_prohibited = TRUE;
888 tmp->access_prohibited = TRUE;
890 while (!g_sequence_is_empty (tmp))
892 GSequenceNode *node = g_sequence_get_begin_iter (tmp);
894 node_insert_sorted (seq->end_node, node, seq->end_node,
895 cmp_func, cmp_data);
898 tmp->access_prohibited = FALSE;
899 seq->access_prohibited = FALSE;
901 g_sequence_free (tmp);
905 * g_sequence_sort_changed_iter:
906 * @iter: a #GSequenceIter
907 * @iter_cmp: the function used to compare iterators in the sequence
908 * @cmp_data: user data passed to @cmp_func
910 * Like g_sequence_sort_changed(), but uses
911 * a #GSequenceIterCompareFunc instead of a #GCompareDataFunc as
912 * the compare function.
914 * @iter_cmp is called with two iterators pointing into @seq. It should
915 * return 0 if the iterators are equal, a negative value if the first
916 * iterator comes before the second, and a positive value if the second
917 * iterator comes before the first.
919 * Since: 2.14
921 void
922 g_sequence_sort_changed_iter (GSequenceIter *iter,
923 GSequenceIterCompareFunc iter_cmp,
924 gpointer cmp_data)
926 GSequence *seq, *tmp_seq;
927 GSequenceIter *next, *prev;
929 g_return_if_fail (iter != NULL);
930 g_return_if_fail (!is_end (iter));
931 g_return_if_fail (iter_cmp != NULL);
932 check_iter_access (iter);
934 /* If one of the neighbours is equal to iter, then
935 * don't move it. This ensures that sort_changed() is
936 * a stable operation.
939 next = node_get_next (iter);
940 prev = node_get_prev (iter);
942 if (prev != iter && iter_cmp (prev, iter, cmp_data) == 0)
943 return;
945 if (!is_end (next) && iter_cmp (next, iter, cmp_data) == 0)
946 return;
948 seq = get_sequence (iter);
950 seq->access_prohibited = TRUE;
952 tmp_seq = g_sequence_new (NULL);
953 tmp_seq->real_sequence = seq;
955 node_unlink (iter);
956 node_insert_before (tmp_seq->end_node, iter);
958 node_insert_sorted (seq->end_node, iter, seq->end_node,
959 iter_cmp, cmp_data);
961 g_sequence_free (tmp_seq);
963 seq->access_prohibited = FALSE;
967 * g_sequence_insert_sorted_iter:
968 * @seq: a #GSequence
969 * @data: data for the new item
970 * @iter_cmp: the function used to compare iterators in the sequence
971 * @cmp_data: user data passed to @cmp_func
973 * Like g_sequence_insert_sorted(), but uses
974 * a #GSequenceIterCompareFunc instead of a #GCompareDataFunc as
975 * the compare function.
977 * @iter_cmp is called with two iterators pointing into @seq.
978 * It should return 0 if the iterators are equal, a negative
979 * value if the first iterator comes before the second, and a
980 * positive value if the second iterator comes before the first.
982 * It is called with two iterators pointing into @seq. It should
983 * return 0 if the iterators are equal, a negative value if the
984 * first iterator comes before the second, and a positive value
985 * if the second iterator comes before the first.
987 * Returns: a #GSequenceIter pointing to the new item
989 * Since: 2.14
991 GSequenceIter *
992 g_sequence_insert_sorted_iter (GSequence *seq,
993 gpointer data,
994 GSequenceIterCompareFunc iter_cmp,
995 gpointer cmp_data)
997 GSequenceNode *new_node;
998 GSequence *tmp_seq;
1000 g_return_val_if_fail (seq != NULL, NULL);
1001 g_return_val_if_fail (iter_cmp != NULL, NULL);
1003 check_seq_access (seq);
1005 seq->access_prohibited = TRUE;
1007 /* Create a new temporary sequence and put the new node into
1008 * that. The reason for this is that the user compare function
1009 * will be called with the new node, and if it dereferences,
1010 * "is_end" will be called on it. But that will crash if the
1011 * node is not actually in a sequence.
1013 * node_insert_sorted() makes sure the node is unlinked before
1014 * it is inserted.
1016 * The reason we need the "iter" versions at all is that that
1017 * is the only kind of compare functions GtkTreeView can use.
1019 tmp_seq = g_sequence_new (NULL);
1020 tmp_seq->real_sequence = seq;
1022 new_node = g_sequence_append (tmp_seq, data);
1024 node_insert_sorted (seq->end_node, new_node,
1025 seq->end_node, iter_cmp, cmp_data);
1027 g_sequence_free (tmp_seq);
1029 seq->access_prohibited = FALSE;
1031 return new_node;
1035 * g_sequence_search_iter:
1036 * @seq: a #GSequence
1037 * @data: data for the new item
1038 * @iter_cmp: the function used to compare iterators in the sequence
1039 * @cmp_data: user data passed to @iter_cmp
1041 * Like g_sequence_search(), but uses a #GSequenceIterCompareFunc
1042 * instead of a #GCompareDataFunc as the compare function.
1044 * @iter_cmp is called with two iterators pointing into @seq.
1045 * It should return 0 if the iterators are equal, a negative value
1046 * if the first iterator comes before the second, and a positive
1047 * value if the second iterator comes before the first.
1049 * If you are simply searching for an existing element of the sequence,
1050 * consider using g_sequence_lookup_iter().
1052 * This function will fail if the data contained in the sequence is
1053 * unsorted. Use g_sequence_insert_sorted() or
1054 * g_sequence_insert_sorted_iter() to add data to your sequence or, if
1055 * you want to add a large amount of data, call g_sequence_sort() after
1056 * doing unsorted insertions.
1058 * Returns: a #GSequenceIter pointing to the position in @seq
1059 * where @data would have been inserted according to @iter_cmp
1060 * and @cmp_data
1062 * Since: 2.14
1064 GSequenceIter *
1065 g_sequence_search_iter (GSequence *seq,
1066 gpointer data,
1067 GSequenceIterCompareFunc iter_cmp,
1068 gpointer cmp_data)
1070 GSequenceNode *node;
1071 GSequenceNode *dummy;
1072 GSequence *tmp_seq;
1074 g_return_val_if_fail (seq != NULL, NULL);
1076 check_seq_access (seq);
1078 seq->access_prohibited = TRUE;
1080 tmp_seq = g_sequence_new (NULL);
1081 tmp_seq->real_sequence = seq;
1083 dummy = g_sequence_append (tmp_seq, data);
1085 node = node_find_closest (seq->end_node, dummy,
1086 seq->end_node, iter_cmp, cmp_data);
1088 g_sequence_free (tmp_seq);
1090 seq->access_prohibited = FALSE;
1092 return node;
1096 * g_sequence_lookup_iter:
1097 * @seq: a #GSequence
1098 * @data: data to lookup
1099 * @iter_cmp: the function used to compare iterators in the sequence
1100 * @cmp_data: user data passed to @iter_cmp
1102 * Like g_sequence_lookup(), but uses a #GSequenceIterCompareFunc
1103 * instead of a #GCompareDataFunc as the compare function.
1105 * @iter_cmp is called with two iterators pointing into @seq.
1106 * It should return 0 if the iterators are equal, a negative value
1107 * if the first iterator comes before the second, and a positive
1108 * value if the second iterator comes before the first.
1110 * This function will fail if the data contained in the sequence is
1111 * unsorted. Use g_sequence_insert_sorted() or
1112 * g_sequence_insert_sorted_iter() to add data to your sequence or, if
1113 * you want to add a large amount of data, call g_sequence_sort() after
1114 * doing unsorted insertions.
1116 * Returns: an #GSequenceIter pointing to the position of
1117 * the first item found equal to @data according to @cmp_func
1118 * and @cmp_data, or %NULL if no such item exists
1120 * Since: 2.28
1122 GSequenceIter *
1123 g_sequence_lookup_iter (GSequence *seq,
1124 gpointer data,
1125 GSequenceIterCompareFunc iter_cmp,
1126 gpointer cmp_data)
1128 GSequenceNode *node;
1129 GSequenceNode *dummy;
1130 GSequence *tmp_seq;
1132 g_return_val_if_fail (seq != NULL, NULL);
1134 check_seq_access (seq);
1136 seq->access_prohibited = TRUE;
1138 tmp_seq = g_sequence_new (NULL);
1139 tmp_seq->real_sequence = seq;
1141 dummy = g_sequence_append (tmp_seq, data);
1143 node = node_find (seq->end_node, dummy,
1144 seq->end_node, iter_cmp, cmp_data);
1146 g_sequence_free (tmp_seq);
1148 seq->access_prohibited = FALSE;
1150 return node;
1154 * g_sequence_iter_get_sequence:
1155 * @iter: a #GSequenceIter
1157 * Returns the #GSequence that @iter points into.
1159 * Returns: the #GSequence that @iter points into
1161 * Since: 2.14
1163 GSequence *
1164 g_sequence_iter_get_sequence (GSequenceIter *iter)
1166 GSequence *seq;
1168 g_return_val_if_fail (iter != NULL, NULL);
1170 seq = get_sequence (iter);
1172 /* For temporary sequences, this points to the sequence that
1173 * is actually being manipulated
1175 return seq->real_sequence;
1179 * g_sequence_get:
1180 * @iter: a #GSequenceIter
1182 * Returns the data that @iter points to.
1184 * Returns: the data that @iter points to
1186 * Since: 2.14
1188 gpointer
1189 g_sequence_get (GSequenceIter *iter)
1191 g_return_val_if_fail (iter != NULL, NULL);
1192 g_return_val_if_fail (!is_end (iter), NULL);
1194 return iter->data;
1198 * g_sequence_set:
1199 * @iter: a #GSequenceIter
1200 * @data: new data for the item
1202 * Changes the data for the item pointed to by @iter to be @data. If
1203 * the sequence has a data destroy function associated with it, that
1204 * function is called on the existing data that @iter pointed to.
1206 * Since: 2.14
1208 void
1209 g_sequence_set (GSequenceIter *iter,
1210 gpointer data)
1212 GSequence *seq;
1214 g_return_if_fail (iter != NULL);
1215 g_return_if_fail (!is_end (iter));
1217 seq = get_sequence (iter);
1219 /* If @data is identical to iter->data, it is destroyed
1220 * here. This will work right in case of ref-counted objects. Also
1221 * it is similar to what ghashtables do.
1223 * For non-refcounted data it's a little less convenient, but
1224 * code relying on self-setting not destroying would be
1225 * pretty dubious anyway ...
1228 if (seq->data_destroy_notify)
1229 seq->data_destroy_notify (iter->data);
1231 iter->data = data;
1235 * g_sequence_get_length:
1236 * @seq: a #GSequence
1238 * Returns the length of @seq. Note that this method is O(h) where `h' is the
1239 * height of the tree. It is thus more efficient to use g_sequence_is_empty()
1240 * when comparing the length to zero.
1242 * Returns: the length of @seq
1244 * Since: 2.14
1246 gint
1247 g_sequence_get_length (GSequence *seq)
1249 return node_get_length (seq->end_node) - 1;
1253 * g_sequence_is_empty:
1254 * @seq: a #GSequence
1256 * Returns %TRUE if the sequence contains zero items.
1258 * This function is functionally identical to checking the result of
1259 * g_sequence_get_length() being equal to zero. However this function is
1260 * implemented in O(1) running time.
1262 * Returns: %TRUE if the sequence is empty, otherwise %FALSE.
1264 * Since: 2.48
1266 gboolean
1267 g_sequence_is_empty (GSequence *seq)
1269 return (seq->end_node->parent == NULL) && (seq->end_node->left == NULL);
1273 * g_sequence_get_end_iter:
1274 * @seq: a #GSequence
1276 * Returns the end iterator for @seg
1278 * Returns: the end iterator for @seq
1280 * Since: 2.14
1282 GSequenceIter *
1283 g_sequence_get_end_iter (GSequence *seq)
1285 g_return_val_if_fail (seq != NULL, NULL);
1287 return seq->end_node;
1291 * g_sequence_get_begin_iter:
1292 * @seq: a #GSequence
1294 * Returns the begin iterator for @seq.
1296 * Returns: the begin iterator for @seq.
1298 * Since: 2.14
1300 GSequenceIter *
1301 g_sequence_get_begin_iter (GSequence *seq)
1303 g_return_val_if_fail (seq != NULL, NULL);
1305 return node_get_first (seq->end_node);
1308 static int
1309 clamp_position (GSequence *seq,
1310 int pos)
1312 gint len = g_sequence_get_length (seq);
1314 if (pos > len || pos < 0)
1315 pos = len;
1317 return pos;
1321 * if pos > number of items or -1, will return end pointer
1324 * g_sequence_get_iter_at_pos:
1325 * @seq: a #GSequence
1326 * @pos: a position in @seq, or -1 for the end
1328 * Returns the iterator at position @pos. If @pos is negative or larger
1329 * than the number of items in @seq, the end iterator is returned.
1331 * Returns: The #GSequenceIter at position @pos
1333 * Since: 2.14
1335 GSequenceIter *
1336 g_sequence_get_iter_at_pos (GSequence *seq,
1337 gint pos)
1339 g_return_val_if_fail (seq != NULL, NULL);
1341 pos = clamp_position (seq, pos);
1343 return node_get_by_pos (seq->end_node, pos);
1347 * g_sequence_move:
1348 * @src: a #GSequenceIter pointing to the item to move
1349 * @dest: a #GSequenceIter pointing to the position to which
1350 * the item is moved
1352 * Moves the item pointed to by @src to the position indicated by @dest.
1353 * After calling this function @dest will point to the position immediately
1354 * after @src. It is allowed for @src and @dest to point into different
1355 * sequences.
1357 * Since: 2.14
1359 void
1360 g_sequence_move (GSequenceIter *src,
1361 GSequenceIter *dest)
1363 g_return_if_fail (src != NULL);
1364 g_return_if_fail (dest != NULL);
1365 g_return_if_fail (!is_end (src));
1367 if (src == dest)
1368 return;
1370 node_unlink (src);
1371 node_insert_before (dest, src);
1374 /* GSequenceIter */
1377 * g_sequence_iter_is_end:
1378 * @iter: a #GSequenceIter
1380 * Returns whether @iter is the end iterator
1382 * Returns: Whether @iter is the end iterator
1384 * Since: 2.14
1386 gboolean
1387 g_sequence_iter_is_end (GSequenceIter *iter)
1389 g_return_val_if_fail (iter != NULL, FALSE);
1391 return is_end (iter);
1395 * g_sequence_iter_is_begin:
1396 * @iter: a #GSequenceIter
1398 * Returns whether @iter is the begin iterator
1400 * Returns: whether @iter is the begin iterator
1402 * Since: 2.14
1404 gboolean
1405 g_sequence_iter_is_begin (GSequenceIter *iter)
1407 g_return_val_if_fail (iter != NULL, FALSE);
1409 return (node_get_prev (iter) == iter);
1413 * g_sequence_iter_get_position:
1414 * @iter: a #GSequenceIter
1416 * Returns the position of @iter
1418 * Returns: the position of @iter
1420 * Since: 2.14
1422 gint
1423 g_sequence_iter_get_position (GSequenceIter *iter)
1425 g_return_val_if_fail (iter != NULL, -1);
1427 return node_get_pos (iter);
1431 * g_sequence_iter_next:
1432 * @iter: a #GSequenceIter
1434 * Returns an iterator pointing to the next position after @iter.
1435 * If @iter is the end iterator, the end iterator is returned.
1437 * Returns: a #GSequenceIter pointing to the next position after @iter
1439 * Since: 2.14
1441 GSequenceIter *
1442 g_sequence_iter_next (GSequenceIter *iter)
1444 g_return_val_if_fail (iter != NULL, NULL);
1446 return node_get_next (iter);
1450 * g_sequence_iter_prev:
1451 * @iter: a #GSequenceIter
1453 * Returns an iterator pointing to the previous position before @iter.
1454 * If @iter is the begin iterator, the begin iterator is returned.
1456 * Returns: a #GSequenceIter pointing to the previous position
1457 * before @iter
1459 * Since: 2.14
1461 GSequenceIter *
1462 g_sequence_iter_prev (GSequenceIter *iter)
1464 g_return_val_if_fail (iter != NULL, NULL);
1466 return node_get_prev (iter);
1470 * g_sequence_iter_move:
1471 * @iter: a #GSequenceIter
1472 * @delta: A positive or negative number indicating how many positions away
1473 * from @iter the returned #GSequenceIter will be
1475 * Returns the #GSequenceIter which is @delta positions away from @iter.
1476 * If @iter is closer than -@delta positions to the beginning of the sequence,
1477 * the begin iterator is returned. If @iter is closer than @delta positions
1478 * to the end of the sequence, the end iterator is returned.
1480 * Returns: a #GSequenceIter which is @delta positions away from @iter
1482 * Since: 2.14
1484 GSequenceIter *
1485 g_sequence_iter_move (GSequenceIter *iter,
1486 gint delta)
1488 gint new_pos;
1489 gint len;
1491 g_return_val_if_fail (iter != NULL, NULL);
1493 len = g_sequence_get_length (get_sequence (iter));
1495 new_pos = node_get_pos (iter) + delta;
1497 if (new_pos < 0)
1498 new_pos = 0;
1499 else if (new_pos > len)
1500 new_pos = len;
1502 return node_get_by_pos (iter, new_pos);
1506 * g_sequence_swap:
1507 * @a: a #GSequenceIter
1508 * @b: a #GSequenceIter
1510 * Swaps the items pointed to by @a and @b. It is allowed for @a and @b
1511 * to point into difference sequences.
1513 * Since: 2.14
1515 void
1516 g_sequence_swap (GSequenceIter *a,
1517 GSequenceIter *b)
1519 GSequenceNode *leftmost, *rightmost, *rightmost_next;
1520 int a_pos, b_pos;
1522 g_return_if_fail (!g_sequence_iter_is_end (a));
1523 g_return_if_fail (!g_sequence_iter_is_end (b));
1525 if (a == b)
1526 return;
1528 a_pos = g_sequence_iter_get_position (a);
1529 b_pos = g_sequence_iter_get_position (b);
1531 if (a_pos > b_pos)
1533 leftmost = b;
1534 rightmost = a;
1536 else
1538 leftmost = a;
1539 rightmost = b;
1542 rightmost_next = node_get_next (rightmost);
1544 /* The situation is now like this:
1546 * ..., leftmost, ......., rightmost, rightmost_next, ...
1549 g_sequence_move (rightmost, leftmost);
1550 g_sequence_move (leftmost, rightmost_next);
1554 * Implementation of a treap
1558 static guint
1559 get_priority (GSequenceNode *node)
1561 guint key = GPOINTER_TO_UINT (node);
1563 /* This hash function is based on one found on Thomas Wang's
1564 * web page at
1566 * http://www.concentric.net/~Ttwang/tech/inthash.htm
1569 key = (key << 15) - key - 1;
1570 key = key ^ (key >> 12);
1571 key = key + (key << 2);
1572 key = key ^ (key >> 4);
1573 key = key + (key << 3) + (key << 11);
1574 key = key ^ (key >> 16);
1576 /* We rely on 0 being less than all other priorities */
1577 return key? key : 1;
1580 static GSequenceNode *
1581 find_root (GSequenceNode *node)
1583 while (node->parent)
1584 node = node->parent;
1586 return node;
1589 static GSequenceNode *
1590 node_new (gpointer data)
1592 GSequenceNode *node = g_slice_new0 (GSequenceNode);
1594 node->n_nodes = 1;
1595 node->data = data;
1596 node->left = NULL;
1597 node->right = NULL;
1598 node->parent = NULL;
1600 return node;
1603 static GSequenceNode *
1604 node_get_first (GSequenceNode *node)
1606 node = find_root (node);
1608 while (node->left)
1609 node = node->left;
1611 return node;
1614 static GSequenceNode *
1615 node_get_last (GSequenceNode *node)
1617 node = find_root (node);
1619 while (node->right)
1620 node = node->right;
1622 return node;
1625 #define NODE_LEFT_CHILD(n) (((n)->parent) && ((n)->parent->left) == (n))
1626 #define NODE_RIGHT_CHILD(n) (((n)->parent) && ((n)->parent->right) == (n))
1628 static GSequenceNode *
1629 node_get_next (GSequenceNode *node)
1631 GSequenceNode *n = node;
1633 if (n->right)
1635 n = n->right;
1636 while (n->left)
1637 n = n->left;
1639 else
1641 while (NODE_RIGHT_CHILD (n))
1642 n = n->parent;
1644 if (n->parent)
1645 n = n->parent;
1646 else
1647 n = node;
1650 return n;
1653 static GSequenceNode *
1654 node_get_prev (GSequenceNode *node)
1656 GSequenceNode *n = node;
1658 if (n->left)
1660 n = n->left;
1661 while (n->right)
1662 n = n->right;
1664 else
1666 while (NODE_LEFT_CHILD (n))
1667 n = n->parent;
1669 if (n->parent)
1670 n = n->parent;
1671 else
1672 n = node;
1675 return n;
1678 #define N_NODES(n) ((n)? (n)->n_nodes : 0)
1680 static gint
1681 node_get_pos (GSequenceNode *node)
1683 int n_smaller = 0;
1685 if (node->left)
1686 n_smaller = node->left->n_nodes;
1688 while (node)
1690 if (NODE_RIGHT_CHILD (node))
1691 n_smaller += N_NODES (node->parent->left) + 1;
1693 node = node->parent;
1696 return n_smaller;
1699 static GSequenceNode *
1700 node_get_by_pos (GSequenceNode *node,
1701 gint pos)
1703 int i;
1705 node = find_root (node);
1707 while ((i = N_NODES (node->left)) != pos)
1709 if (i < pos)
1711 node = node->right;
1712 pos -= (i + 1);
1714 else
1716 node = node->left;
1720 return node;
1723 static GSequenceNode *
1724 node_find (GSequenceNode *haystack,
1725 GSequenceNode *needle,
1726 GSequenceNode *end,
1727 GSequenceIterCompareFunc iter_cmp,
1728 gpointer cmp_data)
1730 gint c;
1732 haystack = find_root (haystack);
1736 /* iter_cmp can't be passed the end node, since the function may
1737 * be user-supplied
1739 if (haystack == end)
1740 c = 1;
1741 else
1742 c = iter_cmp (haystack, needle, cmp_data);
1744 if (c == 0)
1745 break;
1747 if (c > 0)
1748 haystack = haystack->left;
1749 else
1750 haystack = haystack->right;
1752 while (haystack != NULL);
1754 return haystack;
1757 static GSequenceNode *
1758 node_find_closest (GSequenceNode *haystack,
1759 GSequenceNode *needle,
1760 GSequenceNode *end,
1761 GSequenceIterCompareFunc iter_cmp,
1762 gpointer cmp_data)
1764 GSequenceNode *best;
1765 gint c;
1767 haystack = find_root (haystack);
1771 best = haystack;
1773 /* iter_cmp can't be passed the end node, since the function may
1774 * be user-supplied
1776 if (haystack == end)
1777 c = 1;
1778 else
1779 c = iter_cmp (haystack, needle, cmp_data);
1781 /* In the following we don't break even if c == 0. Instead we go on
1782 * searching along the 'bigger' nodes, so that we find the last one
1783 * that is equal to the needle.
1785 if (c > 0)
1786 haystack = haystack->left;
1787 else
1788 haystack = haystack->right;
1790 while (haystack != NULL);
1792 /* If the best node is smaller or equal to the data, then move one step
1793 * to the right to make sure the best one is strictly bigger than the data
1795 if (best != end && c <= 0)
1796 best = node_get_next (best);
1798 return best;
1801 static gint
1802 node_get_length (GSequenceNode *node)
1804 node = find_root (node);
1806 return node->n_nodes;
1809 static void
1810 real_node_free (GSequenceNode *node,
1811 GSequence *seq)
1813 if (node)
1815 real_node_free (node->left, seq);
1816 real_node_free (node->right, seq);
1818 if (seq && seq->data_destroy_notify && node != seq->end_node)
1819 seq->data_destroy_notify (node->data);
1821 g_slice_free (GSequenceNode, node);
1825 static void
1826 node_free (GSequenceNode *node,
1827 GSequence *seq)
1829 node = find_root (node);
1831 real_node_free (node, seq);
1834 static void
1835 node_update_fields (GSequenceNode *node)
1837 int n_nodes = 1;
1839 n_nodes += N_NODES (node->left);
1840 n_nodes += N_NODES (node->right);
1842 node->n_nodes = n_nodes;
1845 static void
1846 node_rotate (GSequenceNode *node)
1848 GSequenceNode *tmp, *old;
1850 g_assert (node->parent);
1851 g_assert (node->parent != node);
1853 if (NODE_LEFT_CHILD (node))
1855 /* rotate right */
1856 tmp = node->right;
1858 node->right = node->parent;
1859 node->parent = node->parent->parent;
1860 if (node->parent)
1862 if (node->parent->left == node->right)
1863 node->parent->left = node;
1864 else
1865 node->parent->right = node;
1868 g_assert (node->right);
1870 node->right->parent = node;
1871 node->right->left = tmp;
1873 if (node->right->left)
1874 node->right->left->parent = node->right;
1876 old = node->right;
1878 else
1880 /* rotate left */
1881 tmp = node->left;
1883 node->left = node->parent;
1884 node->parent = node->parent->parent;
1885 if (node->parent)
1887 if (node->parent->right == node->left)
1888 node->parent->right = node;
1889 else
1890 node->parent->left = node;
1893 g_assert (node->left);
1895 node->left->parent = node;
1896 node->left->right = tmp;
1898 if (node->left->right)
1899 node->left->right->parent = node->left;
1901 old = node->left;
1904 node_update_fields (old);
1905 node_update_fields (node);
1908 static void
1909 node_update_fields_deep (GSequenceNode *node)
1911 if (node)
1913 node_update_fields (node);
1915 node_update_fields_deep (node->parent);
1919 static void
1920 rotate_down (GSequenceNode *node,
1921 guint priority)
1923 guint left, right;
1925 left = node->left ? get_priority (node->left) : 0;
1926 right = node->right ? get_priority (node->right) : 0;
1928 while (priority < left || priority < right)
1930 if (left > right)
1931 node_rotate (node->left);
1932 else
1933 node_rotate (node->right);
1935 left = node->left ? get_priority (node->left) : 0;
1936 right = node->right ? get_priority (node->right) : 0;
1940 static void
1941 node_cut (GSequenceNode *node)
1943 while (node->parent)
1944 node_rotate (node);
1946 if (node->left)
1947 node->left->parent = NULL;
1949 node->left = NULL;
1950 node_update_fields (node);
1952 rotate_down (node, get_priority (node));
1955 static void
1956 node_join (GSequenceNode *left,
1957 GSequenceNode *right)
1959 GSequenceNode *fake = node_new (NULL);
1961 fake->left = find_root (left);
1962 fake->right = find_root (right);
1963 fake->left->parent = fake;
1964 fake->right->parent = fake;
1966 node_update_fields (fake);
1968 node_unlink (fake);
1970 node_free (fake, NULL);
1973 static void
1974 node_insert_before (GSequenceNode *node,
1975 GSequenceNode *new)
1977 new->left = node->left;
1978 if (new->left)
1979 new->left->parent = new;
1981 new->parent = node;
1982 node->left = new;
1984 node_update_fields_deep (new);
1986 while (new->parent && get_priority (new) > get_priority (new->parent))
1987 node_rotate (new);
1989 rotate_down (new, get_priority (new));
1992 static void
1993 node_unlink (GSequenceNode *node)
1995 rotate_down (node, 0);
1997 if (NODE_RIGHT_CHILD (node))
1998 node->parent->right = NULL;
1999 else if (NODE_LEFT_CHILD (node))
2000 node->parent->left = NULL;
2002 if (node->parent)
2003 node_update_fields_deep (node->parent);
2005 node->parent = NULL;
2008 static void
2009 node_insert_sorted (GSequenceNode *node,
2010 GSequenceNode *new,
2011 GSequenceNode *end,
2012 GSequenceIterCompareFunc iter_cmp,
2013 gpointer cmp_data)
2015 GSequenceNode *closest;
2017 closest = node_find_closest (node, new, end, iter_cmp, cmp_data);
2019 node_unlink (new);
2021 node_insert_before (closest, new);