LinkedList2.h 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398
  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. * Returns the next node of a given node.
  127. *
  128. * @param node reference node
  129. * @return next node, or NULL if none
  130. */
  131. static LinkedList2Node * LinkedList2Node_Next (LinkedList2Node *node);
  132. /**
  133. * Returns the previous node of a given node.
  134. *
  135. * @param node reference node
  136. * @return previous node, or NULL if none
  137. */
  138. static LinkedList2Node * LinkedList2Node_Prev (LinkedList2Node *node);
  139. /**
  140. * Initializes a linked list iterator.
  141. * The iterator memory must remain available until either of these occurs:
  142. * - the list is no longer needed, or
  143. * - the iterator is freed with {@link LinkedList2Iterator_Free}, or
  144. * - the iterator reaches the end of iteration.
  145. *
  146. * @param it uninitialized iterator to initialize
  147. * @param list the list
  148. * @param dir direction of iteration. Must be 1 (forward) or -1 (backward).
  149. * @param node current position of the iterator. Can be a node in the list
  150. * or NULL for end of iteration.
  151. */
  152. static void LinkedList2Iterator_Init (LinkedList2Iterator *it, LinkedList2 *list, int dir, LinkedList2Node *node);
  153. /**
  154. * Frees a linked list iterator.
  155. *
  156. * @param it iterator to free
  157. */
  158. static void LinkedList2Iterator_Free (LinkedList2Iterator *it);
  159. /**
  160. * Initializes a linked list iterator with forward direction, with the current
  161. * position at the first node (or at the end of iteration if there are no nodes).
  162. * The iterator memory must remain available until either of these occurs:
  163. * - the list is no longer needed, or
  164. * - the iterator is freed with {@link LinkedList2Iterator_Free}, or
  165. * - the iterator reaches the end of iteration.
  166. *
  167. * @param it uninitialized iterator to initialize
  168. * @param list the list
  169. */
  170. static void LinkedList2Iterator_InitForward (LinkedList2Iterator *it, LinkedList2 *list);
  171. /**
  172. * Initializes a linked list iterator with backward direction, with the current
  173. * position at the last node (or at the end of iteration if there are no nodes).
  174. * The iterator memory must remain available until either of these occurs:
  175. * - the list is no longer needed, or
  176. * - the iterator is freed with {@link LinkedList2Iterator_Free}, or
  177. * - the iterator reaches the end of iteration.
  178. *
  179. * @param it uninitialized iterator to initialize
  180. * @param list the list
  181. */
  182. static void LinkedList2Iterator_InitBackward (LinkedList2Iterator *it, LinkedList2 *list);
  183. /**
  184. * Moves the iterator one node forward or backward (depending on its direction), or,
  185. * if it's at the last or first node (depending on the direction), it reaches
  186. * the end of iteration, or, if it's at the end of iteration, it remains there.
  187. * Returns the the previous position.
  188. *
  189. * @param it the iterator
  190. * @return node on the position of iterator before it was (possibly) moved, or NULL
  191. * if it was at the end of iteration
  192. */
  193. static LinkedList2Node * LinkedList2Iterator_Next (LinkedList2Iterator *it);
  194. void LinkedList2_Init (LinkedList2 *list)
  195. {
  196. list->first = NULL;
  197. list->last = NULL;
  198. }
  199. int LinkedList2_IsEmpty (LinkedList2 *list)
  200. {
  201. return (!list->first);
  202. }
  203. LinkedList2Node * LinkedList2_GetFirst (LinkedList2 *list)
  204. {
  205. return (list->first);
  206. }
  207. LinkedList2Node * LinkedList2_GetLast (LinkedList2 *list)
  208. {
  209. return (list->last);
  210. }
  211. void LinkedList2_Prepend (LinkedList2 *list, LinkedList2Node *node)
  212. {
  213. node->p = NULL;
  214. node->n = list->first;
  215. if (list->first) {
  216. list->first->p = node;
  217. } else {
  218. list->last = node;
  219. }
  220. list->first = node;
  221. node->it = NULL;
  222. }
  223. void LinkedList2_Append (LinkedList2 *list, LinkedList2Node *node)
  224. {
  225. node->p = list->last;
  226. node->n = NULL;
  227. if (list->last) {
  228. list->last->n = node;
  229. } else {
  230. list->first = node;
  231. }
  232. list->last = node;
  233. node->it = NULL;
  234. }
  235. void LinkedList2_InsertBefore (LinkedList2 *list, LinkedList2Node *node, LinkedList2Node *target)
  236. {
  237. node->p = target->p;
  238. node->n = target;
  239. if (target->p) {
  240. target->p->n = node;
  241. } else {
  242. list->first = node;
  243. }
  244. target->p = node;
  245. node->it = NULL;
  246. }
  247. void LinkedList2_InsertAfter (LinkedList2 *list, LinkedList2Node *node, LinkedList2Node *target)
  248. {
  249. node->p = target;
  250. node->n = target->n;
  251. if (target->n) {
  252. target->n->p = node;
  253. } else {
  254. list->last = node;
  255. }
  256. target->n = node;
  257. node->it = NULL;
  258. }
  259. void LinkedList2_Remove (LinkedList2 *list, LinkedList2Node *node)
  260. {
  261. // jump iterators
  262. while (node->it) {
  263. LinkedList2Iterator_Next(node->it);
  264. }
  265. // remove from list
  266. if (node->p) {
  267. node->p->n = node->n;
  268. } else {
  269. list->first = node->n;
  270. }
  271. if (node->n) {
  272. node->n->p = node->p;
  273. } else {
  274. list->last = node->p;
  275. }
  276. }
  277. LinkedList2Node * LinkedList2Node_Next (LinkedList2Node *node)
  278. {
  279. return node->n;
  280. }
  281. LinkedList2Node * LinkedList2Node_Prev (LinkedList2Node *node)
  282. {
  283. return node->p;
  284. }
  285. void LinkedList2Iterator_Init (LinkedList2Iterator *it, LinkedList2 *list, int dir, LinkedList2Node *node)
  286. {
  287. ASSERT(dir == 1 || dir == -1)
  288. it->list = list;
  289. it->dir = dir;
  290. it->e = node;
  291. if (it->e) {
  292. // link into node's iterator list
  293. it->pi = NULL;
  294. it->ni = it->e->it;
  295. if (it->e->it) {
  296. it->e->it->pi = it;
  297. }
  298. it->e->it = it;
  299. }
  300. }
  301. void LinkedList2Iterator_Free (LinkedList2Iterator *it)
  302. {
  303. if (it->e) {
  304. // remove from node's iterator list
  305. if (it->ni) {
  306. it->ni->pi = it->pi;
  307. }
  308. if (it->pi) {
  309. it->pi->ni = it->ni;
  310. } else {
  311. it->e->it = it->ni;
  312. }
  313. }
  314. }
  315. void LinkedList2Iterator_InitForward (LinkedList2Iterator *it, LinkedList2 *list)
  316. {
  317. LinkedList2Iterator_Init(it, list, 1, list->first);
  318. }
  319. void LinkedList2Iterator_InitBackward (LinkedList2Iterator *it, LinkedList2 *list)
  320. {
  321. LinkedList2Iterator_Init(it, list, -1, list->last);
  322. }
  323. LinkedList2Node * LinkedList2Iterator_Next (LinkedList2Iterator *it)
  324. {
  325. // remember original entry
  326. LinkedList2Node *orig = it->e;
  327. // jump to next entry
  328. if (it->e) {
  329. // get next entry
  330. LinkedList2Node *next;
  331. switch (it->dir) {
  332. case 1:
  333. next = it->e->n;
  334. break;
  335. case -1:
  336. next = it->e->p;
  337. break;
  338. default:
  339. ASSERT(0);
  340. }
  341. // destroy interator
  342. LinkedList2Iterator_Free(it);
  343. // re-initialize at next entry
  344. LinkedList2Iterator_Init(it, it->list, it->dir, next);
  345. }
  346. // return original entry
  347. return orig;
  348. }
  349. #endif