/protocols/MQTT/Paho/src/LinkedList.c

https://github.com/macchina-io/macchina.io · C · 501 lines · 261 code · 75 blank · 165 comment · 64 complexity · 84a3b2f031a61274957e2a682f513edf MD5 · raw file

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