Correct rules for making the win32-related files that are made from
[platform/upstream/glib.git] / gslist.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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.
8  *
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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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.
18  */
19
20 /*
21  * Modified by the GLib Team and others 1997-1999.  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/. 
25  */
26
27 /* 
28  * MT safe
29  */
30
31 #include "glib.h"
32
33
34 struct _GAllocator /* from gmem.c */
35 {
36   gchar         *name;
37   guint16        n_preallocs;
38   guint          is_unused : 1;
39   guint          type : 4;
40   GAllocator    *last;
41   GMemChunk     *mem_chunk;
42   GSList        *free_lists; /* implementation specific */
43 };
44
45 G_LOCK_DEFINE_STATIC (current_allocator);
46 static GAllocator       *current_allocator = NULL;
47
48 /* HOLDS: current_allocator_lock */
49 static void
50 g_slist_validate_allocator (GAllocator *allocator)
51 {
52   g_return_if_fail (allocator != NULL);
53   g_return_if_fail (allocator->is_unused == TRUE);
54
55   if (allocator->type != G_ALLOCATOR_SLIST)
56     {
57       allocator->type = G_ALLOCATOR_SLIST;
58       if (allocator->mem_chunk)
59         {
60           g_mem_chunk_destroy (allocator->mem_chunk);
61           allocator->mem_chunk = NULL;
62         }
63     }
64
65   if (!allocator->mem_chunk)
66     {
67       allocator->mem_chunk = g_mem_chunk_new (allocator->name,
68                                               sizeof (GSList),
69                                               sizeof (GSList) * allocator->n_preallocs,
70                                               G_ALLOC_ONLY);
71       allocator->free_lists = NULL;
72     }
73
74   allocator->is_unused = FALSE;
75 }
76
77 void
78 g_slist_push_allocator (GAllocator *allocator)
79 {
80   G_LOCK (current_allocator);
81   g_slist_validate_allocator (allocator);
82   allocator->last = current_allocator;
83   current_allocator = allocator;
84   G_UNLOCK (current_allocator);
85 }
86
87 void
88 g_slist_pop_allocator (void)
89 {
90   G_LOCK (current_allocator);
91   if (current_allocator)
92     {
93       GAllocator *allocator;
94
95       allocator = current_allocator;
96       current_allocator = allocator->last;
97       allocator->last = NULL;
98       allocator->is_unused = TRUE;
99     }
100   G_UNLOCK (current_allocator);
101 }
102
103 GSList*
104 g_slist_alloc (void)
105 {
106   GSList *list;
107
108   G_LOCK (current_allocator);
109   if (!current_allocator)
110     {
111       GAllocator *allocator = g_allocator_new ("GLib default GSList allocator",
112                                                128);
113       g_slist_validate_allocator (allocator);
114       allocator->last = NULL;
115       current_allocator = allocator; 
116     }
117   if (!current_allocator->free_lists)
118     {
119       list = g_chunk_new (GSList, current_allocator->mem_chunk);
120       list->data = NULL;
121     }
122   else
123     {
124       if (current_allocator->free_lists->data)
125         {
126           list = current_allocator->free_lists->data;
127           current_allocator->free_lists->data = list->next;
128           list->data = NULL;
129         }
130       else
131         {
132           list = current_allocator->free_lists;
133           current_allocator->free_lists = list->next;
134         }
135     }
136   G_UNLOCK (current_allocator);
137   
138   list->next = NULL;
139
140   return list;
141 }
142
143 void
144 g_slist_free (GSList *list)
145 {
146   if (list)
147     {
148       list->data = list->next;
149       G_LOCK (current_allocator);
150       list->next = current_allocator->free_lists;
151       current_allocator->free_lists = list;
152       G_UNLOCK (current_allocator);
153     }
154 }
155
156 void
157 g_slist_free_1 (GSList *list)
158 {
159   if (list)
160     {
161       list->data = NULL;
162       G_LOCK (current_allocator);
163       list->next = current_allocator->free_lists;
164       current_allocator->free_lists = list;
165       G_UNLOCK (current_allocator);
166     }
167 }
168
169 GSList*
170 g_slist_append (GSList   *list,
171                 gpointer  data)
172 {
173   GSList *new_list;
174   GSList *last;
175
176   new_list = g_slist_alloc ();
177   new_list->data = data;
178
179   if (list)
180     {
181       last = g_slist_last (list);
182       /* g_assert (last != NULL); */
183       last->next = new_list;
184
185       return list;
186     }
187   else
188       return new_list;
189 }
190
191 GSList*
192 g_slist_prepend (GSList   *list,
193                  gpointer  data)
194 {
195   GSList *new_list;
196
197   new_list = g_slist_alloc ();
198   new_list->data = data;
199   new_list->next = list;
200
201   return new_list;
202 }
203
204 GSList*
205 g_slist_insert (GSList   *list,
206                 gpointer  data,
207                 gint      position)
208 {
209   GSList *prev_list;
210   GSList *tmp_list;
211   GSList *new_list;
212
213   if (position < 0)
214     return g_slist_append (list, data);
215   else if (position == 0)
216     return g_slist_prepend (list, data);
217
218   new_list = g_slist_alloc ();
219   new_list->data = data;
220
221   if (!list)
222     return new_list;
223
224   prev_list = NULL;
225   tmp_list = list;
226
227   while ((position-- > 0) && tmp_list)
228     {
229       prev_list = tmp_list;
230       tmp_list = tmp_list->next;
231     }
232
233   if (prev_list)
234     {
235       new_list->next = prev_list->next;
236       prev_list->next = new_list;
237     }
238   else
239     {
240       new_list->next = list;
241       list = new_list;
242     }
243
244   return list;
245 }
246
247 GSList *
248 g_slist_concat (GSList *list1, GSList *list2)
249 {
250   if (list2)
251     {
252       if (list1)
253         g_slist_last (list1)->next = list2;
254       else
255         list1 = list2;
256     }
257
258   return list1;
259 }
260
261 GSList*
262 g_slist_remove (GSList   *list,
263                 gpointer  data)
264 {
265   GSList *tmp;
266   GSList *prev;
267
268   prev = NULL;
269   tmp = list;
270
271   while (tmp)
272     {
273       if (tmp->data == data)
274         {
275           if (prev)
276             prev->next = tmp->next;
277           if (list == tmp)
278             list = list->next;
279
280           tmp->next = NULL;
281           g_slist_free (tmp);
282
283           break;
284         }
285
286       prev = tmp;
287       tmp = tmp->next;
288     }
289
290   return list;
291 }
292
293 GSList*
294 g_slist_remove_link (GSList *list,
295                      GSList *link)
296 {
297   GSList *tmp;
298   GSList *prev;
299
300   prev = NULL;
301   tmp = list;
302
303   while (tmp)
304     {
305       if (tmp == link)
306         {
307           if (prev)
308             prev->next = tmp->next;
309           if (list == tmp)
310             list = list->next;
311
312           tmp->next = NULL;
313           break;
314         }
315
316       prev = tmp;
317       tmp = tmp->next;
318     }
319
320   return list;
321 }
322
323 GSList*
324 g_slist_copy (GSList *list)
325 {
326   GSList *new_list = NULL;
327
328   if (list)
329     {
330       GSList *last;
331
332       new_list = g_slist_alloc ();
333       new_list->data = list->data;
334       last = new_list;
335       list = list->next;
336       while (list)
337         {
338           last->next = g_slist_alloc ();
339           last = last->next;
340           last->data = list->data;
341           list = list->next;
342         }
343     }
344
345   return new_list;
346 }
347
348 GSList*
349 g_slist_reverse (GSList *list)
350 {
351   GSList *tmp;
352   GSList *prev;
353   GSList *last;
354
355   last = NULL;
356   prev = NULL;
357
358   while (list)
359     {
360       last = list;
361
362       tmp = list->next;
363       list->next = prev;
364
365       prev = list;
366       list = tmp;
367     }
368
369   return last;
370 }
371
372 GSList*
373 g_slist_nth (GSList *list,
374              guint   n)
375 {
376   while ((n-- > 0) && list)
377     list = list->next;
378
379   return list;
380 }
381
382 gpointer
383 g_slist_nth_data (GSList   *list,
384                   guint     n)
385 {
386   while ((n-- > 0) && list)
387     list = list->next;
388
389   return list ? list->data : NULL;
390 }
391
392 GSList*
393 g_slist_find (GSList   *list,
394               gpointer  data)
395 {
396   while (list)
397     {
398       if (list->data == data)
399         break;
400       list = list->next;
401     }
402
403   return list;
404 }
405
406 GSList*
407 g_slist_find_custom (GSList      *list,
408                      gpointer     data,
409                      GCompareFunc func)
410 {
411   g_return_val_if_fail (func != NULL, list);
412
413   while (list)
414     {
415       if (! func (list->data, data))
416         return list;
417       list = list->next;
418     }
419
420   return NULL;
421 }
422
423 gint
424 g_slist_position (GSList *list,
425                   GSList *link)
426 {
427   gint i;
428
429   i = 0;
430   while (list)
431     {
432       if (list == link)
433         return i;
434       i++;
435       list = list->next;
436     }
437
438   return -1;
439 }
440
441 gint
442 g_slist_index (GSList   *list,
443                gpointer data)
444 {
445   gint i;
446
447   i = 0;
448   while (list)
449     {
450       if (list->data == data)
451         return i;
452       i++;
453       list = list->next;
454     }
455
456   return -1;
457 }
458
459 GSList*
460 g_slist_last (GSList *list)
461 {
462   if (list)
463     {
464       while (list->next)
465         list = list->next;
466     }
467
468   return list;
469 }
470
471 guint
472 g_slist_length (GSList *list)
473 {
474   guint length;
475
476   length = 0;
477   while (list)
478     {
479       length++;
480       list = list->next;
481     }
482
483   return length;
484 }
485
486 void
487 g_slist_foreach (GSList   *list,
488                  GFunc     func,
489                  gpointer  user_data)
490 {
491   while (list)
492     {
493       (*func) (list->data, user_data);
494       list = list->next;
495     }
496 }
497
498 GSList*
499 g_slist_insert_sorted (GSList       *list,
500                        gpointer      data,
501                        GCompareFunc  func)
502 {
503   GSList *tmp_list = list;
504   GSList *prev_list = NULL;
505   GSList *new_list;
506   gint cmp;
507  
508   g_return_val_if_fail (func != NULL, list);
509
510   if (!list)
511     {
512       new_list = g_slist_alloc();
513       new_list->data = data;
514       return new_list;
515     }
516  
517   cmp = (*func) (data, tmp_list->data);
518  
519   while ((tmp_list->next) && (cmp > 0))
520     {
521       prev_list = tmp_list;
522       tmp_list = tmp_list->next;
523       cmp = (*func) (data, tmp_list->data);
524     }
525
526   new_list = g_slist_alloc();
527   new_list->data = data;
528
529   if ((!tmp_list->next) && (cmp > 0))
530     {
531       tmp_list->next = new_list;
532       return list;
533     }
534   
535   if (prev_list)
536     {
537       prev_list->next = new_list;
538       new_list->next = tmp_list;
539       return list;
540     }
541   else
542     {
543       new_list->next = list;
544       return new_list;
545     }
546 }
547
548 static GSList* 
549 g_slist_sort_merge  (GSList      *l1, 
550                      GSList      *l2,
551                      GCompareFunc compare_func)
552 {
553   GSList list, *l;
554
555   l=&list;
556
557   while (l1 && l2)
558     {
559       if (compare_func(l1->data,l2->data) < 0)
560         {
561           l=l->next=l1;
562           l1=l1->next;
563         } 
564       else 
565         {
566           l=l->next=l2;
567           l2=l2->next;
568         }
569     }
570   l->next= l1 ? l1 : l2;
571   
572   return list.next;
573 }
574
575 GSList* 
576 g_slist_sort (GSList       *list,
577               GCompareFunc compare_func)
578 {
579   GSList *l1, *l2;
580
581   if (!list) 
582     return NULL;
583   if (!list->next) 
584     return list;
585
586   l1 = list; 
587   l2 = list->next;
588
589   while ((l2 = l2->next) != NULL)
590     {
591       if ((l2 = l2->next) == NULL) 
592         break;
593       l1=l1->next;
594     }
595   l2 = l1->next; 
596   l1->next = NULL;
597
598   return g_slist_sort_merge (g_slist_sort (list, compare_func),
599                              g_slist_sort (l2,   compare_func),
600                              compare_func);
601 }