Code

Imported Upstream version 5.5.0
[pkg-collectd.git] / libltdl / slist.c
1 /* slist.c -- generalised singly linked lists
3    Copyright (C) 2000, 2004, 2007, 2008, 2009 Free Software Foundation, Inc.
4    Written by Gary V. Vaughan, 2000
6    NOTE: The canonical source of this file is maintained with the
7    GNU Libtool package.  Report bugs to bug-libtool@gnu.org.
9 GNU Libltdl is free software; you can redistribute it and/or
10 modify it under the terms of the GNU Lesser General Public
11 License as published by the Free Software Foundation; either
12 version 2 of the License, or (at your option) any later version.
14 As a special exception to the GNU Lesser General Public License,
15 if you distribute this file as part of a program or library that
16 is built using GNU Libtool, you may include this file under the
17 same distribution terms that you use for the rest of that program.
19 GNU Libltdl is distributed in the hope that it will be useful,
20 but WITHOUT ANY WARRANTY; without even the implied warranty of
21 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 GNU Lesser General Public License for more details.
24 You should have received a copy of the GNU Lesser General Public
25 License along with GNU Libltdl; see the file COPYING.LIB.  If not, a
26 copy can be downloaded from  http://www.gnu.org/licenses/lgpl.html,
27 or obtained by writing to the Free Software Foundation, Inc.,
28 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29 */
31 #include <assert.h>
33 #include "slist.h"
34 #include <stddef.h>
35 #include <stdlib.h>
37 static SList *  slist_sort_merge    (SList *left, SList *right,
38                                      SListCompare *compare, void *userdata);
41 /* Call DELETE repeatedly on each element of HEAD.
43    CAVEAT: If you call this when HEAD is the start of a list of boxed
44            items, you must remember that each item passed back to your
45            DELETE function will be a boxed item that must be slist_unbox()ed
46            before operating on its contents.
48    e.g. void boxed_delete (void *item) { item_free (slist_unbox (item)); }
49         ...
50           slist = slist_delete (slist, boxed_delete);
51         ...
52 */
53 SList *
54 slist_delete (SList *head, void (*delete_fct) (void *item))
55 {
56   assert (delete_fct);
58   while (head)
59     {
60       SList *next = head->next;
61       (*delete_fct) (head);
62       head = next;
63     }
65   return 0;
66 }
68 /* Call FIND repeatedly with MATCHDATA and each item of *PHEAD, until
69    FIND returns non-NULL, or the list is exhausted.  If a match is found
70    the matching item is destructively removed from *PHEAD, and the value
71    returned by the matching call to FIND is returned.
73    CAVEAT: To avoid memory leaks, unless you already have the address of
74            the stale item, you should probably return that from FIND if
75            it makes a successful match.  Don't forget to slist_unbox()
76            every item in a boxed list before operating on its contents.   */
77 SList *
78 slist_remove (SList **phead, SListCallback *find, void *matchdata)
79 {
80   SList *stale = 0;
81   void *result = 0;
83   assert (find);
85   if (!phead || !*phead)
86     return 0;
88   /* Does the head of the passed list match? */
89   result = (*find) (*phead, matchdata);
90   if (result)
91     {
92       stale = *phead;
93       *phead = stale->next;
94     }
95   /* what about the rest of the elements? */
96   else
97     {
98       SList *head;
99       for (head = *phead; head->next; head = head->next)
100         {
101           result = (*find) (head->next, matchdata);
102           if (result)
103             {
104               stale             = head->next;
105               head->next        = stale->next;
106               break;
107             }
108         }
109     }
111   return (SList *) result;
114 /* Call FIND repeatedly with each element of SLIST and MATCHDATA, until
115    FIND returns non-NULL, or the list is exhausted.  If a match is found
116    the value returned by the matching call to FIND is returned. */
117 void *
118 slist_find (SList *slist, SListCallback *find, void *matchdata)
120   void *result = 0;
122   assert (find);
124   for (; slist; slist = slist->next)
125     {
126       result = (*find) (slist, matchdata);
127       if (result)
128         break;
129     }
131   return result;
134 /* Return a single list, composed by destructively concatenating the
135    items in HEAD and TAIL.  The values of HEAD and TAIL are undefined
136    after calling this function.
138    CAVEAT: Don't mix boxed and unboxed items in a single list.
140    e.g.  slist1 = slist_concat (slist1, slist2);  */
141 SList *
142 slist_concat (SList *head, SList *tail)
144   SList *last;
146   if (!head)
147     {
148       return tail;
149     }
151   last = head;
152   while (last->next)
153     last = last->next;
155   last->next = tail;
157   return head;
160 /* Return a single list, composed by destructively appending all of
161    the items in SLIST to ITEM.  The values of ITEM and SLIST are undefined
162    after calling this function.
164    CAVEAT:  Don't mix boxed and unboxed items in a single list.
166    e.g.  slist1 = slist_cons (slist_box (data), slist1);  */
167 SList *
168 slist_cons (SList *item, SList *slist)
170   if (!item)
171     {
172       return slist;
173     }
175   assert (!item->next);
177   item->next = slist;
178   return item;
181 /* Return a list starting at the second item of SLIST.  */
182 SList *
183 slist_tail (SList *slist)
185   return slist ? slist->next : NULL;
188 /* Return a list starting at the Nth item of SLIST.  If SLIST is less
189    than N items long, NULL is returned.  Just to be confusing, list items
190    are counted from 1, to get the 2nd element of slist:
192    e.g. shared_list = slist_nth (slist, 2);  */
193 SList *
194 slist_nth (SList *slist, size_t n)
196   for (;n > 1 && slist; n--)
197     slist = slist->next;
199   return slist;
202 /* Return the number of items in SLIST.  We start counting from 1, so
203    the length of a list with no items is 0, and so on.  */
204 size_t
205 slist_length (SList *slist)
207   size_t n;
209   for (n = 0; slist; ++n)
210     slist = slist->next;
212   return n;
215 /* Destructively reverse the order of items in SLIST.  The value of SLIST
216    is undefined after calling this function.
218   CAVEAT: You must store the result of this function, or you might not
219           be able to get all the items except the first one back again.
221   e.g.    slist = slist_reverse (slist);  */
222 SList *
223 slist_reverse (SList *slist)
225   SList *result = 0;
226   SList *next;
228   while (slist)
229     {
230       next              = slist->next;
231       slist->next       = result;
232       result            = slist;
233       slist             = next;
234     }
236   return result;
239 /* Call FOREACH once for each item in SLIST, passing both the item and
240    USERDATA on each call. */
241 void *
242 slist_foreach (SList *slist, SListCallback *foreach, void *userdata)
244   void *result = 0;
246   assert (foreach);
248   while (slist)
249     {
250       SList *next = slist->next;
251       result = (*foreach) (slist, userdata);
253       if (result)
254         break;
256       slist = next;
257     }
259   return result;
262 /* Destructively merge the items of two ordered lists LEFT and RIGHT,
263    returning a single sorted list containing the items of both --  Part of
264    the quicksort algorithm.  The values of LEFT and RIGHT are undefined
265    after calling this function.
267    At each iteration, add another item to the merged list by taking the
268    lowest valued item from the head of either LEFT or RIGHT, determined
269    by passing those items and USERDATA to COMPARE.  COMPARE should return
270    less than 0 if the head of LEFT has the lower value, greater than 0 if
271    the head of RIGHT has the lower value, otherwise 0.  */
272 static SList *
273 slist_sort_merge (SList *left, SList *right, SListCompare *compare,
274                   void *userdata)
276   SList merged, *insert;
278   insert = &merged;
280   while (left && right)
281     {
282       if ((*compare) (left, right, userdata) <= 0)
283         {
284           insert = insert->next = left;
285           left = left->next;
286         }
287       else
288         {
289           insert = insert->next = right;
290           right = right->next;
291         }
292     }
294   insert->next = left ? left : right;
296   return merged.next;
299 /* Perform a destructive quicksort on the items in SLIST, by repeatedly
300    calling COMPARE with a pair of items from SLIST along with USERDATA
301    at every iteration.  COMPARE is a function as defined above for
302    slist_sort_merge().  The value of SLIST is undefined after calling
303    this function.
305    e.g.  slist = slist_sort (slist, compare, 0);  */
306 SList *
307 slist_sort (SList *slist, SListCompare *compare, void *userdata)
309   SList *left, *right;
311   if (!slist)
312     return slist;
314   /* Be sure that LEFT and RIGHT never contain the same item.  */
315   left = slist;
316   right = slist->next;
318   if (!right)
319     return left;
321   /* Skip two items with RIGHT and one with SLIST, until RIGHT falls off
322      the end.  SLIST must be about half way along.  */
323   while (right && (right = right->next))
324     {
325       if (!right || !(right = right->next))
326         break;
327       slist = slist->next;
328     }
329   right = slist->next;
330   slist->next = 0;
332   /* Sort LEFT and RIGHT, then merge the two.  */
333   return slist_sort_merge (slist_sort (left, compare, userdata),
334                            slist_sort (right, compare, userdata),
335                            compare, userdata);
339 /* Aside from using the functions above to manage chained structures of
340    any type that has a NEXT pointer as its first field, SLISTs can
341    be comprised of boxed items.  The boxes are chained together in
342    that case, so there is no need for a NEXT field in the item proper.
343    Some care must be taken to slist_box and slist_unbox each item in
344    a boxed list at the appropriate points to avoid leaking the memory
345    used for the boxes.  It us usually a very bad idea to mix boxed and
346    non-boxed items in a single list.  */
348 /* Return a `boxed' freshly mallocated 1 element list containing
349    USERDATA.  */
350 SList *
351 slist_box (const void *userdata)
353   SList *item = (SList *) malloc (sizeof *item);
355   if (item)
356     {
357       item->next     = 0;
358       item->userdata = userdata;
359     }
361   return item;
364 /* Return the contents of a `boxed' ITEM, recycling the box itself.  */
365 void *
366 slist_unbox (SList *item)
368   void *userdata = 0;
370   if (item)
371     {
372       /* Strip the const, because responsibility for this memory
373          passes to the caller on return.  */
374       userdata = (void *) item->userdata;
375       free (item);
376     }
378   return userdata;