LinkedList2.h 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406
  1. /**
  2. * @file LinkedList2.h
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the author nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *
  29. * @section DESCRIPTION
  30. *
  31. * Doubly linked list that support multiple iterations and removing
  32. * aritrary elements during iteration.
  33. */
  34. #ifndef BADVPN_STRUCTURE_LINKEDLIST2_H
  35. #define BADVPN_STRUCTURE_LINKEDLIST2_H
  36. #include <stddef.h>
  37. #include <stdint.h>
  38. #include <misc/debug.h>
  39. struct LinkedList2Iterator_t;
  40. /**
  41. * Linked list node.
  42. */
  43. typedef struct LinkedList2Node_t
  44. {
  45. struct LinkedList2Node_t *p;
  46. struct LinkedList2Node_t *n;
  47. struct LinkedList2Iterator_t *it;
  48. } LinkedList2Node;
  49. /**
  50. * Doubly linked list that support multiple iterations and removing
  51. * aritrary elements during iteration.
  52. */
  53. typedef struct
  54. {
  55. LinkedList2Node *first;
  56. LinkedList2Node *last;
  57. } LinkedList2;
  58. /**
  59. * Linked list iterator.
  60. */
  61. typedef struct LinkedList2Iterator_t
  62. {
  63. LinkedList2 *list;
  64. int8_t dir;
  65. struct LinkedList2Node_t *e;
  66. struct LinkedList2Iterator_t *pi;
  67. struct LinkedList2Iterator_t *ni;
  68. } LinkedList2Iterator;
  69. /**
  70. * Initializes the linked list.
  71. *
  72. * @param list list to initialize
  73. */
  74. static void LinkedList2_Init (LinkedList2 *list);
  75. /**
  76. * Determines if the list is empty.
  77. *
  78. * @param list the list
  79. * @return 1 if empty, 0 if not
  80. */
  81. static int LinkedList2_IsEmpty (LinkedList2 *list);
  82. /**
  83. * Returns the first node of the list.
  84. *
  85. * @param list the list
  86. * @return first node of the list, or NULL if the list is empty
  87. */
  88. static LinkedList2Node * LinkedList2_GetFirst (LinkedList2 *list);
  89. /**
  90. * Returns the last node of the list.
  91. *
  92. * @param list the list
  93. * @return last node of the list, or NULL if the list is empty
  94. */
  95. static LinkedList2Node * LinkedList2_GetLast (LinkedList2 *list);
  96. /**
  97. * Inserts a node to the beginning of the list.
  98. *
  99. * @param list the list
  100. * @param node uninitialized node to insert
  101. */
  102. static void LinkedList2_Prepend (LinkedList2 *list, LinkedList2Node *node);
  103. /**
  104. * Inserts a node to the end of the list.
  105. *
  106. * @param list the list
  107. * @param node uninitialized node to insert
  108. */
  109. static void LinkedList2_Append (LinkedList2 *list, LinkedList2Node *node);
  110. /**
  111. * Inserts a node before a given node.
  112. *
  113. * @param list the list
  114. * @param node uninitialized node to insert
  115. * @param target node in the list to insert before
  116. */
  117. static void LinkedList2_InsertBefore (LinkedList2 *list, LinkedList2Node *node, LinkedList2Node *target);
  118. /**
  119. * Inserts a node after a given node.
  120. *
  121. * @param list the list
  122. * @param node uninitialized node to insert
  123. * @param target node in the list to insert after
  124. */
  125. static void LinkedList2_InsertAfter (LinkedList2 *list, LinkedList2Node *node, LinkedList2Node *target);
  126. /**
  127. * Removes a node from the list.
  128. *
  129. * @param list the list
  130. * @param node node to remove
  131. */
  132. static void LinkedList2_Remove (LinkedList2 *list, LinkedList2Node *node);
  133. /**
  134. * Returns the next node of a given node.
  135. *
  136. * @param node reference node
  137. * @return next node, or NULL if none
  138. */
  139. static LinkedList2Node * LinkedList2Node_Next (LinkedList2Node *node);
  140. /**
  141. * Returns the previous node of a given node.
  142. *
  143. * @param node reference node
  144. * @return previous node, or NULL if none
  145. */
  146. static LinkedList2Node * LinkedList2Node_Prev (LinkedList2Node *node);
  147. /**
  148. * Initializes a linked list iterator.
  149. * The iterator memory must remain available until either of these occurs:
  150. * - the list is no longer needed, or
  151. * - the iterator is freed with {@link LinkedList2Iterator_Free}, or
  152. * - the iterator reaches the end of iteration.
  153. *
  154. * @param it uninitialized iterator to initialize
  155. * @param list the list
  156. * @param dir direction of iteration. Must be 1 (forward) or -1 (backward).
  157. * @param node current position of the iterator. Can be a node in the list
  158. * or NULL for end of iteration.
  159. */
  160. static void LinkedList2Iterator_Init (LinkedList2Iterator *it, LinkedList2 *list, int dir, LinkedList2Node *node);
  161. /**
  162. * Frees a linked list iterator.
  163. *
  164. * @param it iterator to free
  165. */
  166. static void LinkedList2Iterator_Free (LinkedList2Iterator *it);
  167. /**
  168. * Initializes a linked list iterator with forward direction, with the current
  169. * position at the first node (or at the end of iteration if there are no nodes).
  170. * The iterator memory must remain available until either of these occurs:
  171. * - the list is no longer needed, or
  172. * - the iterator is freed with {@link LinkedList2Iterator_Free}, or
  173. * - the iterator reaches the end of iteration.
  174. *
  175. * @param it uninitialized iterator to initialize
  176. * @param list the list
  177. */
  178. static void LinkedList2Iterator_InitForward (LinkedList2Iterator *it, LinkedList2 *list);
  179. /**
  180. * Initializes a linked list iterator with backward direction, with the current
  181. * position at the last node (or at the end of iteration if there are no nodes).
  182. * The iterator memory must remain available until either of these occurs:
  183. * - the list is no longer needed, or
  184. * - the iterator is freed with {@link LinkedList2Iterator_Free}, or
  185. * - the iterator reaches the end of iteration.
  186. *
  187. * @param it uninitialized iterator to initialize
  188. * @param list the list
  189. */
  190. static void LinkedList2Iterator_InitBackward (LinkedList2Iterator *it, LinkedList2 *list);
  191. /**
  192. * Moves the iterator one node forward or backward (depending on its direction), or,
  193. * if it's at the last or first node (depending on the direction), it reaches
  194. * the end of iteration, or, if it's at the end of iteration, it remains there.
  195. * Returns the the previous position.
  196. *
  197. * @param it the iterator
  198. * @return node on the position of iterator before it was (possibly) moved, or NULL
  199. * if it was at the end of iteration
  200. */
  201. static LinkedList2Node * LinkedList2Iterator_Next (LinkedList2Iterator *it);
  202. void LinkedList2_Init (LinkedList2 *list)
  203. {
  204. list->first = NULL;
  205. list->last = NULL;
  206. }
  207. int LinkedList2_IsEmpty (LinkedList2 *list)
  208. {
  209. return (!list->first);
  210. }
  211. LinkedList2Node * LinkedList2_GetFirst (LinkedList2 *list)
  212. {
  213. return (list->first);
  214. }
  215. LinkedList2Node * LinkedList2_GetLast (LinkedList2 *list)
  216. {
  217. return (list->last);
  218. }
  219. void LinkedList2_Prepend (LinkedList2 *list, LinkedList2Node *node)
  220. {
  221. node->p = NULL;
  222. node->n = list->first;
  223. if (list->first) {
  224. list->first->p = node;
  225. } else {
  226. list->last = node;
  227. }
  228. list->first = node;
  229. node->it = NULL;
  230. }
  231. void LinkedList2_Append (LinkedList2 *list, LinkedList2Node *node)
  232. {
  233. node->p = list->last;
  234. node->n = NULL;
  235. if (list->last) {
  236. list->last->n = node;
  237. } else {
  238. list->first = node;
  239. }
  240. list->last = node;
  241. node->it = NULL;
  242. }
  243. void LinkedList2_InsertBefore (LinkedList2 *list, LinkedList2Node *node, LinkedList2Node *target)
  244. {
  245. node->p = target->p;
  246. node->n = target;
  247. if (target->p) {
  248. target->p->n = node;
  249. } else {
  250. list->first = node;
  251. }
  252. target->p = node;
  253. node->it = NULL;
  254. }
  255. void LinkedList2_InsertAfter (LinkedList2 *list, LinkedList2Node *node, LinkedList2Node *target)
  256. {
  257. node->p = target;
  258. node->n = target->n;
  259. if (target->n) {
  260. target->n->p = node;
  261. } else {
  262. list->last = node;
  263. }
  264. target->n = node;
  265. node->it = NULL;
  266. }
  267. void LinkedList2_Remove (LinkedList2 *list, LinkedList2Node *node)
  268. {
  269. // jump iterators
  270. while (node->it) {
  271. LinkedList2Iterator_Next(node->it);
  272. }
  273. // remove from list
  274. if (node->p) {
  275. node->p->n = node->n;
  276. } else {
  277. list->first = node->n;
  278. }
  279. if (node->n) {
  280. node->n->p = node->p;
  281. } else {
  282. list->last = node->p;
  283. }
  284. }
  285. LinkedList2Node * LinkedList2Node_Next (LinkedList2Node *node)
  286. {
  287. return node->n;
  288. }
  289. LinkedList2Node * LinkedList2Node_Prev (LinkedList2Node *node)
  290. {
  291. return node->p;
  292. }
  293. void LinkedList2Iterator_Init (LinkedList2Iterator *it, LinkedList2 *list, int dir, LinkedList2Node *node)
  294. {
  295. ASSERT(dir == 1 || dir == -1)
  296. it->list = list;
  297. it->dir = dir;
  298. it->e = node;
  299. if (it->e) {
  300. // link into node's iterator list
  301. it->pi = NULL;
  302. it->ni = it->e->it;
  303. if (it->e->it) {
  304. it->e->it->pi = it;
  305. }
  306. it->e->it = it;
  307. }
  308. }
  309. void LinkedList2Iterator_Free (LinkedList2Iterator *it)
  310. {
  311. if (it->e) {
  312. // remove from node's iterator list
  313. if (it->ni) {
  314. it->ni->pi = it->pi;
  315. }
  316. if (it->pi) {
  317. it->pi->ni = it->ni;
  318. } else {
  319. it->e->it = it->ni;
  320. }
  321. }
  322. }
  323. void LinkedList2Iterator_InitForward (LinkedList2Iterator *it, LinkedList2 *list)
  324. {
  325. LinkedList2Iterator_Init(it, list, 1, list->first);
  326. }
  327. void LinkedList2Iterator_InitBackward (LinkedList2Iterator *it, LinkedList2 *list)
  328. {
  329. LinkedList2Iterator_Init(it, list, -1, list->last);
  330. }
  331. LinkedList2Node * LinkedList2Iterator_Next (LinkedList2Iterator *it)
  332. {
  333. // remember original entry
  334. LinkedList2Node *orig = it->e;
  335. // jump to next entry
  336. if (it->e) {
  337. // get next entry
  338. LinkedList2Node *next;
  339. switch (it->dir) {
  340. case 1:
  341. next = it->e->n;
  342. break;
  343. case -1:
  344. next = it->e->p;
  345. break;
  346. default:
  347. ASSERT(0);
  348. }
  349. // destroy interator
  350. LinkedList2Iterator_Free(it);
  351. // re-initialize at next entry
  352. LinkedList2Iterator_Init(it, it->list, it->dir, next);
  353. }
  354. // return original entry
  355. return orig;
  356. }
  357. #endif