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