lili.c 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309
  1. /*
  2. * Copyright 2010 by egnite GmbH
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without
  7. * modification, are permitted provided that the following conditions
  8. * are met:
  9. *
  10. * 1. Redistributions of source code must retain the above copyright
  11. * notice, this list of conditions and the following disclaimer.
  12. * 2. Redistributions in binary form must reproduce the above copyright
  13. * notice, this list of conditions and the following disclaimer in the
  14. * documentation and/or other materials provided with the distribution.
  15. * 3. Neither the name of the copyright holders nor the names of
  16. * contributors may be used to endorse or promote products derived
  17. * from this software without specific prior written permission.
  18. *
  19. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  22. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
  23. * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  24. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  25. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  26. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  27. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  28. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  29. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  30. * SUCH DAMAGE.
  31. *
  32. * For additional information see http://www.ethernut.de/
  33. */
  34. /*
  35. * \file gorp/list/lili.c
  36. * \brief Linked list main functions.
  37. *
  38. * \verbatim
  39. * $Id$
  40. * \endverbatim
  41. */
  42. #include <memdebug.h>
  43. #include <sys/nutdebug.h>
  44. #include <stdlib.h>
  45. #include <gorp/lili.h>
  46. /*!
  47. * \addtogroup xgLili
  48. */
  49. /*@{*/
  50. /*!
  51. * \brief Compare two items references.
  52. *
  53. * This is the default comparison function used on sorted lists.
  54. *
  55. * \param ref1 Reference of the first item.
  56. * \param ref2 Reference of the second item.
  57. *
  58. * \return An integer less than, equal to, or greater than zero, if the
  59. * value of the first reference is less than, equal, or greater
  60. * than the value of the second, resp.
  61. */
  62. static int LiLiDefaultItemCompare(LILI_ITEMREF ref1, LILI_ITEMREF ref2)
  63. {
  64. return ref1 - ref2;
  65. }
  66. /*
  67. * \brief Add the first node object to an empty list.
  68. *
  69. * \param list Pointer to a list object, obtained from a previous call
  70. * to LiLiCreate().
  71. * \param node Pointer to the node object to add.
  72. */
  73. static void LiLiNodeAddFirst(LILI *list, LILI_NODE *node)
  74. {
  75. /* The list must be empty. */
  76. NUTASSERT(list->lst_head == NULL);
  77. NUTASSERT(list->lst_tail == NULL);
  78. /* Insert the first node. */
  79. list->lst_head = node;
  80. list->lst_tail = node;
  81. node->nod_nxt = NULL;
  82. node->nod_prv = NULL;
  83. }
  84. /*!
  85. * \brief Remove a given node from the list.
  86. *
  87. * Special applications may use this function instead of LiLiPopItem().
  88. *
  89. * The caller must make sure, that this node is a member of the specified
  90. * list. After returning from this function, this pointer is no longer
  91. * usable.
  92. *
  93. * Note, that this call will not destroy the copy of an associated item
  94. * object.
  95. *
  96. * \param list Pointer to a list object, obtained from a previous call
  97. * to LiLiCreate().
  98. * \param node Pointer to the node object to remove. Ignored if NULL.
  99. */
  100. void LiLiRemoveNode(LILI *list, LILI_NODE *node)
  101. {
  102. /* Sanity checks. */
  103. NUTASSERT(list != NULL);
  104. if (node) {
  105. NUTASSERT(list->lst_head != NULL);
  106. NUTASSERT(list->lst_tail != NULL);
  107. /* Remove the forward link. */
  108. if (node->nod_nxt) {
  109. node->nod_nxt->nod_prv = node->nod_prv;
  110. } else {
  111. list->lst_tail = node->nod_prv;
  112. }
  113. /* Remove the backward link. */
  114. if (node->nod_prv) {
  115. node->nod_prv->nod_nxt = node->nod_nxt;
  116. } else {
  117. list->lst_head = node->nod_nxt;
  118. }
  119. free(node);
  120. }
  121. }
  122. /*
  123. * \brief Insert a new node object after a given node.
  124. *
  125. * Note, that list attributes are ignored. Anyway, special applications may
  126. * use this function instead of LiLiPushItem().
  127. *
  128. * \param list Pointer to a list object, obtained from a previous call
  129. * to LiLiCreate().
  130. * \param node Pointer to the node after which the a new node will be
  131. * inserted. If the list is empty, this must be set to NULL.
  132. * \param ref The reference of the item to associate with the new node.
  133. * If a function for creating an item copy has been specified,
  134. * it will be called before inserting the new node.
  135. *
  136. * \return Pointer to the new node object or NULL on errors.
  137. */
  138. LILI_NODE *LiLiInsertItemAfterNode(LILI *list, LILI_NODE *node, LILI_ITEMREF ref)
  139. {
  140. LILI_NODE *newnode;
  141. /* Sanity check. */
  142. NUTASSERT(list != NULL);
  143. newnode = malloc(sizeof(LILI_NODE));
  144. if (newnode) {
  145. /* Optionally create a duplicate of the item. */
  146. newnode->nod_itm = list->lst_icreate ? list->lst_icreate(ref) : ref;
  147. if (node) {
  148. /* A node is provided. The list must have members. */
  149. NUTASSERT(list->lst_head != NULL);
  150. NUTASSERT(list->lst_tail != NULL);
  151. /* Link the new node to the list. */
  152. newnode->nod_nxt = node->nod_nxt;
  153. newnode->nod_prv = node;
  154. node->nod_nxt = newnode;
  155. if (newnode->nod_nxt) {
  156. newnode->nod_nxt->nod_prv = newnode;
  157. }
  158. if (node == list->lst_tail) {
  159. list->lst_tail = newnode;
  160. }
  161. } else {
  162. /* No node provided. Add the first node to an empty list. */
  163. LiLiNodeAddFirst(list, newnode);
  164. }
  165. }
  166. return newnode;
  167. }
  168. /*
  169. * \brief Insert new data node before a given node.
  170. *
  171. * Note, that list attributes are ignored. Anyway, special applications may
  172. * use this function instead of LiLiPushItem().
  173. *
  174. * \param list Pointer to a list object, obtained from a previous call
  175. * to LiLiCreate().
  176. * \param ref The reference of the item to associate with the new node.
  177. * If a function for creating an item copy has been specified,
  178. * it will be called before inserting the new node.
  179. *
  180. * \return Pointer to the new node object or NULL on errors.
  181. */
  182. LILI_NODE *LiLiInsertItemBeforeNode(LILI *list, LILI_NODE *node, LILI_ITEMREF ref)
  183. {
  184. LILI_NODE *newnode;
  185. /* Sanity checks. */
  186. NUTASSERT(list != NULL);
  187. newnode = malloc(sizeof(LILI_NODE));
  188. if (newnode) {
  189. newnode->nod_itm = list->lst_icreate ? list->lst_icreate(ref) : ref;
  190. if (node) {
  191. /* A node is provided. The list must have members. */
  192. NUTASSERT(list->lst_head != NULL);
  193. NUTASSERT(list->lst_tail != NULL);
  194. /* Link the new node to the list. */
  195. newnode->nod_nxt = node;
  196. newnode->nod_prv = node->nod_prv;
  197. if (newnode->nod_prv) {
  198. newnode->nod_prv->nod_nxt = newnode;
  199. }
  200. node->nod_prv = newnode;
  201. if (node == list->lst_head) {
  202. list->lst_head = newnode;
  203. }
  204. } else {
  205. /* No node provided. Add the first node to an empty list. */
  206. LiLiNodeAddFirst(list, newnode);
  207. }
  208. }
  209. return newnode;
  210. }
  211. /*!
  212. * \brief Create a linked list.
  213. *
  214. * \param flags Attribute flags, either LILI_F_LIFO for a last-in
  215. * first-out queue, LILI_F_FIFO for a first-in first-out
  216. * queue, or LILI_F_SORT for a sorted list. Any of them
  217. * may be or'ed with the attribute flag LILI_F_UNIQUE to
  218. * avoid duplicate entries.
  219. * \param icre Pointer to a function, which is called to create an
  220. * item for adding to the list. If NULL, the item reference
  221. * itself is used in the list. See LiLiCreateStringItemCopy().
  222. * \param ides Pointer to a function, which is called to destroy an
  223. * item. Set to NULL, if the item reference is used in the
  224. * list. See LiLiDestroyStringItemCopy().
  225. * \param icmp Pointer to a function, which is called to compare items.
  226. * If NULL, the item reference values are directly compared.
  227. * See LiLiCompareStringItems().
  228. *
  229. * \return Pointer to a list object on success, otherwise a NULL pointer
  230. * is returned.
  231. */
  232. LILI *LiLiCreate(uint8_t flags, LiLiItemCreateFunc icre, LiLiItemDestroyFunc ides, LiLiItemCompareFunc icmp)
  233. {
  234. LILI *list = calloc(1, sizeof(LILI));
  235. if (list) {
  236. list->lst_icreate = icre;
  237. list->lst_idestroy = ides;
  238. if (icmp) {
  239. list->lst_icompare = icmp;
  240. } else {
  241. list->lst_icompare = LiLiDefaultItemCompare;
  242. }
  243. list->lst_flags = flags;
  244. }
  245. return list;
  246. }
  247. /*!
  248. * \brief Remove all items from a list.
  249. *
  250. * This function will not release the list object. Use LiLiDestroy()
  251. * to release the complete list.
  252. *
  253. * \param list Pointer to a list object, obtained from a previous call
  254. * to LiLiCreate().
  255. */
  256. void LiLiClean(LILI *list)
  257. {
  258. LILI_NODE *node;
  259. /* Sanity checks. */
  260. NUTASSERT(list != NULL);
  261. if (list->lst_head) {
  262. while ((node = list->lst_head) != NULL) {
  263. list->lst_head = node->nod_nxt;
  264. if (list->lst_idestroy) {
  265. list->lst_idestroy(LiLiNodeItem(node));
  266. }
  267. free(node);
  268. }
  269. list->lst_tail = NULL;
  270. }
  271. }
  272. /*!
  273. * \brief Destroy a linked list.
  274. *
  275. * This function will remove all nodes, destroy item object copies and
  276. * finally destroy the list object.
  277. *
  278. * \param list Pointer to a list object to destroy, obtained from a
  279. * previous call to LiLiCreate(),
  280. */
  281. void LiLiDestroy(LILI *list)
  282. {
  283. /* Remove all node objects. */
  284. LiLiClean(list);
  285. /* Release the list object. */
  286. free(list);
  287. }
  288. /*@}*/