]> Pileus Git - ~andy/gtk/blob - glib/glist.c
Someone has to make SOME backwards incompatible changes sometime. I
[~andy/gtk] / glib / 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 ()
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 ()
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 gint
304 g_list_position (GList     *list,
305                  GList     *link)
306 {
307   gint nth;
308   GList *curlink;
309   for(nth = 0, curlink = list; curlink; curlink = g_list_next(curlink), nth++)
310     {
311         if(curlink == link) return nth;
312     }
313
314   return -1;
315 }
316
317
318 GList*
319 g_list_find (GList    *list,
320              gpointer  data)
321 {
322   while (list)
323     {
324       if (list->data == data)
325         break;
326       list = list->next;
327     }
328   
329   return list;
330 }
331
332 GList*
333 g_list_last (GList *list)
334 {
335   if (list)
336     {
337       while (list->next)
338         list = list->next;
339     }
340   
341   return list;
342 }
343
344 GList*
345 g_list_first (GList *list)
346 {
347   if (list)
348     {
349       while (list->prev)
350         list = list->prev;
351     }
352   
353   return list;
354 }
355
356 guint
357 g_list_length (GList *list)
358 {
359   guint length;
360   
361   length = 0;
362   while (list)
363     {
364       length++;
365       list = list->next;
366     }
367   
368   return length;
369 }
370
371 void
372 g_list_foreach (GList    *list,
373                 GFunc     func,
374                 gpointer  user_data)
375 {
376   while (list)
377     {
378       (*func) (list->data, user_data);
379       list = list->next;
380     }
381 }
382
383
384 GList*
385 g_list_insert_sorted (GList    *list,
386                       gpointer  data,
387                       GCompareFunc  func)
388 {
389   GList *tmp_list = list;
390   GList *new_list;
391   gint cmp;
392   
393   if (!list) 
394     {
395       new_list = g_list_alloc();
396       new_list->data = data;
397       return new_list;
398     }
399   
400   cmp = (*func) (data, tmp_list->data);
401   
402   while ((tmp_list->next) && (cmp > 0))
403     {
404       tmp_list = tmp_list->next;
405       cmp = (*func) (data, tmp_list->data);
406     }
407
408   new_list = g_list_alloc();
409   new_list->data = data;
410
411   if ((!tmp_list->next) && (cmp > 0))
412     {
413       tmp_list->next = new_list;
414       new_list->prev = tmp_list;
415       return list;
416     }
417    
418   if (tmp_list->prev)
419     {
420       tmp_list->prev->next = new_list;
421       new_list->prev = tmp_list->prev;
422     }
423   new_list->next = tmp_list;
424   tmp_list->prev = new_list;
425  
426   if (tmp_list == list)
427     return new_list;
428   else
429     return list;
430 }