#include <glib.h> not <glib/glib.h>
[platform/upstream/glib.git] / glist.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 #include "glib.h"
20
21
22 typedef struct _GRealListAllocator GRealListAllocator;
23
24 struct _GRealListAllocator
25 {
26   GMemChunk *list_mem_chunk;
27   GList     *free_list;
28 };
29
30
31 static GRealListAllocator *default_allocator = NULL;
32 static GRealListAllocator *current_allocator = NULL;
33
34
35 GListAllocator*
36 g_list_allocator_new (void)
37 {
38   GRealListAllocator* allocator = g_new (GRealListAllocator, 1);
39   
40   allocator->list_mem_chunk = NULL;
41   allocator->free_list = NULL;
42   
43   return (GListAllocator*) allocator;
44 }
45
46 void
47 g_list_allocator_free (GListAllocator* fallocator)
48 {
49   GRealListAllocator* allocator = (GRealListAllocator *) fallocator;
50   
51   if (allocator && allocator->list_mem_chunk)
52     g_mem_chunk_destroy (allocator->list_mem_chunk);
53   if (allocator)
54     g_free (allocator);
55 }
56
57 GListAllocator*
58 g_list_set_allocator (GListAllocator* fallocator)
59 {
60   GRealListAllocator* allocator = (GRealListAllocator *) fallocator;
61   GRealListAllocator* old_allocator = current_allocator;
62   
63   if (allocator)
64     current_allocator = allocator;
65   else
66     {
67       if (!default_allocator)
68         default_allocator = (GRealListAllocator*) g_list_allocator_new ();
69       current_allocator = default_allocator;
70     }
71   
72   if (!current_allocator->list_mem_chunk)
73     current_allocator->list_mem_chunk = g_mem_chunk_new ("list mem chunk",
74                                                          sizeof (GList),
75                                                          1024,
76                                                          G_ALLOC_ONLY);
77   
78   return (GListAllocator*) (old_allocator == default_allocator ? NULL : old_allocator);
79 }
80
81
82 GList*
83 g_list_alloc (void)
84 {
85   GList *new_list;
86   
87   g_list_set_allocator (NULL);
88   if (current_allocator->free_list)
89     {
90       new_list = current_allocator->free_list;
91       current_allocator->free_list = current_allocator->free_list->next;
92     }
93   else
94     {
95       new_list = g_chunk_new (GList, current_allocator->list_mem_chunk);
96     }
97   
98   new_list->data = NULL;
99   new_list->next = NULL;
100   new_list->prev = NULL;
101   
102   return new_list;
103 }
104
105 void
106 g_list_free (GList *list)
107 {
108   GList *last;
109   
110   if (list)
111     {
112       last = g_list_last (list);
113       last->next = current_allocator->free_list;
114       current_allocator->free_list = list;
115     }
116 }
117
118 void
119 g_list_free_1 (GList *list)
120 {
121   if (list)
122     {
123       list->next = current_allocator->free_list;
124       current_allocator->free_list = list;
125     }
126 }
127
128 GList*
129 g_list_append (GList    *list,
130                gpointer  data)
131 {
132   GList *new_list;
133   GList *last;
134   
135   new_list = g_list_alloc ();
136   new_list->data = data;
137   
138   if (list)
139     {
140       last = g_list_last (list);
141       /* g_assert (last != NULL); */
142       last->next = new_list;
143       new_list->prev = last;
144
145       return list;
146     }
147   else
148     return new_list;
149 }
150
151 GList*
152 g_list_prepend (GList    *list,
153                 gpointer  data)
154 {
155   GList *new_list;
156   
157   new_list = g_list_alloc ();
158   new_list->data = data;
159   
160   if (list)
161     {
162       if (list->prev)
163         {
164           list->prev->next = new_list;
165           new_list->prev = list->prev;
166         }
167       list->prev = new_list;
168       new_list->next = list;
169     }
170   
171   return new_list;
172 }
173
174 GList*
175 g_list_insert (GList    *list,
176                gpointer  data,
177                gint      position)
178 {
179   GList *new_list;
180   GList *tmp_list;
181   
182   if (position < 0)
183     return g_list_append (list, data);
184   else if (position == 0)
185     return g_list_prepend (list, data);
186   
187   tmp_list = g_list_nth (list, position);
188   if (!tmp_list)
189     return g_list_append (list, data);
190   
191   new_list = g_list_alloc ();
192   new_list->data = data;
193   
194   if (tmp_list->prev)
195     {
196       tmp_list->prev->next = new_list;
197       new_list->prev = tmp_list->prev;
198     }
199   new_list->next = tmp_list;
200   tmp_list->prev = new_list;
201   
202   if (tmp_list == list)
203     return new_list;
204   else
205     return list;
206 }
207
208 GList *
209 g_list_concat (GList *list1, GList *list2)
210 {
211   GList *tmp_list;
212   
213   if (list2)
214     {
215       tmp_list = g_list_last (list1);
216       if (tmp_list)
217         tmp_list->next = list2;
218       else
219         list1 = list2;
220       list2->prev = tmp_list;
221     }
222   
223   return list1;
224 }
225
226 GList*
227 g_list_remove (GList    *list,
228                gpointer  data)
229 {
230   GList *tmp;
231   
232   tmp = list;
233   while (tmp)
234     {
235       if (tmp->data != data)
236         tmp = tmp->next;
237       else
238         {
239           if (tmp->prev)
240             tmp->prev->next = tmp->next;
241           if (tmp->next)
242             tmp->next->prev = tmp->prev;
243           
244           if (list == tmp)
245             list = list->next;
246           
247           g_list_free_1 (tmp);
248           
249           break;
250         }
251     }
252   return list;
253 }
254
255 GList*
256 g_list_remove_link (GList *list,
257                     GList *link)
258 {
259   if (link)
260     {
261       if (link->prev)
262         link->prev->next = link->next;
263       if (link->next)
264         link->next->prev = link->prev;
265       
266       if (link == list)
267         list = list->next;
268       
269       link->next = NULL;
270       link->prev = NULL;
271     }
272   
273   return list;
274 }
275
276 GList*
277 g_list_reverse (GList *list)
278 {
279   GList *last;
280   
281   last = NULL;
282   while (list)
283     {
284       last = list;
285       list = last->next;
286       last->next = last->prev;
287       last->prev = list;
288     }
289   
290   return last;
291 }
292
293 GList*
294 g_list_nth (GList *list,
295             guint  n)
296 {
297   while ((n-- > 0) && list)
298     list = list->next;
299   
300   return list;
301 }
302
303 gpointer
304 g_list_nth_data (GList     *list,
305                  guint      n)
306 {
307   while ((n-- > 0) && list)
308     list = list->next;
309   
310   return list ? list->data : NULL;
311 }
312
313 GList*
314 g_list_find (GList    *list,
315              gpointer  data)
316 {
317   while (list)
318     {
319       if (list->data == data)
320         break;
321       list = list->next;
322     }
323   
324   return list;
325 }
326
327 GList*
328 g_list_find_custom (GList       *list,
329                     gpointer     data,
330                     GCompareFunc func)
331 {
332   g_return_val_if_fail (func != NULL, list);
333
334   while (list)
335     {
336       if (! func (list->data, data))
337         return list;
338       list = list->next;
339     }
340
341   return NULL;
342 }
343
344
345 gint
346 g_list_position (GList *list,
347                  GList *link)
348 {
349   gint i;
350
351   i = 0;
352   while (list)
353     {
354       if (list == link)
355         return i;
356       i++;
357       list = list->next;
358     }
359
360   return -1;
361 }
362
363 gint
364 g_list_index (GList   *list,
365               gpointer data)
366 {
367   gint i;
368
369   i = 0;
370   while (list)
371     {
372       if (list->data == data)
373         return i;
374       i++;
375       list = list->next;
376     }
377
378   return -1;
379 }
380
381 GList*
382 g_list_last (GList *list)
383 {
384   if (list)
385     {
386       while (list->next)
387         list = list->next;
388     }
389   
390   return list;
391 }
392
393 GList*
394 g_list_first (GList *list)
395 {
396   if (list)
397     {
398       while (list->prev)
399         list = list->prev;
400     }
401   
402   return list;
403 }
404
405 guint
406 g_list_length (GList *list)
407 {
408   guint length;
409   
410   length = 0;
411   while (list)
412     {
413       length++;
414       list = list->next;
415     }
416   
417   return length;
418 }
419
420 void
421 g_list_foreach (GList    *list,
422                 GFunc     func,
423                 gpointer  user_data)
424 {
425   while (list)
426     {
427       (*func) (list->data, user_data);
428       list = list->next;
429     }
430 }
431
432
433 GList*
434 g_list_insert_sorted (GList        *list,
435                       gpointer      data,
436                       GCompareFunc  func)
437 {
438   GList *tmp_list = list;
439   GList *new_list;
440   gint cmp;
441
442   g_return_val_if_fail (func != NULL, list);
443   
444   if (!list) 
445     {
446       new_list = g_list_alloc();
447       new_list->data = data;
448       return new_list;
449     }
450   
451   cmp = (*func) (data, tmp_list->data);
452   
453   while ((tmp_list->next) && (cmp > 0))
454     {
455       tmp_list = tmp_list->next;
456       cmp = (*func) (data, tmp_list->data);
457     }
458
459   new_list = g_list_alloc();
460   new_list->data = data;
461
462   if ((!tmp_list->next) && (cmp > 0))
463     {
464       tmp_list->next = new_list;
465       new_list->prev = tmp_list;
466       return list;
467     }
468    
469   if (tmp_list->prev)
470     {
471       tmp_list->prev->next = new_list;
472       new_list->prev = tmp_list->prev;
473     }
474   new_list->next = tmp_list;
475   tmp_list->prev = new_list;
476  
477   if (tmp_list == list)
478     return new_list;
479   else
480     return list;
481 }