doubly_linked_list.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. /*!
  2. Temelia - Doubly Linked List implementation source file.
  3. Copyright (C) 2008 Ceata (http://ceata.org/proiecte/temelia).
  4. @author Dascalu Laurentiu, Macovei Alexandru
  5. This program is free software; you can redistribute it and
  6. modify it under the terms of the GNU General Public License
  7. as published by the Free Software Foundation; either version 3
  8. of the License, or (at your option) any later version.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU General Public License for more details.
  13. You should have received a copy of the GNU General Public License
  14. along with this program; if not, write to the Free Software
  15. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  16. */
  17. #include "include/doubly_linked_list.h"
  18. #include "include/common.h"
  19. #include "include/list_common.h"
  20. #include <stdlib.h>
  21. struct _doubly_linked_list_t
  22. {
  23. struct _doubly_linked_list_iterator_t *begin;
  24. struct _doubly_linked_list_iterator_t *end;
  25. int size;
  26. };
  27. static void _doubly_linked_list_reverse_aux(doubly_linked_list_iterator_t it);
  28. doubly_linked_list_t doubly_linked_list_new(void)
  29. {
  30. doubly_linked_list_t list;
  31. LIST_NEW(doubly_linked_list_t, list);
  32. return list;
  33. }
  34. doubly_linked_list_t doubly_linked_list_clone(doubly_linked_list_t list,
  35. void *(*clone)(void *key, void *context), void *context)
  36. {
  37. doubly_linked_list_t clone_list;
  38. doubly_linked_list_iterator_t it;
  39. LIST_CLONE(doubly_linked_list, list, it, clone_list, clone, context);
  40. return clone_list;
  41. }
  42. void doubly_linked_list_delete(doubly_linked_list_t list)
  43. {
  44. doubly_linked_list_iterator_t crt, prc;
  45. LIST_DELETE(list, crt, prc, doubly_linked_list_iterator);
  46. }
  47. int doubly_linked_list_is_empty(doubly_linked_list_t list)
  48. {
  49. _ASSERT(list, ==, NULL, NULL_POINTER, -1);
  50. return list->size == 0;
  51. }
  52. void *doubly_linked_list_get_front(doubly_linked_list_t list)
  53. {
  54. _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
  55. _ASSERT(list->size, <=, 0, INVALID_INPUT, NULL);
  56. return doubly_linked_list_iterator_get_key(list->begin);
  57. }
  58. void *doubly_linked_list_get_back(doubly_linked_list_t list)
  59. {
  60. _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
  61. _ASSERT(list->size, <=, 0, INVALID_INPUT, NULL);
  62. return doubly_linked_list_iterator_get_key(list->end);
  63. }
  64. doubly_linked_list_iterator_t doubly_linked_list_get_begin(
  65. doubly_linked_list_t list)
  66. {
  67. _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
  68. return list->begin;
  69. }
  70. void doubly_linked_list_set_begin(doubly_linked_list_t list,
  71. doubly_linked_list_iterator_t begin)
  72. {
  73. _ASSERT(list, ==, NULL, NULL_POINTER,);
  74. list->begin = begin;
  75. }
  76. doubly_linked_list_iterator_t doubly_linked_list_get_end(
  77. doubly_linked_list_t list)
  78. {
  79. _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
  80. return list->end;
  81. }
  82. void doubly_linked_list_set_end(doubly_linked_list_t list,
  83. doubly_linked_list_iterator_t end)
  84. {
  85. _ASSERT(list, ==, NULL, NULL_POINTER,);
  86. list->end = end;
  87. }
  88. int doubly_linked_list_get_size(doubly_linked_list_t list)
  89. {
  90. _ASSERT(list, ==, NULL, NULL_POINTER, -1);
  91. return list->size;
  92. }
  93. void doubly_linked_list_set_size(doubly_linked_list_t list, int size)
  94. {
  95. _ASSERT(list, ==, NULL, NULL_POINTER,);
  96. list->size = size;
  97. }
  98. int doubly_linked_list_check(doubly_linked_list_t list,
  99. doubly_linked_list_iterator_t p)
  100. {
  101. doubly_linked_list_iterator_t it_left, it_right;
  102. _ASSERT(list, ==, NULL, NULL_POINTER, -1);
  103. _ASSERT(p, ==, NULL, NULL_POINTER, -1);
  104. for (it_left = list->begin, it_right = list->end; it_left != it_right;)
  105. {
  106. it_left = doubly_linked_list_iterator_get_next(it_left);
  107. it_right = doubly_linked_list_iterator_get_prev(it_right);
  108. }
  109. if (it_left == it_right)
  110. return 1;
  111. return 0;
  112. }
  113. doubly_linked_list_iterator_t doubly_linked_list_get_iterator_at(
  114. doubly_linked_list_t list, int position)
  115. {
  116. doubly_linked_list_iterator_t it;
  117. int i;
  118. _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
  119. _ASSERT(position, <, 0, INVALID_INPUT, NULL);
  120. _ASSERT(position, >=, list->size, INVALID_INPUT, NULL);
  121. it = NULL;
  122. // If position is in the first half, then move from beginning to it.
  123. if (position < list->size / 2)
  124. for (i = 0, it = list->begin; i < position && it != NULL; i++, it
  125. = doubly_linked_list_iterator_get_next(it))
  126. ;
  127. // Else, move from the end to it. Although the complexity is the same with
  128. // the search from beginning in any case, O(n), the constant is not the same.
  129. else
  130. for (i = list->size - 1, it = list->end; i > position && it != NULL; i--, it
  131. = doubly_linked_list_iterator_get_prev(it))
  132. ;
  133. return it;
  134. }
  135. void *doubly_linked_list_get_key_at(doubly_linked_list_t list, int position)
  136. {
  137. doubly_linked_list_iterator_t it = doubly_linked_list_get_iterator_at(list,
  138. position);
  139. if (it)
  140. return doubly_linked_list_iterator_get_key(it);
  141. return NULL;
  142. }
  143. void doubly_linked_list_set_key_at(doubly_linked_list_t list, int position,
  144. void *new_key)
  145. {
  146. doubly_linked_list_iterator_t it = doubly_linked_list_get_iterator_at(list,
  147. position);
  148. if (it)
  149. doubly_linked_list_iterator_set_key(it, new_key);
  150. }
  151. doubly_linked_list_iterator_t doubly_linked_list_search_key(
  152. doubly_linked_list_t list, void *key, int compare(void *x, void *y,
  153. void *context), void *context)
  154. {
  155. doubly_linked_list_iterator_t it_left, it_right;
  156. for (it_left = list->begin, it_right = list->end; it_left != it_right;)
  157. {
  158. if (!compare(doubly_linked_list_iterator_get_key(it_left), key, context))
  159. return it_left;
  160. if (!compare(doubly_linked_list_iterator_get_key(it_right), key,
  161. context))
  162. return it_right;
  163. it_left = doubly_linked_list_iterator_get_next(it_left);
  164. it_right = doubly_linked_list_iterator_get_prev(it_right);
  165. }
  166. return NULL;
  167. }
  168. int doubly_linked_list_search_iterator(doubly_linked_list_t list,
  169. doubly_linked_list_iterator_t it)
  170. {
  171. int i_left, i_right;
  172. doubly_linked_list_iterator_t it_left, it_right;
  173. _ASSERT(list, ==, NULL, NULL_POINTER, -1);
  174. for (it_left = list->begin, it_right = list->end, i_left = 0, i_right
  175. = list->size - 1; it_left != it_right;)
  176. {
  177. if (it_left == it)
  178. return i_left;
  179. if (it_right == it)
  180. return i_right;
  181. it_left = doubly_linked_list_iterator_get_next(it_left);
  182. it_right = doubly_linked_list_iterator_get_prev(it_right);
  183. }
  184. return -1;
  185. }
  186. void doubly_linked_list_remove_iterator(doubly_linked_list_t list,
  187. doubly_linked_list_iterator_t it, int delete_iterator)
  188. {
  189. doubly_linked_list_iterator_t aux;
  190. _ASSERT(list, ==, NULL, NULL_POINTER,);
  191. _ASSERT(it, ==, NULL, NULL_POINTER,);
  192. _ASSERT(list->size, ==, 0, EMPTY,);
  193. if (it == list->begin)
  194. {
  195. list->begin = doubly_linked_list_iterator_get_next(list->begin);
  196. doubly_linked_list_iterator_set_prev(list->begin, NULL);
  197. }
  198. else if (it == list->end)
  199. {
  200. aux = doubly_linked_list_iterator_get_prev(list->end);
  201. doubly_linked_list_iterator_set_next(aux, NULL);
  202. list->end = aux;
  203. }
  204. else
  205. {
  206. aux = doubly_linked_list_iterator_get_prev(it);
  207. doubly_linked_list_iterator_set_next(aux,
  208. doubly_linked_list_iterator_get_next(
  209. doubly_linked_list_iterator_get_next(aux)));
  210. doubly_linked_list_iterator_set_prev(
  211. doubly_linked_list_iterator_get_next(aux), aux);
  212. }
  213. list->size--;
  214. if (delete_iterator)
  215. _delete(it);
  216. }
  217. doubly_linked_list_iterator_t doubly_linked_list_remove_key(
  218. doubly_linked_list_t list, void *key, int compare(void *x, void *y,
  219. void *context), void *context, int free)
  220. {
  221. doubly_linked_list_iterator_t it = doubly_linked_list_search_key(list, key,
  222. compare, context);
  223. if (it)
  224. {
  225. doubly_linked_list_remove_iterator(list, it, free);
  226. if (free)
  227. return NULL;
  228. return it;
  229. }
  230. return NULL;
  231. }
  232. void doubly_linked_list_insert_before(doubly_linked_list_t list,
  233. doubly_linked_list_iterator_t it, void *key)
  234. {
  235. doubly_linked_list_iterator_t new_node;
  236. _ASSERT(list, ==, NULL, NULL_POINTER,);
  237. new_node = doubly_linked_list_iterator_new(key, NULL, NULL);
  238. if (list->size == 0)
  239. {
  240. if (it == NULL)
  241. list->begin = list->end = new_node;
  242. else
  243. {
  244. doubly_linked_list_iterator_delete(new_node);
  245. _ASSERT(NULL, ==, NULL, INVALID_INPUT,);
  246. }
  247. }
  248. else if (it == list->begin)
  249. {
  250. doubly_linked_list_iterator_set_next(new_node, it);
  251. doubly_linked_list_iterator_set_prev(it, new_node);
  252. list->begin = new_node;
  253. }
  254. else if (it == NULL)
  255. {
  256. doubly_linked_list_iterator_set_prev(new_node, list->end);
  257. doubly_linked_list_iterator_set_next(list->end, new_node);
  258. list->end = new_node;
  259. }
  260. else
  261. {
  262. doubly_linked_list_iterator_join(doubly_linked_list_iterator_get_prev(
  263. it), new_node, it);
  264. if (list->size == 1)
  265. list->begin = new_node;
  266. }
  267. list->size++;
  268. }
  269. void doubly_linked_list_insert_after(doubly_linked_list_t list,
  270. doubly_linked_list_iterator_t it, void *key)
  271. {
  272. doubly_linked_list_iterator_t new_node;
  273. _ASSERT(list, ==, NULL, NULL_POINTER,);
  274. new_node = doubly_linked_list_iterator_new(key, NULL, NULL);
  275. _ASSERT(new_node, ==, NULL, NULL_POINTER,);
  276. if (list->size == 0)
  277. {
  278. if (it == NULL)
  279. list->begin = list->end = new_node;
  280. else
  281. {
  282. doubly_linked_list_iterator_delete(new_node);
  283. return;
  284. }
  285. }
  286. else if (it == list->end)
  287. {
  288. doubly_linked_list_iterator_set_next(it, new_node);
  289. doubly_linked_list_iterator_set_prev(new_node, it);
  290. list->end = new_node;
  291. }
  292. else if (it == NULL)
  293. {
  294. doubly_linked_list_iterator_set_prev(list->begin, new_node);
  295. doubly_linked_list_iterator_set_next(new_node, list->begin);
  296. list->begin = new_node;
  297. }
  298. else
  299. {
  300. doubly_linked_list_iterator_join(it, new_node,
  301. doubly_linked_list_iterator_get_next(it));
  302. if (list->size == 1)
  303. list->end = new_node;
  304. }
  305. list->size++;
  306. }
  307. void doubly_linked_list_push_front(doubly_linked_list_t list, void *key)
  308. {
  309. _ASSERT(list, ==, NULL, NULL_POINTER,);
  310. doubly_linked_list_insert_before(list, list->begin, key);
  311. }
  312. void doubly_linked_list_push_back(doubly_linked_list_t list, void *key)
  313. {
  314. doubly_linked_list_iterator_t new_node;
  315. _ASSERT(list, ==, NULL, NULL_POINTER,);
  316. new_node = doubly_linked_list_iterator_new(key, NULL, NULL);
  317. _ASSERT(new_node, ==, NULL, NULL_POINTER,);
  318. if (list->size == 0)
  319. {
  320. list->begin = list->end = new_node;
  321. list->size = 1;
  322. return;
  323. }
  324. doubly_linked_list_iterator_join(list->end, new_node, NULL);
  325. list->end = new_node;
  326. list->size++;
  327. }
  328. void doubly_linked_list_pop_front(doubly_linked_list_t list)
  329. {
  330. doubly_linked_list_iterator_t aux;
  331. _ASSERT(list, ==, NULL, NULL_POINTER,);
  332. _ASSERT(list->size, <=, 0, INVALID_INPUT,);
  333. aux = list->begin;
  334. if (list->size == 1)
  335. list->begin = list->end = NULL;
  336. else
  337. {
  338. list->begin = doubly_linked_list_iterator_get_next(list->begin);
  339. doubly_linked_list_iterator_set_prev(list->begin, NULL);
  340. }
  341. _delete(aux);
  342. list->size--;
  343. }
  344. void doubly_linked_list_pop_back(doubly_linked_list_t list)
  345. {
  346. doubly_linked_list_iterator_t aux;
  347. _ASSERT(list, ==, NULL, NULL_POINTER,);
  348. _ASSERT(list->size, <=, 0, INVALID_INPUT,);
  349. aux = list->end;
  350. if (list->size == 1)
  351. list->begin = list->end = NULL;
  352. else
  353. {
  354. list->end = doubly_linked_list_iterator_get_prev(list->end);
  355. doubly_linked_list_iterator_set_next(list->end, NULL);
  356. }
  357. _delete(aux);
  358. list->size--;
  359. }
  360. void doubly_linked_list_iterate(doubly_linked_list_t list, void key_handler(
  361. void *x, void *context), void *context, int order)
  362. {
  363. doubly_linked_list_iterator_t p;
  364. _ASSERT(list, ==, NULL, NULL_POINTER,);
  365. _ASSERT(key_handler, ==, NULL, NULL_POINTER,);
  366. if (order == 1)
  367. for (p = list->begin; p != NULL; p
  368. = doubly_linked_list_iterator_get_next(p))
  369. key_handler(doubly_linked_list_iterator_get_key(p), context);
  370. else if (order == -1)
  371. for (p = list->end; p != NULL; p
  372. = doubly_linked_list_iterator_get_prev(p))
  373. key_handler(doubly_linked_list_iterator_get_key(p), context);
  374. else
  375. temelia_errno = INVALID_INPUT;
  376. }
  377. void doubly_linked_list_sort(doubly_linked_list_t list, int compare(void *x,
  378. void *y, void *context), void *context)
  379. {
  380. void *aux;
  381. doubly_linked_list_iterator_t it;
  382. LIST_SORT(list, it, aux, compare, context, doubly_linked_list_iterator);
  383. }
  384. doubly_linked_list_t doubly_linked_list_merge(doubly_linked_list_t list1,
  385. doubly_linked_list_t list2,
  386. int compare(void *x, void *y, void *context), void *context)
  387. {
  388. doubly_linked_list_t L3;
  389. doubly_linked_list_iterator_t it1, it2;
  390. void *key1, *key2;
  391. _ASSERT(list1, ==, NULL, NULL_POINTER, NULL);
  392. _ASSERT(list2, ==, NULL, NULL_POINTER, NULL);
  393. _ASSERT(compare, ==, NULL, NULL_POINTER, NULL);
  394. L3 = doubly_linked_list_new();
  395. it1 = list1->begin;
  396. it2 = list2->begin;
  397. LIST_MERGE(L3, it1, it2, key1, key2, doubly_linked_list, compare, context);
  398. return L3;
  399. }
  400. void doubly_linked_list_reverse(doubly_linked_list_t list)
  401. {
  402. void *aux;
  403. _ASSERT(list, ==, NULL, NULL_POINTER,);
  404. _doubly_linked_list_reverse_aux(list->begin);
  405. /*
  406. * Swaps "begin" with "end" for a consistent reverse;
  407. * also sets "end's" next iterator pointer to NULL
  408. */
  409. aux = list->begin;
  410. list->begin = list->end;
  411. list->end = aux;
  412. doubly_linked_list_iterator_set_next(list->end, NULL);
  413. doubly_linked_list_iterator_set_prev(list->begin, NULL);
  414. }
  415. void doubly_linked_list_spice(doubly_linked_list_t list1,
  416. doubly_linked_list_t list2, doubly_linked_list_iterator_t it)
  417. {
  418. doubly_linked_list_iterator_t next_node;
  419. _ASSERT(list1, ==, NULL, NULL_POINTER,);
  420. _ASSERT(list2, ==, NULL, NULL_POINTER,);
  421. if (it == NULL)
  422. {
  423. /*
  424. * => list2 -> list1
  425. */
  426. if (list1->end == NULL || list1->begin == list1->end)
  427. list1->end = list2->end;
  428. doubly_linked_list_iterator_join(list2->end, list1->begin,
  429. doubly_linked_list_iterator_get_next(list1->begin));
  430. list1->begin = list2->begin;
  431. }
  432. else if (list1->size > 0)
  433. {
  434. if (it == list1->end)
  435. {
  436. doubly_linked_list_iterator_join(list1->end, list2->begin,
  437. doubly_linked_list_iterator_get_next(list2->begin));
  438. list1->end = list2->end;
  439. }
  440. else
  441. {
  442. // Finally, we can use the given iterator :-)
  443. next_node = doubly_linked_list_iterator_get_next(it);
  444. _ASSERT(next_node, ==, NULL, NULL_POINTER,);
  445. doubly_linked_list_iterator_join(it, list2->begin,
  446. doubly_linked_list_iterator_get_next(list2->begin));
  447. doubly_linked_list_iterator_join(
  448. doubly_linked_list_iterator_get_prev(list2->end),
  449. list2->end, next_node);
  450. }
  451. }
  452. else if (list1->size == 0)
  453. {
  454. // Simply copies the two pointers
  455. list1->begin = list2->begin;
  456. list1->end = list2->end;
  457. }
  458. list1->size += list2->size;
  459. _delete(list2);
  460. }
  461. static void _doubly_linked_list_reverse_aux(doubly_linked_list_iterator_t it)
  462. {
  463. static doubly_linked_list_iterator_t _aux;
  464. if (it == NULL)
  465. return;
  466. _doubly_linked_list_reverse_aux(doubly_linked_list_iterator_get_next(it));
  467. _aux = doubly_linked_list_iterator_get_next(it);
  468. doubly_linked_list_iterator_set_next(_aux, it);
  469. doubly_linked_list_iterator_set_prev(it, _aux);
  470. }