1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3 *
4 * GQueue: Double ended queue implementation, piggy backed on GList.
5 * Copyright (C) 1998 Tim Janik
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 /*
22 * MT safe
23 */
24
25 /**
26 * SECTION:queue
27 * @Title: Double-ended Queues
28 * @Short_description: double-ended queue data structure
29 *
30 * The #GQueue structure and its associated functions provide a standard
31 * queue data structure. Internally, GQueue uses the same data structure
32 * as #GList to store elements with the same complexity over
33 * insertion/deletion (O(1)) and access/search (O(n)) operations.
34 *
35 * The data contained in each element can be either integer values, by
36 * using one of the [Type Conversion Macros][glib-Type-Conversion-Macros],
37 * or simply pointers to any type of data.
38 *
39 * As with all other GLib data structures, #GQueue is not thread-safe.
40 * For a thread-safe queue, use #GAsyncQueue.
41 *
42 * To create a new GQueue, use g_queue_new().
43 *
44 * To initialize a statically-allocated GQueue, use #G_QUEUE_INIT or
45 * g_queue_init().
46 *
47 * To add elements, use g_queue_push_head(), g_queue_push_head_link(),
48 * g_queue_push_tail() and g_queue_push_tail_link().
49 *
50 * To remove elements, use g_queue_pop_head() and g_queue_pop_tail().
51 *
52 * To free the entire queue, use g_queue_free().
53 */
54 #include "config.h"
55
56 #include "gqueue.h"
57
58 #include "gtestutils.h"
59 #include "gslice.h"
60
61 /**
62 * g_queue_new:
63 *
64 * Creates a new #GQueue.
65 *
66 * Returns: a newly allocated #GQueue
67 **/
68 GQueue *
g_queue_new(void)69 g_queue_new (void)
70 {
71 return g_slice_new0 (GQueue);
72 }
73
74 /**
75 * g_queue_free:
76 * @queue: a #GQueue
77 *
78 * Frees the memory allocated for the #GQueue. Only call this function
79 * if @queue was created with g_queue_new(). If queue elements contain
80 * dynamically-allocated memory, they should be freed first.
81 *
82 * If queue elements contain dynamically-allocated memory, you should
83 * either use g_queue_free_full() or free them manually first.
84 **/
85 void
g_queue_free(GQueue * queue)86 g_queue_free (GQueue *queue)
87 {
88 g_return_if_fail (queue != NULL);
89
90 g_list_free (queue->head);
91 g_slice_free (GQueue, queue);
92 }
93
94 /**
95 * g_queue_free_full:
96 * @queue: a pointer to a #GQueue
97 * @free_func: the function to be called to free each element's data
98 *
99 * Convenience method, which frees all the memory used by a #GQueue,
100 * and calls the specified destroy function on every element's data.
101 *
102 * @free_func should not modify the queue (eg, by removing the freed
103 * element from it).
104 *
105 * Since: 2.32
106 */
107 void
g_queue_free_full(GQueue * queue,GDestroyNotify free_func)108 g_queue_free_full (GQueue *queue,
109 GDestroyNotify free_func)
110 {
111 g_queue_foreach (queue, (GFunc) free_func, NULL);
112 g_queue_free (queue);
113 }
114
115 /**
116 * g_queue_init:
117 * @queue: an uninitialized #GQueue
118 *
119 * A statically-allocated #GQueue must be initialized with this function
120 * before it can be used. Alternatively you can initialize it with
121 * #G_QUEUE_INIT. It is not necessary to initialize queues created with
122 * g_queue_new().
123 *
124 * Since: 2.14
125 */
126 void
g_queue_init(GQueue * queue)127 g_queue_init (GQueue *queue)
128 {
129 g_return_if_fail (queue != NULL);
130
131 queue->head = queue->tail = NULL;
132 queue->length = 0;
133 }
134
135 /**
136 * g_queue_clear:
137 * @queue: a #GQueue
138 *
139 * Removes all the elements in @queue. If queue elements contain
140 * dynamically-allocated memory, they should be freed first.
141 *
142 * Since: 2.14
143 */
144 void
g_queue_clear(GQueue * queue)145 g_queue_clear (GQueue *queue)
146 {
147 g_return_if_fail (queue != NULL);
148
149 g_list_free (queue->head);
150 g_queue_init (queue);
151 }
152
153 /**
154 * g_queue_clear_full:
155 * @queue: a pointer to a #GQueue
156 * @free_func: (nullable): the function to be called to free memory allocated
157 *
158 * Convenience method, which frees all the memory used by a #GQueue,
159 * and calls the provided @free_func on each item in the #GQueue.
160 *
161 * Since: 2.60
162 */
163 void
g_queue_clear_full(GQueue * queue,GDestroyNotify free_func)164 g_queue_clear_full (GQueue *queue,
165 GDestroyNotify free_func)
166 {
167 g_return_if_fail (queue != NULL);
168
169 if (free_func != NULL)
170 g_queue_foreach (queue, (GFunc) free_func, NULL);
171
172 g_queue_clear (queue);
173 }
174
175 /**
176 * g_queue_is_empty:
177 * @queue: a #GQueue.
178 *
179 * Returns %TRUE if the queue is empty.
180 *
181 * Returns: %TRUE if the queue is empty
182 */
183 gboolean
g_queue_is_empty(GQueue * queue)184 g_queue_is_empty (GQueue *queue)
185 {
186 g_return_val_if_fail (queue != NULL, TRUE);
187
188 return queue->head == NULL;
189 }
190
191 /**
192 * g_queue_get_length:
193 * @queue: a #GQueue
194 *
195 * Returns the number of items in @queue.
196 *
197 * Returns: the number of items in @queue
198 *
199 * Since: 2.4
200 */
201 guint
g_queue_get_length(GQueue * queue)202 g_queue_get_length (GQueue *queue)
203 {
204 g_return_val_if_fail (queue != NULL, 0);
205
206 return queue->length;
207 }
208
209 /**
210 * g_queue_reverse:
211 * @queue: a #GQueue
212 *
213 * Reverses the order of the items in @queue.
214 *
215 * Since: 2.4
216 */
217 void
g_queue_reverse(GQueue * queue)218 g_queue_reverse (GQueue *queue)
219 {
220 g_return_if_fail (queue != NULL);
221
222 queue->tail = queue->head;
223 queue->head = g_list_reverse (queue->head);
224 }
225
226 /**
227 * g_queue_copy:
228 * @queue: a #GQueue
229 *
230 * Copies a @queue. Note that is a shallow copy. If the elements in the
231 * queue consist of pointers to data, the pointers are copied, but the
232 * actual data is not.
233 *
234 * Returns: a copy of @queue
235 *
236 * Since: 2.4
237 */
238 GQueue *
g_queue_copy(GQueue * queue)239 g_queue_copy (GQueue *queue)
240 {
241 GQueue *result;
242 GList *list;
243
244 g_return_val_if_fail (queue != NULL, NULL);
245
246 result = g_queue_new ();
247
248 for (list = queue->head; list != NULL; list = list->next)
249 g_queue_push_tail (result, list->data);
250
251 return result;
252 }
253
254 /**
255 * g_queue_foreach:
256 * @queue: a #GQueue
257 * @func: the function to call for each element's data
258 * @user_data: user data to pass to @func
259 *
260 * Calls @func for each element in the queue passing @user_data to the
261 * function.
262 *
263 * It is safe for @func to remove the element from @queue, but it must
264 * not modify any part of the queue after that element.
265 *
266 * Since: 2.4
267 */
268 void
g_queue_foreach(GQueue * queue,GFunc func,gpointer user_data)269 g_queue_foreach (GQueue *queue,
270 GFunc func,
271 gpointer user_data)
272 {
273 GList *list;
274
275 g_return_if_fail (queue != NULL);
276 g_return_if_fail (func != NULL);
277
278 list = queue->head;
279 while (list)
280 {
281 GList *next = list->next;
282 func (list->data, user_data);
283 list = next;
284 }
285 }
286
287 /**
288 * g_queue_find:
289 * @queue: a #GQueue
290 * @data: data to find
291 *
292 * Finds the first link in @queue which contains @data.
293 *
294 * Returns: the first link in @queue which contains @data
295 *
296 * Since: 2.4
297 */
298 GList *
g_queue_find(GQueue * queue,gconstpointer data)299 g_queue_find (GQueue *queue,
300 gconstpointer data)
301 {
302 g_return_val_if_fail (queue != NULL, NULL);
303
304 return g_list_find (queue->head, data);
305 }
306
307 /**
308 * g_queue_find_custom:
309 * @queue: a #GQueue
310 * @data: user data passed to @func
311 * @func: a #GCompareFunc to call for each element. It should return 0
312 * when the desired element is found
313 *
314 * Finds an element in a #GQueue, using a supplied function to find the
315 * desired element. It iterates over the queue, calling the given function
316 * which should return 0 when the desired element is found. The function
317 * takes two gconstpointer arguments, the #GQueue element's data as the
318 * first argument and the given user data as the second argument.
319 *
320 * Returns: the found link, or %NULL if it wasn't found
321 *
322 * Since: 2.4
323 */
324 GList *
g_queue_find_custom(GQueue * queue,gconstpointer data,GCompareFunc func)325 g_queue_find_custom (GQueue *queue,
326 gconstpointer data,
327 GCompareFunc func)
328 {
329 g_return_val_if_fail (queue != NULL, NULL);
330 g_return_val_if_fail (func != NULL, NULL);
331
332 return g_list_find_custom (queue->head, data, func);
333 }
334
335 /**
336 * g_queue_sort:
337 * @queue: a #GQueue
338 * @compare_func: the #GCompareDataFunc used to sort @queue. This function
339 * is passed two elements of the queue and should return 0 if they are
340 * equal, a negative value if the first comes before the second, and
341 * a positive value if the second comes before the first.
342 * @user_data: user data passed to @compare_func
343 *
344 * Sorts @queue using @compare_func.
345 *
346 * Since: 2.4
347 */
348 void
g_queue_sort(GQueue * queue,GCompareDataFunc compare_func,gpointer user_data)349 g_queue_sort (GQueue *queue,
350 GCompareDataFunc compare_func,
351 gpointer user_data)
352 {
353 g_return_if_fail (queue != NULL);
354 g_return_if_fail (compare_func != NULL);
355
356 queue->head = g_list_sort_with_data (queue->head, compare_func, user_data);
357 queue->tail = g_list_last (queue->head);
358 }
359
360 /**
361 * g_queue_push_head:
362 * @queue: a #GQueue.
363 * @data: the data for the new element.
364 *
365 * Adds a new element at the head of the queue.
366 */
367 void
g_queue_push_head(GQueue * queue,gpointer data)368 g_queue_push_head (GQueue *queue,
369 gpointer data)
370 {
371 g_return_if_fail (queue != NULL);
372
373 queue->head = g_list_prepend (queue->head, data);
374 if (!queue->tail)
375 queue->tail = queue->head;
376 queue->length++;
377 }
378
379 /**
380 * g_queue_push_nth:
381 * @queue: a #GQueue
382 * @data: the data for the new element
383 * @n: the position to insert the new element. If @n is negative or
384 * larger than the number of elements in the @queue, the element is
385 * added to the end of the queue.
386 *
387 * Inserts a new element into @queue at the given position.
388 *
389 * Since: 2.4
390 */
391 void
g_queue_push_nth(GQueue * queue,gpointer data,gint n)392 g_queue_push_nth (GQueue *queue,
393 gpointer data,
394 gint n)
395 {
396 g_return_if_fail (queue != NULL);
397
398 if (n < 0 || (guint) n >= queue->length)
399 {
400 g_queue_push_tail (queue, data);
401 return;
402 }
403
404 g_queue_insert_before (queue, g_queue_peek_nth_link (queue, n), data);
405 }
406
407 /**
408 * g_queue_push_head_link:
409 * @queue: a #GQueue
410 * @link_: a single #GList element, not a list with more than one element
411 *
412 * Adds a new element at the head of the queue.
413 */
414 void
g_queue_push_head_link(GQueue * queue,GList * link)415 g_queue_push_head_link (GQueue *queue,
416 GList *link)
417 {
418 g_return_if_fail (queue != NULL);
419 g_return_if_fail (link != NULL);
420 g_return_if_fail (link->prev == NULL);
421 g_return_if_fail (link->next == NULL);
422
423 link->next = queue->head;
424 if (queue->head)
425 queue->head->prev = link;
426 else
427 queue->tail = link;
428 queue->head = link;
429 queue->length++;
430 }
431
432 /**
433 * g_queue_push_tail:
434 * @queue: a #GQueue
435 * @data: the data for the new element
436 *
437 * Adds a new element at the tail of the queue.
438 */
439 void
g_queue_push_tail(GQueue * queue,gpointer data)440 g_queue_push_tail (GQueue *queue,
441 gpointer data)
442 {
443 g_return_if_fail (queue != NULL);
444
445 queue->tail = g_list_append (queue->tail, data);
446 if (queue->tail->next)
447 queue->tail = queue->tail->next;
448 else
449 queue->head = queue->tail;
450 queue->length++;
451 }
452
453 /**
454 * g_queue_push_tail_link:
455 * @queue: a #GQueue
456 * @link_: a single #GList element, not a list with more than one element
457 *
458 * Adds a new element at the tail of the queue.
459 */
460 void
g_queue_push_tail_link(GQueue * queue,GList * link)461 g_queue_push_tail_link (GQueue *queue,
462 GList *link)
463 {
464 g_return_if_fail (queue != NULL);
465 g_return_if_fail (link != NULL);
466 g_return_if_fail (link->prev == NULL);
467 g_return_if_fail (link->next == NULL);
468
469 link->prev = queue->tail;
470 if (queue->tail)
471 queue->tail->next = link;
472 else
473 queue->head = link;
474 queue->tail = link;
475 queue->length++;
476 }
477
478 /**
479 * g_queue_push_nth_link:
480 * @queue: a #GQueue
481 * @n: the position to insert the link. If this is negative or larger than
482 * the number of elements in @queue, the link is added to the end of
483 * @queue.
484 * @link_: the link to add to @queue
485 *
486 * Inserts @link into @queue at the given position.
487 *
488 * Since: 2.4
489 */
490 void
g_queue_push_nth_link(GQueue * queue,gint n,GList * link_)491 g_queue_push_nth_link (GQueue *queue,
492 gint n,
493 GList *link_)
494 {
495 GList *next;
496 GList *prev;
497
498 g_return_if_fail (queue != NULL);
499 g_return_if_fail (link_ != NULL);
500
501 if (n < 0 || (guint) n >= queue->length)
502 {
503 g_queue_push_tail_link (queue, link_);
504 return;
505 }
506
507 g_assert (queue->head);
508 g_assert (queue->tail);
509
510 next = g_queue_peek_nth_link (queue, n);
511 prev = next->prev;
512
513 if (prev)
514 prev->next = link_;
515 next->prev = link_;
516
517 link_->next = next;
518 link_->prev = prev;
519
520 if (queue->head->prev)
521 queue->head = queue->head->prev;
522
523 /* The case where we’re pushing @link_ at the end of @queue is handled above
524 * using g_queue_push_tail_link(), so we should never have to manually adjust
525 * queue->tail. */
526 g_assert (queue->tail->next == NULL);
527
528 queue->length++;
529 }
530
531 /**
532 * g_queue_pop_head:
533 * @queue: a #GQueue
534 *
535 * Removes the first element of the queue and returns its data.
536 *
537 * Returns: the data of the first element in the queue, or %NULL
538 * if the queue is empty
539 */
540 gpointer
g_queue_pop_head(GQueue * queue)541 g_queue_pop_head (GQueue *queue)
542 {
543 g_return_val_if_fail (queue != NULL, NULL);
544
545 if (queue->head)
546 {
547 GList *node = queue->head;
548 gpointer data = node->data;
549
550 queue->head = node->next;
551 if (queue->head)
552 queue->head->prev = NULL;
553 else
554 queue->tail = NULL;
555 g_list_free_1 (node);
556 queue->length--;
557
558 return data;
559 }
560
561 return NULL;
562 }
563
564 /**
565 * g_queue_pop_head_link:
566 * @queue: a #GQueue
567 *
568 * Removes and returns the first element of the queue.
569 *
570 * Returns: the #GList element at the head of the queue, or %NULL
571 * if the queue is empty
572 */
573 GList *
g_queue_pop_head_link(GQueue * queue)574 g_queue_pop_head_link (GQueue *queue)
575 {
576 g_return_val_if_fail (queue != NULL, NULL);
577
578 if (queue->head)
579 {
580 GList *node = queue->head;
581
582 queue->head = node->next;
583 if (queue->head)
584 {
585 queue->head->prev = NULL;
586 node->next = NULL;
587 }
588 else
589 queue->tail = NULL;
590 queue->length--;
591
592 return node;
593 }
594
595 return NULL;
596 }
597
598 /**
599 * g_queue_peek_head_link:
600 * @queue: a #GQueue
601 *
602 * Returns the first link in @queue.
603 *
604 * Returns: the first link in @queue, or %NULL if @queue is empty
605 *
606 * Since: 2.4
607 */
608 GList *
g_queue_peek_head_link(GQueue * queue)609 g_queue_peek_head_link (GQueue *queue)
610 {
611 g_return_val_if_fail (queue != NULL, NULL);
612
613 return queue->head;
614 }
615
616 /**
617 * g_queue_peek_tail_link:
618 * @queue: a #GQueue
619 *
620 * Returns the last link in @queue.
621 *
622 * Returns: the last link in @queue, or %NULL if @queue is empty
623 *
624 * Since: 2.4
625 */
626 GList *
g_queue_peek_tail_link(GQueue * queue)627 g_queue_peek_tail_link (GQueue *queue)
628 {
629 g_return_val_if_fail (queue != NULL, NULL);
630
631 return queue->tail;
632 }
633
634 /**
635 * g_queue_pop_tail:
636 * @queue: a #GQueue
637 *
638 * Removes the last element of the queue and returns its data.
639 *
640 * Returns: the data of the last element in the queue, or %NULL
641 * if the queue is empty
642 */
643 gpointer
g_queue_pop_tail(GQueue * queue)644 g_queue_pop_tail (GQueue *queue)
645 {
646 g_return_val_if_fail (queue != NULL, NULL);
647
648 if (queue->tail)
649 {
650 GList *node = queue->tail;
651 gpointer data = node->data;
652
653 queue->tail = node->prev;
654 if (queue->tail)
655 queue->tail->next = NULL;
656 else
657 queue->head = NULL;
658 queue->length--;
659 g_list_free_1 (node);
660
661 return data;
662 }
663
664 return NULL;
665 }
666
667 /**
668 * g_queue_pop_nth:
669 * @queue: a #GQueue
670 * @n: the position of the element
671 *
672 * Removes the @n'th element of @queue and returns its data.
673 *
674 * Returns: the element's data, or %NULL if @n is off the end of @queue
675 *
676 * Since: 2.4
677 */
678 gpointer
g_queue_pop_nth(GQueue * queue,guint n)679 g_queue_pop_nth (GQueue *queue,
680 guint n)
681 {
682 GList *nth_link;
683 gpointer result;
684
685 g_return_val_if_fail (queue != NULL, NULL);
686
687 if (n >= queue->length)
688 return NULL;
689
690 nth_link = g_queue_peek_nth_link (queue, n);
691 result = nth_link->data;
692
693 g_queue_delete_link (queue, nth_link);
694
695 return result;
696 }
697
698 /**
699 * g_queue_pop_tail_link:
700 * @queue: a #GQueue
701 *
702 * Removes and returns the last element of the queue.
703 *
704 * Returns: the #GList element at the tail of the queue, or %NULL
705 * if the queue is empty
706 */
707 GList *
g_queue_pop_tail_link(GQueue * queue)708 g_queue_pop_tail_link (GQueue *queue)
709 {
710 g_return_val_if_fail (queue != NULL, NULL);
711
712 if (queue->tail)
713 {
714 GList *node = queue->tail;
715
716 queue->tail = node->prev;
717 if (queue->tail)
718 {
719 queue->tail->next = NULL;
720 node->prev = NULL;
721 }
722 else
723 queue->head = NULL;
724 queue->length--;
725
726 return node;
727 }
728
729 return NULL;
730 }
731
732 /**
733 * g_queue_pop_nth_link:
734 * @queue: a #GQueue
735 * @n: the link's position
736 *
737 * Removes and returns the link at the given position.
738 *
739 * Returns: the @n'th link, or %NULL if @n is off the end of @queue
740 *
741 * Since: 2.4
742 */
743 GList*
g_queue_pop_nth_link(GQueue * queue,guint n)744 g_queue_pop_nth_link (GQueue *queue,
745 guint n)
746 {
747 GList *link;
748
749 g_return_val_if_fail (queue != NULL, NULL);
750
751 if (n >= queue->length)
752 return NULL;
753
754 link = g_queue_peek_nth_link (queue, n);
755 g_queue_unlink (queue, link);
756
757 return link;
758 }
759
760 /**
761 * g_queue_peek_nth_link:
762 * @queue: a #GQueue
763 * @n: the position of the link
764 *
765 * Returns the link at the given position
766 *
767 * Returns: the link at the @n'th position, or %NULL
768 * if @n is off the end of the list
769 *
770 * Since: 2.4
771 */
772 GList *
g_queue_peek_nth_link(GQueue * queue,guint n)773 g_queue_peek_nth_link (GQueue *queue,
774 guint n)
775 {
776 GList *link;
777 guint i;
778
779 g_return_val_if_fail (queue != NULL, NULL);
780
781 if (n >= queue->length)
782 return NULL;
783
784 if (n > queue->length / 2)
785 {
786 n = queue->length - n - 1;
787
788 link = queue->tail;
789 for (i = 0; i < n; ++i)
790 link = link->prev;
791 }
792 else
793 {
794 link = queue->head;
795 for (i = 0; i < n; ++i)
796 link = link->next;
797 }
798
799 return link;
800 }
801
802 /**
803 * g_queue_link_index:
804 * @queue: a #GQueue
805 * @link_: a #GList link
806 *
807 * Returns the position of @link_ in @queue.
808 *
809 * Returns: the position of @link_, or -1 if the link is
810 * not part of @queue
811 *
812 * Since: 2.4
813 */
814 gint
g_queue_link_index(GQueue * queue,GList * link_)815 g_queue_link_index (GQueue *queue,
816 GList *link_)
817 {
818 g_return_val_if_fail (queue != NULL, -1);
819
820 return g_list_position (queue->head, link_);
821 }
822
823 /**
824 * g_queue_unlink:
825 * @queue: a #GQueue
826 * @link_: a #GList link that must be part of @queue
827 *
828 * Unlinks @link_ so that it will no longer be part of @queue.
829 * The link is not freed.
830 *
831 * @link_ must be part of @queue.
832 *
833 * Since: 2.4
834 */
835 void
g_queue_unlink(GQueue * queue,GList * link_)836 g_queue_unlink (GQueue *queue,
837 GList *link_)
838 {
839 g_return_if_fail (queue != NULL);
840 g_return_if_fail (link_ != NULL);
841
842 if (link_ == queue->tail)
843 queue->tail = queue->tail->prev;
844
845 queue->head = g_list_remove_link (queue->head, link_);
846 queue->length--;
847 }
848
849 /**
850 * g_queue_delete_link:
851 * @queue: a #GQueue
852 * @link_: a #GList link that must be part of @queue
853 *
854 * Removes @link_ from @queue and frees it.
855 *
856 * @link_ must be part of @queue.
857 *
858 * Since: 2.4
859 */
860 void
g_queue_delete_link(GQueue * queue,GList * link_)861 g_queue_delete_link (GQueue *queue,
862 GList *link_)
863 {
864 g_return_if_fail (queue != NULL);
865 g_return_if_fail (link_ != NULL);
866
867 g_queue_unlink (queue, link_);
868 g_list_free (link_);
869 }
870
871 /**
872 * g_queue_peek_head:
873 * @queue: a #GQueue
874 *
875 * Returns the first element of the queue.
876 *
877 * Returns: the data of the first element in the queue, or %NULL
878 * if the queue is empty
879 */
880 gpointer
g_queue_peek_head(GQueue * queue)881 g_queue_peek_head (GQueue *queue)
882 {
883 g_return_val_if_fail (queue != NULL, NULL);
884
885 return queue->head ? queue->head->data : NULL;
886 }
887
888 /**
889 * g_queue_peek_tail:
890 * @queue: a #GQueue
891 *
892 * Returns the last element of the queue.
893 *
894 * Returns: the data of the last element in the queue, or %NULL
895 * if the queue is empty
896 */
897 gpointer
g_queue_peek_tail(GQueue * queue)898 g_queue_peek_tail (GQueue *queue)
899 {
900 g_return_val_if_fail (queue != NULL, NULL);
901
902 return queue->tail ? queue->tail->data : NULL;
903 }
904
905 /**
906 * g_queue_peek_nth:
907 * @queue: a #GQueue
908 * @n: the position of the element
909 *
910 * Returns the @n'th element of @queue.
911 *
912 * Returns: the data for the @n'th element of @queue,
913 * or %NULL if @n is off the end of @queue
914 *
915 * Since: 2.4
916 */
917 gpointer
g_queue_peek_nth(GQueue * queue,guint n)918 g_queue_peek_nth (GQueue *queue,
919 guint n)
920 {
921 GList *link;
922
923 g_return_val_if_fail (queue != NULL, NULL);
924
925 link = g_queue_peek_nth_link (queue, n);
926
927 if (link)
928 return link->data;
929
930 return NULL;
931 }
932
933 /**
934 * g_queue_index:
935 * @queue: a #GQueue
936 * @data: the data to find
937 *
938 * Returns the position of the first element in @queue which contains @data.
939 *
940 * Returns: the position of the first element in @queue which
941 * contains @data, or -1 if no element in @queue contains @data
942 *
943 * Since: 2.4
944 */
945 gint
g_queue_index(GQueue * queue,gconstpointer data)946 g_queue_index (GQueue *queue,
947 gconstpointer data)
948 {
949 g_return_val_if_fail (queue != NULL, -1);
950
951 return g_list_index (queue->head, data);
952 }
953
954 /**
955 * g_queue_remove:
956 * @queue: a #GQueue
957 * @data: the data to remove
958 *
959 * Removes the first element in @queue that contains @data.
960 *
961 * Returns: %TRUE if @data was found and removed from @queue
962 *
963 * Since: 2.4
964 */
965 gboolean
g_queue_remove(GQueue * queue,gconstpointer data)966 g_queue_remove (GQueue *queue,
967 gconstpointer data)
968 {
969 GList *link;
970
971 g_return_val_if_fail (queue != NULL, FALSE);
972
973 link = g_list_find (queue->head, data);
974
975 if (link)
976 g_queue_delete_link (queue, link);
977
978 return (link != NULL);
979 }
980
981 /**
982 * g_queue_remove_all:
983 * @queue: a #GQueue
984 * @data: the data to remove
985 *
986 * Remove all elements whose data equals @data from @queue.
987 *
988 * Returns: the number of elements removed from @queue
989 *
990 * Since: 2.4
991 */
992 guint
g_queue_remove_all(GQueue * queue,gconstpointer data)993 g_queue_remove_all (GQueue *queue,
994 gconstpointer data)
995 {
996 GList *list;
997 guint old_length;
998
999 g_return_val_if_fail (queue != NULL, 0);
1000
1001 old_length = queue->length;
1002
1003 list = queue->head;
1004 while (list)
1005 {
1006 GList *next = list->next;
1007
1008 if (list->data == data)
1009 g_queue_delete_link (queue, list);
1010
1011 list = next;
1012 }
1013
1014 return (old_length - queue->length);
1015 }
1016
1017 /**
1018 * g_queue_insert_before:
1019 * @queue: a #GQueue
1020 * @sibling: (nullable): a #GList link that must be part of @queue, or %NULL to
1021 * push at the tail of the queue.
1022 * @data: the data to insert
1023 *
1024 * Inserts @data into @queue before @sibling.
1025 *
1026 * @sibling must be part of @queue. Since GLib 2.44 a %NULL sibling pushes the
1027 * data at the tail of the queue.
1028 *
1029 * Since: 2.4
1030 */
1031 void
g_queue_insert_before(GQueue * queue,GList * sibling,gpointer data)1032 g_queue_insert_before (GQueue *queue,
1033 GList *sibling,
1034 gpointer data)
1035 {
1036 g_return_if_fail (queue != NULL);
1037
1038 if (sibling == NULL)
1039 {
1040 /* We don't use g_list_insert_before() with a NULL sibling because it
1041 * would be a O(n) operation and we would need to update manually the tail
1042 * pointer.
1043 */
1044 g_queue_push_tail (queue, data);
1045 }
1046 else
1047 {
1048 queue->head = g_list_insert_before (queue->head, sibling, data);
1049 queue->length++;
1050 }
1051 }
1052
1053 /**
1054 * g_queue_insert_before_link:
1055 * @queue: a #GQueue
1056 * @sibling: (nullable): a #GList link that must be part of @queue, or %NULL to
1057 * push at the tail of the queue.
1058 * @link_: a #GList link to insert which must not be part of any other list.
1059 *
1060 * Inserts @link_ into @queue before @sibling.
1061 *
1062 * @sibling must be part of @queue.
1063 *
1064 * Since: 2.62
1065 */
1066 void
g_queue_insert_before_link(GQueue * queue,GList * sibling,GList * link_)1067 g_queue_insert_before_link (GQueue *queue,
1068 GList *sibling,
1069 GList *link_)
1070 {
1071 g_return_if_fail (queue != NULL);
1072 g_return_if_fail (link_ != NULL);
1073 g_return_if_fail (link_->prev == NULL);
1074 g_return_if_fail (link_->next == NULL);
1075
1076 if G_UNLIKELY (sibling == NULL)
1077 {
1078 /* We don't use g_list_insert_before_link() with a NULL sibling because it
1079 * would be a O(n) operation and we would need to update manually the tail
1080 * pointer.
1081 */
1082 g_queue_push_tail_link (queue, link_);
1083 }
1084 else
1085 {
1086 queue->head = g_list_insert_before_link (queue->head, sibling, link_);
1087 queue->length++;
1088 }
1089 }
1090
1091 /**
1092 * g_queue_insert_after:
1093 * @queue: a #GQueue
1094 * @sibling: (nullable): a #GList link that must be part of @queue, or %NULL to
1095 * push at the head of the queue.
1096 * @data: the data to insert
1097 *
1098 * Inserts @data into @queue after @sibling.
1099 *
1100 * @sibling must be part of @queue. Since GLib 2.44 a %NULL sibling pushes the
1101 * data at the head of the queue.
1102 *
1103 * Since: 2.4
1104 */
1105 void
g_queue_insert_after(GQueue * queue,GList * sibling,gpointer data)1106 g_queue_insert_after (GQueue *queue,
1107 GList *sibling,
1108 gpointer data)
1109 {
1110 g_return_if_fail (queue != NULL);
1111
1112 if (sibling == NULL)
1113 g_queue_push_head (queue, data);
1114 else
1115 g_queue_insert_before (queue, sibling->next, data);
1116 }
1117
1118 /**
1119 * g_queue_insert_after_link:
1120 * @queue: a #GQueue
1121 * @sibling: (nullable): a #GList link that must be part of @queue, or %NULL to
1122 * push at the head of the queue.
1123 * @link_: a #GList link to insert which must not be part of any other list.
1124 *
1125 * Inserts @link_ into @queue after @sibling.
1126 *
1127 * @sibling must be part of @queue.
1128 *
1129 * Since: 2.62
1130 */
1131 void
g_queue_insert_after_link(GQueue * queue,GList * sibling,GList * link_)1132 g_queue_insert_after_link (GQueue *queue,
1133 GList *sibling,
1134 GList *link_)
1135 {
1136 g_return_if_fail (queue != NULL);
1137 g_return_if_fail (link_ != NULL);
1138 g_return_if_fail (link_->prev == NULL);
1139 g_return_if_fail (link_->next == NULL);
1140
1141 if G_UNLIKELY (sibling == NULL)
1142 g_queue_push_head_link (queue, link_);
1143 else
1144 g_queue_insert_before_link (queue, sibling->next, link_);
1145 }
1146
1147 /**
1148 * g_queue_insert_sorted:
1149 * @queue: a #GQueue
1150 * @data: the data to insert
1151 * @func: the #GCompareDataFunc used to compare elements in the queue. It is
1152 * called with two elements of the @queue and @user_data. It should
1153 * return 0 if the elements are equal, a negative value if the first
1154 * element comes before the second, and a positive value if the second
1155 * element comes before the first.
1156 * @user_data: user data passed to @func
1157 *
1158 * Inserts @data into @queue using @func to determine the new position.
1159 *
1160 * Since: 2.4
1161 */
1162 void
g_queue_insert_sorted(GQueue * queue,gpointer data,GCompareDataFunc func,gpointer user_data)1163 g_queue_insert_sorted (GQueue *queue,
1164 gpointer data,
1165 GCompareDataFunc func,
1166 gpointer user_data)
1167 {
1168 GList *list;
1169
1170 g_return_if_fail (queue != NULL);
1171
1172 list = queue->head;
1173 while (list && func (list->data, data, user_data) < 0)
1174 list = list->next;
1175
1176 g_queue_insert_before (queue, list, data);
1177 }
1178