Add a couple of languages that have LANG_* codes in newest headers, just
[glib.git] / glib / glist.c
blob3935cb1b1169caecedbfc09d797e87b22e1dbdc5
1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
21 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
22 * file for a list of people on the GLib Team. See the ChangeLog
23 * files for a list of changes. These files are distributed with
24 * GLib at ftp://ftp.gtk.org/pub/gtk/.
27 /*
28 * MT safe
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif
35 #include "glib.h"
38 #ifndef DISABLE_MEM_POOLS
39 struct _GAllocator /* from gmem.c */
41 gchar *name;
42 guint16 n_preallocs;
43 guint is_unused : 1;
44 guint type : 4;
45 GAllocator *last;
46 GMemChunk *mem_chunk;
47 GList *free_lists; /* implementation specific */
50 static GAllocator *current_allocator = NULL;
51 G_LOCK_DEFINE_STATIC (current_allocator);
53 /* HOLDS: current_allocator_lock */
54 static void
55 g_list_validate_allocator (GAllocator *allocator)
57 g_return_if_fail (allocator != NULL);
58 g_return_if_fail (allocator->is_unused == TRUE);
60 if (allocator->type != G_ALLOCATOR_LIST)
62 allocator->type = G_ALLOCATOR_LIST;
63 if (allocator->mem_chunk)
65 g_mem_chunk_destroy (allocator->mem_chunk);
66 allocator->mem_chunk = NULL;
70 if (!allocator->mem_chunk)
72 allocator->mem_chunk = g_mem_chunk_new (allocator->name,
73 sizeof (GList),
74 sizeof (GList) * allocator->n_preallocs,
75 G_ALLOC_ONLY);
76 allocator->free_lists = NULL;
79 allocator->is_unused = FALSE;
82 void
83 g_list_push_allocator(GAllocator *allocator)
85 G_LOCK (current_allocator);
86 g_list_validate_allocator (allocator);
87 allocator->last = current_allocator;
88 current_allocator = allocator;
89 G_UNLOCK (current_allocator);
92 void
93 g_list_pop_allocator (void)
95 G_LOCK (current_allocator);
96 if (current_allocator)
98 GAllocator *allocator;
100 allocator = current_allocator;
101 current_allocator = allocator->last;
102 allocator->last = NULL;
103 allocator->is_unused = TRUE;
105 G_UNLOCK (current_allocator);
108 static inline GList*
109 _g_list_alloc (void)
111 GList *list;
113 G_LOCK (current_allocator);
114 if (!current_allocator)
116 GAllocator *allocator = g_allocator_new ("GLib default GList allocator",
117 128);
118 g_list_validate_allocator (allocator);
119 allocator->last = NULL;
120 current_allocator = allocator;
122 if (!current_allocator->free_lists)
124 list = g_chunk_new (GList, current_allocator->mem_chunk);
125 list->data = NULL;
127 else
129 if (current_allocator->free_lists->data)
131 list = current_allocator->free_lists->data;
132 current_allocator->free_lists->data = list->next;
133 list->data = NULL;
135 else
137 list = current_allocator->free_lists;
138 current_allocator->free_lists = list->next;
141 G_UNLOCK (current_allocator);
142 list->next = NULL;
143 list->prev = NULL;
145 return list;
148 GList*
149 g_list_alloc (void)
151 return _g_list_alloc ();
154 void
155 g_list_free (GList *list)
157 if (list)
159 GList *last_node = list;
161 #ifdef ENABLE_GC_FRIENDLY
162 while (last_node->next)
164 last_node->data = NULL;
165 last_node->prev = NULL;
166 last_node = last_node->next;
168 last_node->data = NULL;
169 last_node->prev = NULL;
170 #else /* !ENABLE_GC_FRIENDLY */
171 list->data = list->next;
172 #endif /* ENABLE_GC_FRIENDLY */
174 G_LOCK (current_allocator);
175 last_node->next = current_allocator->free_lists;
176 current_allocator->free_lists = list;
177 G_UNLOCK (current_allocator);
181 static inline void
182 _g_list_free_1 (GList *list)
184 if (list)
186 list->data = NULL;
188 #ifdef ENABLE_GC_FRIENDLY
189 list->prev = NULL;
190 #endif /* ENABLE_GC_FRIENDLY */
192 G_LOCK (current_allocator);
193 list->next = current_allocator->free_lists;
194 current_allocator->free_lists = list;
195 G_UNLOCK (current_allocator);
199 void
200 g_list_free_1 (GList *list)
202 _g_list_free_1 (list);
205 #else /* DISABLE_MEM_POOLS */
207 #define _g_list_alloc g_list_alloc
208 GList*
209 g_list_alloc (void)
211 GList *list;
213 list = g_new0 (GList, 1);
215 return list;
218 void
219 g_list_free (GList *list)
221 GList *last;
223 while (list)
225 last = list;
226 list = list->next;
227 g_free (last);
231 #define _g_list_free_1 g_list_free_1
232 void
233 g_list_free_1 (GList *list)
235 g_free (list);
238 #endif
240 GList*
241 g_list_append (GList *list,
242 gpointer data)
244 GList *new_list;
245 GList *last;
247 new_list = _g_list_alloc ();
248 new_list->data = data;
250 if (list)
252 last = g_list_last (list);
253 /* g_assert (last != NULL); */
254 last->next = new_list;
255 new_list->prev = last;
257 return list;
259 else
260 return new_list;
263 GList*
264 g_list_prepend (GList *list,
265 gpointer data)
267 GList *new_list;
269 new_list = _g_list_alloc ();
270 new_list->data = data;
272 if (list)
274 if (list->prev)
276 list->prev->next = new_list;
277 new_list->prev = list->prev;
279 list->prev = new_list;
280 new_list->next = list;
283 return new_list;
286 GList*
287 g_list_insert (GList *list,
288 gpointer data,
289 gint position)
291 GList *new_list;
292 GList *tmp_list;
294 if (position < 0)
295 return g_list_append (list, data);
296 else if (position == 0)
297 return g_list_prepend (list, data);
299 tmp_list = g_list_nth (list, position);
300 if (!tmp_list)
301 return g_list_append (list, data);
303 new_list = _g_list_alloc ();
304 new_list->data = data;
306 if (tmp_list->prev)
308 tmp_list->prev->next = new_list;
309 new_list->prev = tmp_list->prev;
311 new_list->next = tmp_list;
312 tmp_list->prev = new_list;
314 if (tmp_list == list)
315 return new_list;
316 else
317 return list;
320 GList*
321 g_list_insert_before (GList *list,
322 GList *sibling,
323 gpointer data)
325 if (!list)
327 list = g_list_alloc ();
328 list->data = data;
329 g_return_val_if_fail (sibling == NULL, list);
330 return list;
332 else if (sibling)
334 GList *node;
336 node = g_list_alloc ();
337 node->data = data;
338 if (sibling->prev)
340 node->prev = sibling->prev;
341 node->prev->next = node;
342 node->next = sibling;
343 sibling->prev = node;
344 return list;
346 else
348 node->next = sibling;
349 sibling->prev = node;
350 g_return_val_if_fail (sibling == list, node);
351 return node;
354 else
356 GList *last;
358 last = list;
359 while (last->next)
360 last = last->next;
362 last->next = g_list_alloc ();
363 last->next->data = data;
364 last->next->prev = last;
366 return list;
370 GList *
371 g_list_concat (GList *list1, GList *list2)
373 GList *tmp_list;
375 if (list2)
377 tmp_list = g_list_last (list1);
378 if (tmp_list)
379 tmp_list->next = list2;
380 else
381 list1 = list2;
382 list2->prev = tmp_list;
385 return list1;
388 GList*
389 g_list_remove (GList *list,
390 gconstpointer data)
392 GList *tmp;
394 tmp = list;
395 while (tmp)
397 if (tmp->data != data)
398 tmp = tmp->next;
399 else
401 if (tmp->prev)
402 tmp->prev->next = tmp->next;
403 if (tmp->next)
404 tmp->next->prev = tmp->prev;
406 if (list == tmp)
407 list = list->next;
409 _g_list_free_1 (tmp);
411 break;
414 return list;
417 GList*
418 g_list_remove_all (GList *list,
419 gconstpointer data)
421 GList *tmp = list;
423 while (tmp)
425 if (tmp->data != data)
426 tmp = tmp->next;
427 else
429 GList *next = tmp->next;
431 if (tmp->prev)
432 tmp->prev->next = next;
433 else
434 list = next;
435 if (next)
436 next->prev = tmp->prev;
438 _g_list_free_1 (tmp);
439 tmp = next;
442 return list;
445 static inline GList*
446 _g_list_remove_link (GList *list,
447 GList *link)
449 if (link)
451 if (link->prev)
452 link->prev->next = link->next;
453 if (link->next)
454 link->next->prev = link->prev;
456 if (link == list)
457 list = list->next;
459 link->next = NULL;
460 link->prev = NULL;
463 return list;
466 GList*
467 g_list_remove_link (GList *list,
468 GList *link)
470 return _g_list_remove_link (list, link);
473 GList*
474 g_list_delete_link (GList *list,
475 GList *link)
477 list = _g_list_remove_link (list, link);
478 _g_list_free_1 (link);
480 return list;
483 GList*
484 g_list_copy (GList *list)
486 GList *new_list = NULL;
488 if (list)
490 GList *last;
492 new_list = _g_list_alloc ();
493 new_list->data = list->data;
494 last = new_list;
495 list = list->next;
496 while (list)
498 last->next = _g_list_alloc ();
499 last->next->prev = last;
500 last = last->next;
501 last->data = list->data;
502 list = list->next;
506 return new_list;
509 GList*
510 g_list_reverse (GList *list)
512 GList *last;
514 last = NULL;
515 while (list)
517 last = list;
518 list = last->next;
519 last->next = last->prev;
520 last->prev = list;
523 return last;
526 GList*
527 g_list_nth (GList *list,
528 guint n)
530 while ((n-- > 0) && list)
531 list = list->next;
533 return list;
536 GList*
537 g_list_nth_prev (GList *list,
538 guint n)
540 while ((n-- > 0) && list)
541 list = list->prev;
543 return list;
546 gpointer
547 g_list_nth_data (GList *list,
548 guint n)
550 while ((n-- > 0) && list)
551 list = list->next;
553 return list ? list->data : NULL;
556 GList*
557 g_list_find (GList *list,
558 gconstpointer data)
560 while (list)
562 if (list->data == data)
563 break;
564 list = list->next;
567 return list;
570 GList*
571 g_list_find_custom (GList *list,
572 gconstpointer data,
573 GCompareFunc func)
575 g_return_val_if_fail (func != NULL, list);
577 while (list)
579 if (! func (list->data, data))
580 return list;
581 list = list->next;
584 return NULL;
588 gint
589 g_list_position (GList *list,
590 GList *link)
592 gint i;
594 i = 0;
595 while (list)
597 if (list == link)
598 return i;
599 i++;
600 list = list->next;
603 return -1;
606 gint
607 g_list_index (GList *list,
608 gconstpointer data)
610 gint i;
612 i = 0;
613 while (list)
615 if (list->data == data)
616 return i;
617 i++;
618 list = list->next;
621 return -1;
624 GList*
625 g_list_last (GList *list)
627 if (list)
629 while (list->next)
630 list = list->next;
633 return list;
636 GList*
637 g_list_first (GList *list)
639 if (list)
641 while (list->prev)
642 list = list->prev;
645 return list;
648 guint
649 g_list_length (GList *list)
651 guint length;
653 length = 0;
654 while (list)
656 length++;
657 list = list->next;
660 return length;
663 void
664 g_list_foreach (GList *list,
665 GFunc func,
666 gpointer user_data)
668 while (list)
670 GList *next = list->next;
671 (*func) (list->data, user_data);
672 list = next;
677 GList*
678 g_list_insert_sorted (GList *list,
679 gpointer data,
680 GCompareFunc func)
682 GList *tmp_list = list;
683 GList *new_list;
684 gint cmp;
686 g_return_val_if_fail (func != NULL, list);
688 if (!list)
690 new_list = _g_list_alloc ();
691 new_list->data = data;
692 return new_list;
695 cmp = (*func) (data, tmp_list->data);
697 while ((tmp_list->next) && (cmp > 0))
699 tmp_list = tmp_list->next;
700 cmp = (*func) (data, tmp_list->data);
703 new_list = _g_list_alloc ();
704 new_list->data = data;
706 if ((!tmp_list->next) && (cmp > 0))
708 tmp_list->next = new_list;
709 new_list->prev = tmp_list;
710 return list;
713 if (tmp_list->prev)
715 tmp_list->prev->next = new_list;
716 new_list->prev = tmp_list->prev;
718 new_list->next = tmp_list;
719 tmp_list->prev = new_list;
721 if (tmp_list == list)
722 return new_list;
723 else
724 return list;
727 static GList *
728 g_list_sort_merge (GList *l1,
729 GList *l2,
730 GFunc compare_func,
731 gboolean use_data,
732 gpointer user_data)
734 GList list, *l, *lprev;
735 gint cmp;
737 l = &list;
738 lprev = NULL;
740 while (l1 && l2)
742 if (use_data)
743 cmp = ((GCompareDataFunc) compare_func) (l1->data, l2->data, user_data);
744 else
745 cmp = ((GCompareFunc) compare_func) (l1->data, l2->data);
747 if (cmp <= 0)
749 l->next = l1;
750 l = l->next;
751 l->prev = lprev;
752 lprev = l;
753 l1 = l1->next;
755 else
757 l->next = l2;
758 l = l->next;
759 l->prev = lprev;
760 lprev = l;
761 l2 = l2->next;
764 l->next = l1 ? l1 : l2;
765 l->next->prev = l;
767 return list.next;
770 static GList*
771 g_list_sort_real (GList *list,
772 GFunc compare_func,
773 gboolean use_data,
774 gpointer user_data)
776 GList *l1, *l2;
778 if (!list)
779 return NULL;
780 if (!list->next)
781 return list;
783 l1 = list;
784 l2 = list->next;
786 while ((l2 = l2->next) != NULL)
788 if ((l2 = l2->next) == NULL)
789 break;
790 l1 = l1->next;
792 l2 = l1->next;
793 l1->next = NULL;
795 return g_list_sort_merge (g_list_sort_real (list, compare_func, use_data, user_data),
796 g_list_sort_real (l2, compare_func, use_data, user_data),
797 compare_func,
798 use_data,
799 user_data);
802 GList *
803 g_list_sort (GList *list,
804 GCompareFunc compare_func)
806 return g_list_sort_real (list, (GFunc) compare_func, FALSE, NULL);
810 GList *
811 g_list_sort_with_data (GList *list,
812 GCompareDataFunc compare_func,
813 gpointer user_data)
815 return g_list_sort_real (list, (GFunc) compare_func, TRUE, user_data);
818 static GList*
819 g_list_sort2 (GList *list,
820 GCompareFunc compare_func)
822 GSList *runs = NULL;
823 GList *tmp;
825 /* Degenerate case. */
826 if (!list) return NULL;
828 /* Assume: list = [12,2,4,11,2,4,6,1,1,12]. */
829 for (tmp = list; tmp; )
831 GList *tmp2;
832 for (tmp2 = tmp;
833 tmp2->next && compare_func (tmp2->data, tmp2->next->data) <= 0;
834 tmp2 = tmp2->next)
835 /* Nothing */;
836 runs = g_slist_append (runs, tmp);
837 tmp = tmp2->next;
838 tmp2->next = NULL;
840 /* Now: runs = [[12],[2,4,11],[2,4,6],[1,1,12]]. */
842 while (runs->next)
844 /* We have more than one run. Merge pairwise. */
845 GSList *dst, *src, *dstprev = NULL;
846 dst = src = runs;
847 while (src && src->next)
849 dst->data = g_list_sort_merge (src->data,
850 src->next->data,
851 (GFunc) compare_func,
852 FALSE, NULL);
853 dstprev = dst;
854 dst = dst->next;
855 src = src->next->next;
858 /* If number of runs was odd, just keep the last. */
859 if (src)
861 dst->data = src->data;
862 dstprev = dst;
863 dst = dst->next;
866 dstprev->next = NULL;
867 g_slist_free (dst);
870 /* After 1st loop: runs = [[2,4,11,12],[1,1,2,4,6,12]]. */
871 /* After 2nd loop: runs = [[1,1,2,2,4,4,6,11,12,12]]. */
873 list = runs->data;
874 g_slist_free (runs);
875 return list;