LinkedList.c 13 KB

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