linked_list.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552
  1. /*!
  2. Temelia - Linked list implementation source file.
  3. Copyright (C) 2008, 2009 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/linked_list.h"
  18. #include "include/common.h"
  19. #include "include/list_common.h"
  20. #include <stdlib.h>
  21. struct _linked_list_t
  22. {
  23. /*! reference to the first node in the list */
  24. struct _linked_list_iterator_t *begin;
  25. /*! reference to the last node in the list */
  26. struct _linked_list_iterator_t *end;
  27. /*! list's size */
  28. int size;
  29. };
  30. /* Auxiliary recursive function used by the linked_list_print function if value == -1 . */
  31. static void _linked_list_iterate_aux(linked_list_iterator_t it,
  32. void key_handler(void *, void *context), void *context);
  33. static void _linked_list_reverse_aux(linked_list_iterator_t it);
  34. linked_list_t linked_list_new(void)
  35. {
  36. linked_list_t list;
  37. LIST_NEW(linked_list_t, list);
  38. return list;
  39. }
  40. void linked_list_delete(linked_list_t list)
  41. {
  42. linked_list_iterator_t crt, prc;
  43. LIST_DELETE(list, crt, prc, linked_list_iterator);
  44. }
  45. linked_list_t linked_list_clone(linked_list_t list, void *(*clone)(void *key,
  46. void *context), void *context)
  47. {
  48. linked_list_t clone_list;
  49. linked_list_iterator_t it;
  50. LIST_CLONE(linked_list, list, it, clone_list, clone, context);
  51. return clone_list;
  52. }
  53. int linked_list_is_empty(linked_list_t list)
  54. {
  55. _ASSERT(list, ==, NULL, NULL_POINTER, -1);
  56. return list->size == 0;
  57. }
  58. void *linked_list_get_front(linked_list_t list)
  59. {
  60. _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
  61. _ASSERT(list->size, ==, 0, INVALID_INPUT, NULL);
  62. return linked_list_iterator_get_key(list->begin);
  63. }
  64. void *linked_list_get_back(linked_list_t list)
  65. {
  66. _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
  67. _ASSERT(list->size, ==, 0, INVALID_INPUT, NULL);
  68. return linked_list_iterator_get_key(list->end);
  69. }
  70. linked_list_iterator_t linked_list_get_begin(linked_list_t list)
  71. {
  72. _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
  73. return list->begin;
  74. }
  75. void linked_list_set_begin(linked_list_t list, linked_list_iterator_t begin)
  76. {
  77. _ASSERT(list, ==, NULL, NULL_POINTER,);
  78. list->begin = begin;
  79. }
  80. linked_list_iterator_t linked_list_get_end(linked_list_t list)
  81. {
  82. _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
  83. return list->end;
  84. }
  85. void linked_list_set_end(linked_list_t list, linked_list_iterator_t end)
  86. {
  87. _ASSERT(list, ==, NULL, NULL_POINTER,);
  88. list->end = end;
  89. }
  90. int linked_list_get_size(linked_list_t list)
  91. {
  92. _ASSERT(list, ==, NULL, NULL_POINTER, -1);
  93. return list->size;
  94. }
  95. void linked_list_set_size(linked_list_t list, int size)
  96. {
  97. _ASSERT(list, ==, NULL, NULL_POINTER,);
  98. list->size = size;
  99. }
  100. int linked_list_check(linked_list_t list, linked_list_iterator_t p)
  101. {
  102. linked_list_iterator_t it;
  103. for (it = list->begin; it != NULL; it = linked_list_iterator_get_next(it))
  104. if (it == p)
  105. return 1;
  106. return 0;
  107. }
  108. linked_list_iterator_t linked_list_iterator_get_prev(linked_list_t list,
  109. linked_list_iterator_t p)
  110. {
  111. linked_list_iterator_t it;
  112. _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
  113. if (p == list->begin)
  114. return NULL;
  115. for (it = list->begin;; it = linked_list_iterator_get_next(it))
  116. if (linked_list_iterator_get_next(it) == p)
  117. return it;
  118. return NULL;
  119. }
  120. linked_list_iterator_t linked_list_get_iterator_at(linked_list_t list,
  121. int position)
  122. {
  123. linked_list_iterator_t it;
  124. int i;
  125. _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
  126. _ASSERT(position, <, 0, INVALID_INPUT, NULL);
  127. _ASSERT(position, >=, list->size, INVALID_INPUT, NULL);
  128. for (i = 0, it = list->begin; i < position && it != NULL; i++, it
  129. = linked_list_iterator_get_next(it))
  130. ;
  131. return it;
  132. }
  133. void *linked_list_get_key_at(linked_list_t list, int position)
  134. {
  135. linked_list_iterator_t it = linked_list_get_iterator_at(list, position);
  136. if (it)
  137. return linked_list_iterator_get_key(it);
  138. return NULL;
  139. }
  140. void linked_list_set_key_at(linked_list_t list, int position, void *new_key)
  141. {
  142. linked_list_iterator_t it = linked_list_get_iterator_at(list, position);
  143. if (it)
  144. linked_list_iterator_set_key(it, new_key);
  145. }
  146. linked_list_iterator_t linked_list_search_key(linked_list_t list, void *key,
  147. int compare(void *x, void *y, void *context), void *context)
  148. {
  149. linked_list_iterator_t it;
  150. _ASSERT(list, ==, NULL, NULL_POINTER, NULL);
  151. _ASSERT(compare, ==, NULL, NULL_POINTER, NULL);
  152. for (it = list->begin; it != NULL; it = linked_list_iterator_get_next(it))
  153. if (!compare(linked_list_iterator_get_key(it), key, context))
  154. return it;
  155. return NULL;
  156. }
  157. int linked_list_search_iterator(linked_list_t list, linked_list_iterator_t it)
  158. {
  159. int i;
  160. linked_list_iterator_t it_search;
  161. _ASSERT(list, ==, NULL, NULL_POINTER, -1);
  162. for (it_search = list->begin, i = 0; it_search; it_search
  163. = linked_list_iterator_get_next(it_search), i++)
  164. if (it_search == it)
  165. return i;
  166. return -1;
  167. }
  168. void linked_list_remove_iterator(linked_list_t list, linked_list_iterator_t it,
  169. int free)
  170. {
  171. linked_list_iterator_t aux;
  172. _ASSERT(list, ==, NULL, NULL_POINTER,);
  173. _ASSERT(it, ==, NULL, NULL_POINTER,);
  174. _ASSERT(list->size, ==, 0, EMPTY,);
  175. if (list->size == 1)
  176. {
  177. if (list->begin == it && list->end == it)
  178. list->begin = list->end = NULL;
  179. else
  180. _ASSERT(1, ==, 1, INVALID_INPUT,);
  181. }
  182. else
  183. {
  184. if (it == list->begin)
  185. list->begin = linked_list_iterator_get_next(list->begin);
  186. else if (it == list->end)
  187. {
  188. for (aux = list->begin; linked_list_iterator_get_next(aux) != it; aux
  189. = linked_list_iterator_get_next(aux))
  190. ;
  191. linked_list_iterator_set_next(aux, NULL);
  192. list->end = aux;
  193. }
  194. else
  195. {
  196. for (aux = list->begin; linked_list_iterator_get_next(aux) != it; aux
  197. = linked_list_iterator_get_next(aux))
  198. ;
  199. if (aux)
  200. linked_list_iterator_set_next(aux,
  201. linked_list_iterator_get_next(
  202. linked_list_iterator_get_next(aux)));
  203. else
  204. _ASSERT(1, ==, 1, INVALID_INPUT,);
  205. }
  206. }
  207. list->size--;
  208. if (free)
  209. _delete(it);
  210. }
  211. linked_list_iterator_t linked_list_remove_key(linked_list_t list, void *key,
  212. int compare(void *x, void *y, void *context), void *context, int free)
  213. {
  214. linked_list_iterator_t it = linked_list_search_key(list, key, compare,
  215. context);
  216. if (it)
  217. {
  218. linked_list_remove_iterator(list, it, free);
  219. if (free)
  220. return NULL;
  221. return it;
  222. }
  223. return NULL;
  224. }
  225. void linked_list_insert_after(linked_list_t list, linked_list_iterator_t it,
  226. void *key)
  227. {
  228. _ASSERT(list, ==, NULL, NULL_POINTER,);
  229. /*
  230. * Inserting after NULL iterator is equivalent
  231. * with inserting before list's begin iterator.
  232. */
  233. if (it == NULL)
  234. linked_list_insert_before(list, list->begin, key);
  235. else
  236. {
  237. linked_list_iterator_join(it, linked_list_iterator_new(key, NULL),
  238. linked_list_iterator_get_next(it));
  239. if (it == list->end)
  240. list->end = linked_list_iterator_get_next(list->end);
  241. list->size++;
  242. }
  243. }
  244. void linked_list_insert_before(linked_list_t list, linked_list_iterator_t it,
  245. void *key)
  246. {
  247. linked_list_iterator_t new_node;
  248. _ASSERT(list, ==, NULL, NULL_POINTER,);
  249. new_node = linked_list_iterator_new(key, NULL);
  250. if (list->size == 0)
  251. {
  252. if (it == NULL)
  253. list->begin = list->end = new_node;
  254. else
  255. {
  256. linked_list_iterator_delete(new_node);
  257. _ASSERT(NULL, ==, NULL, INVALID_INPUT,);
  258. }
  259. }
  260. else if (it == list->begin)
  261. {
  262. linked_list_iterator_set_next(new_node, it);
  263. list->begin = new_node;
  264. }
  265. else if (it == NULL)
  266. {
  267. linked_list_iterator_set_next(list->end, new_node);
  268. list->end = new_node;
  269. }
  270. else
  271. {
  272. linked_list_iterator_join(linked_list_iterator_get_prev(list, it),
  273. new_node, it);
  274. if (list->size == 1)
  275. list->begin = new_node;
  276. }
  277. list->size++;
  278. }
  279. void linked_list_push_front(linked_list_t list, void *key)
  280. {
  281. linked_list_iterator_t new_node;
  282. _ASSERT(list, ==, NULL, NULL_POINTER,);
  283. new_node = linked_list_iterator_new(key, list->begin);
  284. if (list->size == 0)
  285. list->end = list->begin = new_node;
  286. else
  287. list->begin = new_node;
  288. list->size++;
  289. }
  290. void linked_list_push_back(linked_list_t list, void *key)
  291. {
  292. linked_list_iterator_t new_node;
  293. _ASSERT(list, ==, NULL, NULL_POINTER,);
  294. new_node = linked_list_iterator_new(key, NULL);
  295. if (list->size == 0)
  296. list->end = list->begin = new_node;
  297. else
  298. {
  299. linked_list_iterator_set_next(list->end, new_node);
  300. list->end = new_node;
  301. }
  302. list->size++;
  303. }
  304. void linked_list_pop_front(linked_list_t list)
  305. {
  306. linked_list_iterator_t aux;
  307. _ASSERT(list, ==, NULL, NULL_POINTER,);
  308. _ASSERT(list->size, <=, 0, INVALID_INPUT,);
  309. aux = list->begin;
  310. list->begin = linked_list_iterator_get_next(list->begin);
  311. list->size--;
  312. if (list->size == 0)
  313. list->end = NULL;
  314. _delete(aux);
  315. }
  316. void linked_list_pop_back(linked_list_t list)
  317. {
  318. linked_list_iterator_t it, aux;
  319. _ASSERT(list, ==, NULL, NULL_POINTER,);
  320. _ASSERT(list->size, <=, 0, INVALID_INPUT,);
  321. aux = list->end;
  322. if (list->size == 1)
  323. list->begin = list->end = NULL;
  324. else
  325. {
  326. for (it = list->begin; linked_list_iterator_get_next(it) != list->end; it
  327. = linked_list_iterator_get_next(it))
  328. ;
  329. list->end = it;
  330. }
  331. _delete(aux);
  332. list->size--;
  333. }
  334. void linked_list_iterate(linked_list_t list, void key_handler(void *x,
  335. void *context), void *context, int order)
  336. {
  337. linked_list_iterator_t p;
  338. _ASSERT(list, ==, NULL, NULL_POINTER,);
  339. _ASSERT(key_handler, ==, NULL, NULL_POINTER,);
  340. if (order == 1)
  341. for (p = list->begin; p != NULL; p = linked_list_iterator_get_next(p))
  342. key_handler(linked_list_iterator_get_key(p), context);
  343. else if (order == -1)
  344. _linked_list_iterate_aux(list->begin, key_handler, context);
  345. else
  346. temelia_errno = INVALID_INPUT;
  347. }
  348. void linked_list_sort(linked_list_t list, int compare(void *x, void *y,
  349. void *context), void *context)
  350. {
  351. void *aux;
  352. linked_list_iterator_t it;
  353. LIST_SORT(list, it, aux, compare, context, linked_list_iterator);
  354. }
  355. linked_list_t linked_list_merge(linked_list_t L1, linked_list_t L2,
  356. int compare(void *x, void *y, void *context), void *context)
  357. {
  358. linked_list_t L3;
  359. linked_list_iterator_t it1, it2;
  360. void *key1, *key2;
  361. _ASSERT(L1, ==, NULL, NULL_POINTER, NULL);
  362. _ASSERT(L2, ==, NULL, NULL_POINTER, NULL);
  363. _ASSERT(compare, ==, NULL, NULL_POINTER, NULL);
  364. L3 = linked_list_new();
  365. it1 = L1->begin;
  366. it2 = L2->begin;
  367. LIST_MERGE(L3, it1, it2, key1, key2, linked_list, compare, context);
  368. return L3;
  369. }
  370. void linked_list_reverse(linked_list_t list)
  371. {
  372. void *aux;
  373. _ASSERT(list, ==, NULL, NULL_POINTER,);
  374. _linked_list_reverse_aux(list->begin);
  375. /*
  376. * Swaps "begin" with "end" for a consistent reverse;
  377. * also sets "end's" next iterator pointer to NULL
  378. */
  379. aux = list->begin;
  380. list->begin = list->end;
  381. list->end = aux;
  382. linked_list_iterator_set_next(list->end, NULL);
  383. }
  384. void linked_list_spice(linked_list_t list1, linked_list_t list2,
  385. linked_list_iterator_t it)
  386. {
  387. linked_list_iterator_t next_node;
  388. _ASSERT(list1, ==, NULL, NULL_POINTER,);
  389. _ASSERT(list2, ==, NULL, NULL_POINTER,);
  390. if (it == NULL)
  391. {
  392. /*
  393. * => list2 -> list1
  394. */
  395. if (list1->end == NULL || list1->begin == list1->end)
  396. list1->end = list2->end;
  397. linked_list_iterator_set_next(list2->end, list1->begin);
  398. list1->begin = list2->begin;
  399. }
  400. else if (list1->size > 0)
  401. {
  402. if (it == list1->end)
  403. {
  404. linked_list_iterator_set_next(list1->end, list2->begin);
  405. list1->end = list2->end;
  406. }
  407. else
  408. {
  409. // Finally, we can use the given iterator :-)
  410. next_node = linked_list_iterator_get_next(it);
  411. _ASSERT(next_node, ==, NULL, NULL_POINTER,);
  412. linked_list_iterator_set_next(it, list2->begin);
  413. linked_list_iterator_set_next(list2->end, next_node);
  414. }
  415. }
  416. else if (list1->size == 0)
  417. {
  418. // Simply copies the two pointers
  419. list1->begin = list2->begin;
  420. list1->end = list2->end;
  421. }
  422. list1->size += list2->size;
  423. _delete(list2);
  424. }
  425. static void _linked_list_iterate_aux(linked_list_iterator_t it,
  426. void key_handler(void *key, void *context), void *context)
  427. {
  428. _ASSERT(it, ==, NULL, NULL_POINTER,);
  429. _ASSERT(key_handler, ==, NULL, NULL_POINTER,);
  430. _linked_list_iterate_aux(linked_list_iterator_get_next(it), key_handler,
  431. context);
  432. key_handler(linked_list_iterator_get_key(it), context);
  433. }
  434. static void _linked_list_reverse_aux(linked_list_iterator_t it)
  435. {
  436. if (it == NULL)
  437. return;
  438. _linked_list_reverse_aux(linked_list_iterator_get_next(it));
  439. linked_list_iterator_set_next(linked_list_iterator_get_next(it), it);
  440. }