PageRenderTime 54ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 0ms

/srcs/toolbox/list.c

http://github.com/koanlogic/libu
C | 373 lines | 154 code | 56 blank | 163 comment | 39 complexity | 9f20aed2df7bb5c3b65f2e2448a28b30 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. /*
  2. * Copyright (c) 2005-2012 by KoanLogic s.r.l. - All rights reserved.
  3. */
  4. #include <u/libu_conf.h>
  5. #include <u/libu.h>
  6. #include <toolbox/list.h>
  7. typedef struct u_list_item_s
  8. {
  9. TAILQ_ENTRY(u_list_item_s) np;
  10. void *ptr;
  11. } u_list_item_t;
  12. struct u_list_s
  13. {
  14. TAILQ_HEAD(u_list_head_s, u_list_item_s) head;
  15. size_t count;
  16. };
  17. /**
  18. \defgroup list Lists
  19. \{
  20. The \ref list module implements a linked list. Elements - actually
  21. element pointers - can be appended at the end of an ::u_list_t
  22. object (via ::u_list_add), or inserted at a given position (via
  23. ::u_list_insert). Element can be retrieved and deleted by index
  24. (::u_list_get_n, ::u_list_del_n), and also evicted by direct reference
  25. (::u_list_del). The ::u_list_foreach iterator is provided for safe,
  26. easy and efficient (forward) traversal of list objects.
  27. \note Element pointers are never owned by the ::u_list_t object to
  28. which they are linked. The disposal of the resources (possibly)
  29. allocated on the element is up to the user, e.g. when calling
  30. ::u_list_del_n, use the result-argument \p *pptr to pass the
  31. "real" object to its dtor.
  32. */
  33. /**
  34. * \brief Create a new list object
  35. *
  36. * \param plist the newly created ::u_list_t object as a result argument
  37. *
  38. * \retval 0 on success
  39. * \retval ~0 on failure
  40. */
  41. int u_list_create (u_list_t **plist)
  42. {
  43. u_list_t *list = NULL;
  44. list = u_zalloc(sizeof(u_list_t));
  45. dbg_err_sif (list == NULL);
  46. TAILQ_INIT(&list->head);
  47. *plist = list;
  48. return 0;
  49. err:
  50. if(list)
  51. u_free(list);
  52. return ~0;
  53. }
  54. /**
  55. * \brief Free a list object
  56. *
  57. * Free the supplied ::u_list_t object \p list. Note the list doesn't own
  58. * the pointers in it: the client must free them
  59. *
  60. * \param list the ::u_list_t object that has to be disposed
  61. *
  62. * \return nothing
  63. */
  64. void u_list_free (u_list_t *list)
  65. {
  66. dbg_return_if(list == NULL, );
  67. u_list_clear(list);
  68. u_free(list);
  69. return;
  70. }
  71. /**
  72. * \brief Push an element to the list
  73. *
  74. * Push the supplied pointer \p ptr to the ::u_list_t object \p list
  75. *
  76. * \param list the parent ::u_list_t object (created via ::u_list_create)
  77. * \param ptr the the reference to the element that has to be push'd
  78. *
  79. * \retval 0 on success
  80. * \retval ~0 on failure
  81. */
  82. int u_list_add (u_list_t *list, void *ptr)
  83. {
  84. return u_list_insert(list, ptr, list->count);
  85. }
  86. /**
  87. * \brief Pop an element from the list
  88. *
  89. * Evict the element referenced by \p ptr from the ::u_list_t object \p list
  90. *
  91. * \param list the parent ::u_list_t object (created via ::u_list_create)
  92. * \param ptr reference to the element that has to be evicted
  93. *
  94. * \retval 0 if \p ptr has been successfully removed
  95. * \retval ~0 if \p ptr was not found
  96. */
  97. int u_list_del (u_list_t *list, void *ptr)
  98. {
  99. u_list_item_t *item = NULL;
  100. TAILQ_FOREACH(item, &list->head, np)
  101. {
  102. if(item->ptr == ptr)
  103. {
  104. TAILQ_REMOVE(&list->head, item, np);
  105. list->count--;
  106. u_free(item);
  107. return 0; /* removed */
  108. }
  109. }
  110. return ~0; /* not found */
  111. }
  112. /**
  113. * \brief Count elements in list
  114. *
  115. * Count the number of elements actually present in the supplied ::u_list_t
  116. * object \p list
  117. *
  118. * \param list the ::u_list_t object that has to be queried
  119. *
  120. * \return the number of elements in \p list
  121. */
  122. size_t u_list_count (u_list_t *list)
  123. {
  124. /* a SIGBUS/SIGSEGV is better than returning 0 if list == NULL */
  125. /* NOTE: perhaps we could use ssize_t instead, and return -1 on error */
  126. return list->count;
  127. }
  128. /**
  129. * \brief Get the n-th element in list
  130. *
  131. * Get the element at index position \p n from the ::u_list_t object \p list
  132. *
  133. * \param list an ::u_list_t object
  134. * \param n the index of the element that we are supposed to retrieve
  135. *
  136. * \return the pointer to the n-th element or \c NULL if no element was
  137. * found at index \p n
  138. */
  139. void *u_list_get_n (u_list_t *list, size_t n)
  140. {
  141. u_list_item_t *item = NULL;
  142. dbg_return_if (list == NULL, NULL);
  143. dbg_return_if (n > list->count, NULL);
  144. TAILQ_FOREACH(item, &list->head, np)
  145. {
  146. if(n-- == 0)
  147. return item->ptr;
  148. }
  149. return NULL;
  150. }
  151. /**
  152. * \brief Insert an element at the given position
  153. *
  154. * Insert the supplied element \p ptr into the ::u_list_t object list at
  155. * index \p n
  156. *
  157. * \param list the parent ::u_list_t object (created via ::u_list_create)
  158. * \param ptr the element that has to be push'd
  159. * \param n the position in the list (from zero to ::u_list_count)
  160. *
  161. * \retval 0 on success
  162. * \retval ~0 on failure
  163. */
  164. int u_list_insert (u_list_t *list, void *ptr, size_t n)
  165. {
  166. u_list_item_t *prev, *item = NULL;
  167. dbg_return_if (list == NULL, ~0);
  168. dbg_return_if (n > list->count, ~0);
  169. item = u_zalloc(sizeof(u_list_item_t));
  170. dbg_err_sif (item == NULL);
  171. item->ptr = ptr;
  172. if(n == 0)
  173. {
  174. TAILQ_INSERT_HEAD(&list->head, item, np);
  175. } else if (n == list->count) {
  176. TAILQ_INSERT_TAIL(&list->head, item, np);
  177. } else {
  178. /* find the current n-th elem */
  179. TAILQ_FOREACH(prev, &list->head, np)
  180. {
  181. if(n-- == 0)
  182. break;
  183. }
  184. TAILQ_INSERT_BEFORE(prev, item, np);
  185. }
  186. list->count++;
  187. return 0;
  188. err:
  189. if(item)
  190. u_free(item);
  191. return ~0;
  192. }
  193. /**
  194. * \brief Return the first item of the list and initialize the iterator
  195. *
  196. * Return the first item of the supplied ::u_list_t object and initialize the
  197. * opaque iterator \p it
  198. *
  199. * \param list the ::u_list_t object (created via ::u_list_create)
  200. * \param it opaque iterator object of type \c void**
  201. *
  202. * \return the first item or \c NULL if the list is empty
  203. */
  204. void *u_list_first (u_list_t *list, void **it)
  205. {
  206. u_list_item_t *item;
  207. dbg_return_if (list == NULL, NULL);
  208. item = TAILQ_FIRST(&list->head);
  209. if(it && item)
  210. *it = TAILQ_NEXT(item, np);
  211. else if(it)
  212. *it = NULL;
  213. if(item)
  214. return item->ptr;
  215. return NULL;
  216. }
  217. /**
  218. * \brief Return the next element while iterating over a list
  219. *
  220. * Return the next element while iterating over the supplied ::u_list_t
  221. * object \p list. The \p it iterator must have been already initialized
  222. * via a previous call to ::u_list_first
  223. *
  224. * \param list an ::u_list_t object created via ::u_list_create
  225. * \param it opaque iterator already initialized with ::u_list_first
  226. *
  227. * List iteration example:
  228. * \code
  229. void *it;
  230. my_t *my;
  231. // indifferently one could have used: u_list_foreach (list, my, it) { ... }
  232. for (my = u_list_first(list, &it); my; my = u_list_next(list, &it))
  233. do_something_with(my);
  234. ...
  235. * \endcode
  236. *
  237. * \return the requested item or \c NULL if the last item in list was reached
  238. *
  239. * \see u_list_foreach
  240. * \see u_list_iforeach
  241. */
  242. void *u_list_next (u_list_t *list, void **it)
  243. {
  244. u_list_item_t *item;
  245. dbg_return_if (list == NULL, NULL);
  246. dbg_return_if (it == NULL, NULL);
  247. nop_return_if (*it == NULL, NULL);
  248. item = *it;
  249. if(it && item)
  250. *it = TAILQ_NEXT(item, np);
  251. else if(it)
  252. *it = NULL;
  253. if(item)
  254. return item->ptr;
  255. return NULL;
  256. }
  257. /**
  258. * \brief Delete an element given its position in the list
  259. *
  260. * Delete the element at index \p n from the supplied ::u_list_t object
  261. * \p list and give back the reference to the stored object via the result
  262. * argument \p pptr. At a later stage \c *pptr can be appropriately destroyed.
  263. *
  264. * \param list the parent ::u_list_t object (created via ::u_list_create)
  265. * \param n element position in the list
  266. * \param pptr element reference
  267. *
  268. * \retval 0 if \p ptr has been removed
  269. * \retval ~0 if \p ptr was not found
  270. */
  271. int u_list_del_n (u_list_t *list, size_t n, void **pptr)
  272. {
  273. u_list_item_t *item = NULL;
  274. dbg_return_if (list == NULL, ~0);
  275. dbg_return_if (n >= list->count, ~0);
  276. TAILQ_FOREACH(item, &list->head, np)
  277. {
  278. if(n-- == 0)
  279. break;
  280. }
  281. if(pptr)
  282. *pptr = item->ptr;
  283. TAILQ_REMOVE(&list->head, item, np);
  284. list->count--;
  285. u_free(item);
  286. return 0;
  287. }
  288. /**
  289. * \brief Remove all elements from the list
  290. *
  291. * Remove all elements from the supplied ::u_list_t object \p list. Beware
  292. * that the referenced objects - if any - won't be available anymore and
  293. * could be lost (usually causing memory leaking).
  294. *
  295. * \param list the ::u_list_t object that must be reset
  296. *
  297. * \retval 0 on success
  298. * \retval ~0 on failure
  299. */
  300. int u_list_clear (u_list_t *list)
  301. {
  302. u_list_item_t *item;
  303. dbg_err_if(list == NULL);
  304. while((item = TAILQ_FIRST(&list->head)) != NULL)
  305. {
  306. TAILQ_REMOVE(&list->head, item, np);
  307. u_free(item);
  308. }
  309. return 0;
  310. err:
  311. return ~0;
  312. }
  313. /**
  314. * \}
  315. */