LinkedList.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508
  1. /*******************************************************************************
  2. * Copyright (c) 2009, 2020 IBM Corp.
  3. *
  4. * All rights reserved. This program and the accompanying materials
  5. * are made available under the terms of the Eclipse Public License v2.0
  6. * and Eclipse Distribution License v1.0 which accompany this distribution.
  7. *
  8. * The Eclipse Public License is available at
  9. * https://www.eclipse.org/legal/epl-2.0/
  10. * and the Eclipse Distribution License is available at
  11. * http://www.eclipse.org/org/documents/edl-v10.php.
  12. *
  13. * Contributors:
  14. * Ian Craggs - initial API and implementation and/or initial documentation
  15. * Ian Craggs - updates for the async client
  16. *******************************************************************************/
  17. /**
  18. * @file
  19. * \brief functions which apply to linked list structures.
  20. *
  21. * These linked lists can hold data of any sort, pointed to by the content pointer of the
  22. * ListElement structure. ListElements hold the points to the next and previous items in the
  23. * list.
  24. * */
  25. #include "LinkedList.h"
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include "Heap.h"
  29. static int ListUnlink(List* aList, void* content, int(*callback)(void*, void*), int freeContent);
  30. /**
  31. * Sets a list structure to empty - all null values. Does not remove any items from the list.
  32. * @param newl a pointer to the list structure to be initialized
  33. */
  34. void ListZero(List* newl)
  35. {
  36. memset(newl, '\0', sizeof(List));
  37. }
  38. /**
  39. * Allocates and initializes a new list structure.
  40. * @return a pointer to the new list structure
  41. */
  42. List* ListInitialize(void)
  43. {
  44. List* newl = malloc(sizeof(List));
  45. if (newl)
  46. ListZero(newl);
  47. return newl;
  48. }
  49. /**
  50. * Append an already allocated ListElement and content to a list. Can be used to move
  51. * an item from one list to another.
  52. * @param aList the list to which the item is to be added
  53. * @param content the list item content itself
  54. * @param newel the ListElement to be used in adding the new item
  55. * @param size the size of the element
  56. */
  57. void ListAppendNoMalloc(List* aList, void* content, ListElement* newel, size_t size)
  58. { /* for heap use */
  59. newel->content = content;
  60. newel->next = NULL;
  61. newel->prev = aList->last;
  62. if (aList->first == NULL)
  63. aList->first = newel;
  64. else
  65. aList->last->next = newel;
  66. aList->last = newel;
  67. ++(aList->count);
  68. aList->size += size;
  69. }
  70. /**
  71. * Append an item to a list.
  72. * @param aList the list to which the item is to be added
  73. * @param content the list item content itself
  74. * @param size the size of the element
  75. */
  76. ListElement* ListAppend(List* aList, void* content, size_t size)
  77. {
  78. ListElement* newel = malloc(sizeof(ListElement));
  79. if (newel)
  80. ListAppendNoMalloc(aList, content, newel, size);
  81. return newel;
  82. }
  83. /**
  84. * Insert an item to a list at a specific position.
  85. * @param aList the list to which the item is to be added
  86. * @param content the list item content itself
  87. * @param size the size of the element
  88. * @param index the position in the list. If NULL, this function is equivalent
  89. * to ListAppend.
  90. */
  91. ListElement* ListInsert(List* aList, void* content, size_t size, ListElement* index)
  92. {
  93. ListElement* newel = malloc(sizeof(ListElement));
  94. if (newel == NULL)
  95. return newel;
  96. if ( index == NULL )
  97. ListAppendNoMalloc(aList, content, newel, size);
  98. else
  99. {
  100. newel->content = content;
  101. newel->next = index;
  102. newel->prev = index->prev;
  103. index->prev = newel;
  104. if ( newel->prev != NULL )
  105. newel->prev->next = newel;
  106. else
  107. aList->first = newel;
  108. ++(aList->count);
  109. aList->size += size;
  110. }
  111. return newel;
  112. }
  113. /**
  114. * Finds an element in a list by comparing the content pointers, rather than the contents
  115. * @param aList the list in which the search is to be conducted
  116. * @param content pointer to the list item content itself
  117. * @return the list item found, or NULL
  118. */
  119. ListElement* ListFind(List* aList, void* content)
  120. {
  121. return ListFindItem(aList, content, NULL);
  122. }
  123. /**
  124. * Finds an element in a list by comparing the content or pointer to the content. A callback
  125. * function is used to define the method of comparison for each element.
  126. * @param aList the list in which the search is to be conducted
  127. * @param content pointer to the content to look for
  128. * @param callback pointer to a function which compares each element (NULL means compare by content pointer)
  129. * @return the list element found, or NULL
  130. */
  131. ListElement* ListFindItem(List* aList, void* content, int(*callback)(void*, void*))
  132. {
  133. ListElement* rc = NULL;
  134. if (aList->current != NULL && ((callback == NULL && aList->current->content == content) ||
  135. (callback != NULL && callback(aList->current->content, content))))
  136. rc = aList->current;
  137. else
  138. {
  139. ListElement* current = NULL;
  140. /* find the content */
  141. while (ListNextElement(aList, &current) != NULL)
  142. {
  143. if (callback == NULL)
  144. {
  145. if (current->content == content)
  146. {
  147. rc = current;
  148. break;
  149. }
  150. }
  151. else
  152. {
  153. if (callback(current->content, content))
  154. {
  155. rc = current;
  156. break;
  157. }
  158. }
  159. }
  160. if (rc != NULL)
  161. aList->current = rc;
  162. }
  163. return rc;
  164. }
  165. /**
  166. * Removes and optionally frees an element in a list by comparing the content.
  167. * A callback function is used to define the method of comparison for each element.
  168. * @param aList the list in which the search is to be conducted
  169. * @param content pointer to the content to look for
  170. * @param callback pointer to a function which compares each element
  171. * @param freeContent boolean value to indicate whether the item found is to be freed
  172. * @return 1=item removed, 0=item not removed
  173. */
  174. static int ListUnlink(List* aList, void* content, int(*callback)(void*, void*), int freeContent)
  175. {
  176. ListElement* next = NULL;
  177. ListElement* saved = aList->current;
  178. int saveddeleted = 0;
  179. if (!ListFindItem(aList, content, callback))
  180. return 0; /* false, did not remove item */
  181. if (aList->current->prev == NULL)
  182. /* so this is the first element, and we have to update the "first" pointer */
  183. aList->first = aList->current->next;
  184. else
  185. aList->current->prev->next = aList->current->next;
  186. if (aList->current->next == NULL)
  187. aList->last = aList->current->prev;
  188. else
  189. aList->current->next->prev = aList->current->prev;
  190. next = aList->current->next;
  191. if (freeContent)
  192. {
  193. free(aList->current->content);
  194. aList->current->content = NULL;
  195. }
  196. if (saved == aList->current)
  197. saveddeleted = 1;
  198. free(aList->current);
  199. if (saveddeleted)
  200. aList->current = next;
  201. else
  202. aList->current = saved;
  203. --(aList->count);
  204. return 1; /* successfully removed item */
  205. }
  206. /**
  207. * Removes but does not free an item in a list by comparing the pointer to the content.
  208. * @param aList the list in which the search is to be conducted
  209. * @param content pointer to the content to look for
  210. * @return 1=item removed, 0=item not removed
  211. */
  212. int ListDetach(List* aList, void* content)
  213. {
  214. return ListUnlink(aList, content, NULL, 0);
  215. }
  216. /**
  217. * Removes and frees an item in a list by comparing the pointer to the content.
  218. * @param aList the list from which the item is to be removed
  219. * @param content pointer to the content to look for
  220. * @return 1=item removed, 0=item not removed
  221. */
  222. int ListRemove(List* aList, void* content)
  223. {
  224. return ListUnlink(aList, content, NULL, 1);
  225. }
  226. /**
  227. * Removes and frees an the first item in a list.
  228. * @param aList the list from which the item is to be removed
  229. * @return 1=item removed, 0=item not removed
  230. */
  231. void* ListDetachHead(List* aList)
  232. {
  233. void *content = NULL;
  234. if (aList->count > 0)
  235. {
  236. ListElement* first = aList->first;
  237. if (aList->current == first)
  238. aList->current = first->next;
  239. if (aList->last == first) /* i.e. no of items in list == 1 */
  240. aList->last = NULL;
  241. content = first->content;
  242. aList->first = aList->first->next;
  243. if (aList->first)
  244. aList->first->prev = NULL;
  245. free(first);
  246. --(aList->count);
  247. }
  248. return content;
  249. }
  250. /**
  251. * Removes and frees an the first item in a list.
  252. * @param aList the list from which the item is to be removed
  253. * @return 1=item removed, 0=item not removed
  254. */
  255. int ListRemoveHead(List* aList)
  256. {
  257. free(ListDetachHead(aList));
  258. return 0;
  259. }
  260. /**
  261. * Removes but does not free the last item in a list.
  262. * @param aList the list from which the item is to be removed
  263. * @return the last item removed (or NULL if none was)
  264. */
  265. void* ListPopTail(List* aList)
  266. {
  267. void* content = NULL;
  268. if (aList->count > 0)
  269. {
  270. ListElement* last = aList->last;
  271. if (aList->current == last)
  272. aList->current = last->prev;
  273. if (aList->first == last) /* i.e. no of items in list == 1 */
  274. aList->first = NULL;
  275. content = last->content;
  276. aList->last = aList->last->prev;
  277. if (aList->last)
  278. aList->last->next = NULL;
  279. free(last);
  280. --(aList->count);
  281. }
  282. return content;
  283. }
  284. /**
  285. * Removes but does not free an element in a list by comparing the content.
  286. * A callback function is used to define the method of comparison for each element.
  287. * @param aList the list in which the search is to be conducted
  288. * @param content pointer to the content to look for
  289. * @param callback pointer to a function which compares each element
  290. * @return 1=item removed, 0=item not removed
  291. */
  292. int ListDetachItem(List* aList, void* content, int(*callback)(void*, void*))
  293. { /* do not free the content */
  294. return ListUnlink(aList, content, callback, 0);
  295. }
  296. /**
  297. * Removes and frees an element in a list by comparing the content.
  298. * A callback function is used to define the method of comparison for each element
  299. * @param aList the list in which the search is to be conducted
  300. * @param content pointer to the content to look for
  301. * @param callback pointer to a function which compares each element
  302. * @return 1=item removed, 0=item not removed
  303. */
  304. int ListRemoveItem(List* aList, void* content, int(*callback)(void*, void*))
  305. { /* remove from list and free the content */
  306. return ListUnlink(aList, content, callback, 1);
  307. }
  308. /**
  309. * Removes and frees all items in a list, leaving the list ready for new items.
  310. * @param aList the list to which the operation is to be applied
  311. */
  312. void ListEmpty(List* aList)
  313. {
  314. while (aList->first != NULL)
  315. {
  316. ListElement* first = aList->first;
  317. if (first->content != NULL)
  318. {
  319. free(first->content);
  320. first->content = NULL;
  321. }
  322. aList->first = first->next;
  323. free(first);
  324. }
  325. aList->count = 0;
  326. aList->size = 0;
  327. aList->current = aList->first = aList->last = NULL;
  328. }
  329. /**
  330. * Removes and frees all items in a list, and frees the list itself
  331. * @param aList the list to which the operation is to be applied
  332. */
  333. void ListFree(List* aList)
  334. {
  335. ListEmpty(aList);
  336. free(aList);
  337. }
  338. /**
  339. * Removes and but does not free all items in a list, and frees the list itself
  340. * @param aList the list to which the operation is to be applied
  341. */
  342. void ListFreeNoContent(List* aList)
  343. {
  344. while (aList->first != NULL)
  345. {
  346. ListElement* first = aList->first;
  347. aList->first = first->next;
  348. free(first);
  349. }
  350. free(aList);
  351. }
  352. /**
  353. * Forward iteration through a list
  354. * @param aList the list to which the operation is to be applied
  355. * @param pos pointer to the current position in the list. NULL means start from the beginning of the list
  356. * This is updated on return to the same value as that returned from this function
  357. * @return pointer to the current list element
  358. */
  359. ListElement* ListNextElement(List* aList, ListElement** pos)
  360. {
  361. return *pos = (*pos == NULL) ? aList->first : (*pos)->next;
  362. }
  363. /**
  364. * Backward iteration through a list
  365. * @param aList the list to which the operation is to be applied
  366. * @param pos pointer to the current position in the list. NULL means start from the end of the list
  367. * This is updated on return to the same value as that returned from this function
  368. * @return pointer to the current list element
  369. */
  370. ListElement* ListPrevElement(List* aList, ListElement** pos)
  371. {
  372. return *pos = (*pos == NULL) ? aList->last : (*pos)->prev;
  373. }
  374. /**
  375. * List callback function for comparing integers
  376. * @param a first integer value
  377. * @param b second integer value
  378. * @return boolean indicating whether a and b are equal
  379. */
  380. int intcompare(void* a, void* b)
  381. {
  382. return *((int*)a) == *((int*)b);
  383. }
  384. /**
  385. * List callback function for comparing C strings
  386. * @param a first integer value
  387. * @param b second integer value
  388. * @return boolean indicating whether a and b are equal
  389. */
  390. int stringcompare(void* a, void* b)
  391. {
  392. return strcmp((char*)a, (char*)b) == 0;
  393. }
  394. #if defined(UNIT_TESTS)
  395. int main(int argc, char *argv[])
  396. {
  397. int i, *ip, *todelete;
  398. ListElement* current = NULL;
  399. List* l = ListInitialize();
  400. printf("List initialized\n");
  401. for (i = 0; i < 10; i++)
  402. {
  403. ip = malloc(sizeof(int));
  404. *ip = i;
  405. ListAppend(l, (void*)ip, sizeof(int));
  406. if (i==5)
  407. todelete = ip;
  408. printf("List element appended %d\n", *((int*)(l->last->content)));
  409. }
  410. printf("List contents:\n");
  411. current = NULL;
  412. while (ListNextElement(l, &current) != NULL)
  413. printf("List element: %d\n", *((int*)(current->content)));
  414. printf("List contents in reverse order:\n");
  415. current = NULL;
  416. while (ListPrevElement(l, &current) != NULL)
  417. printf("List element: %d\n", *((int*)(current->content)));
  418. /* if ListFindItem(l, *ip, intcompare)->content */
  419. printf("List contents having deleted element %d:\n", *todelete);
  420. ListRemove(l, todelete);
  421. current = NULL;
  422. while (ListNextElement(l, &current) != NULL)
  423. printf("List element: %d\n", *((int*)(current->content)));
  424. i = 9;
  425. ListRemoveItem(l, &i, intcompare);
  426. printf("List contents having deleted another element, %d, size now %d:\n", i, l->size);
  427. current = NULL;
  428. while (ListNextElement(l, &current) != NULL)
  429. printf("List element: %d\n", *((int*)(current->content)));
  430. ListFree(l);
  431. printf("List freed\n");
  432. }
  433. #endif