LinkedList2.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378
  1. /**
  2. * @file LinkedList2.h
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * This file is part of BadVPN.
  8. *
  9. * BadVPN is free software: you can redistribute it and/or modify
  10. * it under the terms of the GNU General Public License version 2
  11. * as published by the Free Software Foundation.
  12. *
  13. * BadVPN is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along
  19. * with this program; if not, write to the Free Software Foundation, Inc.,
  20. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  21. *
  22. * @section DESCRIPTION
  23. *
  24. * Doubly linked list that support multiple iterations and removing
  25. * aritrary elements during iteration.
  26. */
  27. #ifndef BADVPN_STRUCTURE_LINKEDLIST2_H
  28. #define BADVPN_STRUCTURE_LINKEDLIST2_H
  29. #include <stddef.h>
  30. #include <misc/debug.h>
  31. struct LinkedList2Iterator_t;
  32. /**
  33. * Linked list node.
  34. */
  35. typedef struct LinkedList2Node_t
  36. {
  37. struct LinkedList2Node_t *p;
  38. struct LinkedList2Node_t *n;
  39. struct LinkedList2Iterator_t *it;
  40. } LinkedList2Node;
  41. /**
  42. * Doubly linked list that support multiple iterations and removing
  43. * aritrary elements during iteration.
  44. */
  45. typedef struct
  46. {
  47. LinkedList2Node *first;
  48. LinkedList2Node *last;
  49. } LinkedList2;
  50. /**
  51. * Linked list iterator.
  52. */
  53. typedef struct LinkedList2Iterator_t
  54. {
  55. LinkedList2 *list;
  56. int dir;
  57. struct LinkedList2Node_t *e;
  58. struct LinkedList2Iterator_t *pi;
  59. struct LinkedList2Iterator_t *ni;
  60. } LinkedList2Iterator;
  61. /**
  62. * Initializes the linked list.
  63. *
  64. * @param list list to initialize
  65. */
  66. static void LinkedList2_Init (LinkedList2 *list);
  67. /**
  68. * Determines if the list is empty.
  69. *
  70. * @param list the list
  71. * @return 1 if empty, 0 if not
  72. */
  73. static int LinkedList2_IsEmpty (LinkedList2 *list);
  74. /**
  75. * Returns the first node of the list.
  76. *
  77. * @param list the list
  78. * @return first node of the list, or NULL if the list is empty
  79. */
  80. static LinkedList2Node * LinkedList2_GetFirst (LinkedList2 *list);
  81. /**
  82. * Returns the last node of the list.
  83. *
  84. * @param list the list
  85. * @return last node of the list, or NULL if the list is empty
  86. */
  87. static LinkedList2Node * LinkedList2_GetLast (LinkedList2 *list);
  88. /**
  89. * Inserts a node to the beginning of the list.
  90. *
  91. * @param list the list
  92. * @param node uninitialized node to insert
  93. */
  94. static void LinkedList2_Prepend (LinkedList2 *list, LinkedList2Node *node);
  95. /**
  96. * Inserts a node to the end of the list.
  97. *
  98. * @param list the list
  99. * @param node uninitialized node to insert
  100. */
  101. static void LinkedList2_Append (LinkedList2 *list, LinkedList2Node *node);
  102. /**
  103. * Inserts a node before a given node.
  104. *
  105. * @param list the list
  106. * @param node uninitialized node to insert
  107. * @param target node in the list to insert before
  108. */
  109. static void LinkedList2_InsertBefore (LinkedList2 *list, LinkedList2Node *node, LinkedList2Node *target);
  110. /**
  111. * Inserts a node after 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 after
  116. */
  117. static void LinkedList2_InsertAfter (LinkedList2 *list, LinkedList2Node *node, LinkedList2Node *target);
  118. /**
  119. * Removes a node from the list.
  120. *
  121. * @param list the list
  122. * @param node node to remove
  123. */
  124. static void LinkedList2_Remove (LinkedList2 *list, LinkedList2Node *node);
  125. /**
  126. * Initializes a linked list iterator.
  127. * The iterator memory must remain available until either of these occurs:
  128. * - the list is no longer needed, or
  129. * - the iterator is freed with {@link LinkedList2Iterator_Free}, or
  130. * - the iterator reaches the end of iteration.
  131. *
  132. * @param it uninitialized iterator to initialize
  133. * @param list the list
  134. * @param dir direction of iteration. Must be 1 (forward) or -1 (backward).
  135. * @param node current position of the iterator. Can be a node in the list
  136. * or NULL for end of iteration.
  137. */
  138. static void LinkedList2Iterator_Init (LinkedList2Iterator *it, LinkedList2 *list, int dir, LinkedList2Node *node);
  139. /**
  140. * Frees a linked list iterator.
  141. *
  142. * @param it iterator to free
  143. */
  144. static void LinkedList2Iterator_Free (LinkedList2Iterator *it);
  145. /**
  146. * Initializes a linked list iterator with forward direction, with the current
  147. * position at the first node (or at the end of iteration if there are no nodes).
  148. * The iterator memory must remain available until either of these occurs:
  149. * - the list is no longer needed, or
  150. * - the iterator is freed with {@link LinkedList2Iterator_Free}, or
  151. * - the iterator reaches the end of iteration.
  152. *
  153. * @param it uninitialized iterator to initialize
  154. * @param list the list
  155. */
  156. static void LinkedList2Iterator_InitForward (LinkedList2Iterator *it, LinkedList2 *list);
  157. /**
  158. * Initializes a linked list iterator with backward direction, with the current
  159. * position at the last node (or at the end of iteration if there are no nodes).
  160. * The iterator memory must remain available until either of these occurs:
  161. * - the list is no longer needed, or
  162. * - the iterator is freed with {@link LinkedList2Iterator_Free}, or
  163. * - the iterator reaches the end of iteration.
  164. *
  165. * @param it uninitialized iterator to initialize
  166. * @param list the list
  167. */
  168. static void LinkedList2Iterator_InitBackward (LinkedList2Iterator *it, LinkedList2 *list);
  169. /**
  170. * Moves the iterator one node forward or backward (depending on its direction), or,
  171. * if it's at the last or first node (depending on the direction), it reaches
  172. * the end of iteration, or, if it's at the end of iteration, it remains there.
  173. * Returns the the previous position.
  174. *
  175. * @param it the iterator
  176. * @return node on the position of iterator before it was (possibly) moved, or NULL
  177. * if it was at the end of iteration
  178. */
  179. static LinkedList2Node * LinkedList2Iterator_Next (LinkedList2Iterator *it);
  180. void LinkedList2_Init (LinkedList2 *list)
  181. {
  182. list->first = NULL;
  183. list->last = NULL;
  184. }
  185. int LinkedList2_IsEmpty (LinkedList2 *list)
  186. {
  187. return (!list->first);
  188. }
  189. LinkedList2Node * LinkedList2_GetFirst (LinkedList2 *list)
  190. {
  191. return (list->first);
  192. }
  193. LinkedList2Node * LinkedList2_GetLast (LinkedList2 *list)
  194. {
  195. return (list->last);
  196. }
  197. void LinkedList2_Prepend (LinkedList2 *list, LinkedList2Node *node)
  198. {
  199. node->p = NULL;
  200. node->n = list->first;
  201. if (list->first) {
  202. list->first->p = node;
  203. } else {
  204. list->last = node;
  205. }
  206. list->first = node;
  207. node->it = NULL;
  208. }
  209. void LinkedList2_Append (LinkedList2 *list, LinkedList2Node *node)
  210. {
  211. node->p = list->last;
  212. node->n = NULL;
  213. if (list->last) {
  214. list->last->n = node;
  215. } else {
  216. list->first = node;
  217. }
  218. list->last = node;
  219. node->it = NULL;
  220. }
  221. void LinkedList2_InsertBefore (LinkedList2 *list, LinkedList2Node *node, LinkedList2Node *target)
  222. {
  223. node->p = target->p;
  224. node->n = target;
  225. if (target->p) {
  226. target->p->n = node;
  227. } else {
  228. list->first = node;
  229. }
  230. target->p = node;
  231. node->it = NULL;
  232. }
  233. void LinkedList2_InsertAfter (LinkedList2 *list, LinkedList2Node *node, LinkedList2Node *target)
  234. {
  235. node->p = target;
  236. node->n = target->n;
  237. if (target->n) {
  238. target->n->p = node;
  239. } else {
  240. list->last = node;
  241. }
  242. target->n = node;
  243. node->it = NULL;
  244. }
  245. void LinkedList2_Remove (LinkedList2 *list, LinkedList2Node *node)
  246. {
  247. LinkedList2Iterator *it;
  248. LinkedList2Iterator *next;
  249. // jump iterators
  250. while (node->it) {
  251. LinkedList2Iterator_Next(node->it);
  252. }
  253. // remove from list
  254. if (node->p) {
  255. node->p->n = node->n;
  256. } else {
  257. list->first = node->n;
  258. }
  259. if (node->n) {
  260. node->n->p = node->p;
  261. } else {
  262. list->last = node->p;
  263. }
  264. }
  265. void LinkedList2Iterator_Init (LinkedList2Iterator *it, LinkedList2 *list, int dir, LinkedList2Node *node)
  266. {
  267. ASSERT(dir == 1 || dir == -1)
  268. it->list = list;
  269. it->dir = dir;
  270. it->e = node;
  271. if (!it->e) {
  272. it->pi = NULL;
  273. it->ni = NULL;
  274. } else {
  275. // link into node's iterator list
  276. it->pi = NULL;
  277. it->ni = it->e->it;
  278. if (it->e->it) {
  279. it->e->it->pi = it;
  280. }
  281. it->e->it = it;
  282. }
  283. }
  284. void LinkedList2Iterator_Free (LinkedList2Iterator *it)
  285. {
  286. if (it->e) {
  287. // remove from node's iterator list
  288. if (it->ni) {
  289. it->ni->pi = it->pi;
  290. }
  291. if (it->pi) {
  292. it->pi->ni = it->ni;
  293. } else {
  294. it->e->it = it->ni;
  295. }
  296. }
  297. }
  298. void LinkedList2Iterator_InitForward (LinkedList2Iterator *it, LinkedList2 *list)
  299. {
  300. LinkedList2Iterator_Init(it, list, 1, list->first);
  301. }
  302. void LinkedList2Iterator_InitBackward (LinkedList2Iterator *it, LinkedList2 *list)
  303. {
  304. LinkedList2Iterator_Init(it, list, -1, list->last);
  305. }
  306. LinkedList2Node * LinkedList2Iterator_Next (LinkedList2Iterator *it)
  307. {
  308. // remember original entry
  309. LinkedList2Node *orig = it->e;
  310. // jump to next entry
  311. if (it->e) {
  312. // get next entry
  313. LinkedList2Node *next;
  314. switch (it->dir) {
  315. case 1:
  316. next = it->e->n;
  317. break;
  318. case -1:
  319. next = it->e->p;
  320. break;
  321. default:
  322. ASSERT(0);
  323. }
  324. // destroy interator
  325. LinkedList2Iterator_Free(it);
  326. // re-initialize at next entry
  327. LinkedList2Iterator_Init(it, it->list, it->dir, next);
  328. }
  329. // return original entry
  330. return orig;
  331. }
  332. #endif