slist.c 9.6 KB

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