1 /**
2  * @file list.c  Linked List implementation
3  *
4  * Copyright (C) 2010 Creytiv.com
5  */
6 #include <re_types.h>
7 #include <re_list.h>
8 #include <re_mem.h>
9 
10 
11 #define DEBUG_MODULE "list"
12 #define DEBUG_LEVEL 5
13 #include <re_dbg.h>
14 
15 
16 /**
17  * Initialise a linked list
18  *
19  * @param list Linked list
20  */
list_init(struct list * list)21 void list_init(struct list *list)
22 {
23 	if (!list)
24 		return;
25 
26 	list->head = NULL;
27 	list->tail = NULL;
28 }
29 
30 
31 /**
32  * Flush a linked list and free all elements
33  *
34  * @param list Linked list
35  */
list_flush(struct list * list)36 void list_flush(struct list *list)
37 {
38 	struct le *le;
39 
40 	if (!list)
41 		return;
42 
43 	le = list->head;
44 	while (le) {
45 		struct le *next = le->next;
46 		void *data = le->data;
47 		le->list = NULL;
48 		le->prev = le->next = NULL;
49 		le->data = NULL;
50 		le = next;
51 		mem_deref(data);
52 	}
53 
54 	list_init(list);
55 }
56 
57 
58 /**
59  * Clear a linked list without dereferencing the elements
60  *
61  * @param list Linked list
62  */
list_clear(struct list * list)63 void list_clear(struct list *list)
64 {
65 	struct le *le;
66 
67 	if (!list)
68 		return;
69 
70 	le = list->head;
71 	while (le) {
72 		struct le *next = le->next;
73 		le->list = NULL;
74 		le->prev = le->next = NULL;
75 		le->data = NULL;
76 		le = next;
77 	}
78 
79 	list_init(list);
80 }
81 
82 
83 /**
84  * Append a list element to a linked list
85  *
86  * @param list  Linked list
87  * @param le    List element
88  * @param data  Element data
89  */
list_append(struct list * list,struct le * le,void * data)90 void list_append(struct list *list, struct le *le, void *data)
91 {
92 	if (!list || !le)
93 		return;
94 
95 	if (le->list) {
96 		DEBUG_WARNING("append: le linked to %p\n", le->list);
97 		return;
98 	}
99 
100 	le->prev = list->tail;
101 	le->next = NULL;
102 	le->list = list;
103 	le->data = data;
104 
105 	if (!list->head)
106 		list->head = le;
107 
108 	if (list->tail)
109 		list->tail->next = le;
110 
111 	list->tail = le;
112 }
113 
114 
115 /**
116  * Prepend a list element to a linked list
117  *
118  * @param list  Linked list
119  * @param le    List element
120  * @param data  Element data
121  */
list_prepend(struct list * list,struct le * le,void * data)122 void list_prepend(struct list *list, struct le *le, void *data)
123 {
124 	if (!list || !le)
125 		return;
126 
127 	if (le->list) {
128 		DEBUG_WARNING("prepend: le linked to %p\n", le->list);
129 		return;
130 	}
131 
132 	le->prev = NULL;
133 	le->next = list->head;
134 	le->list = list;
135 	le->data = data;
136 
137 	if (list->head)
138 		list->head->prev = le;
139 
140 	if (!list->tail)
141 		list->tail = le;
142 
143 	list->head = le;
144 }
145 
146 
147 /**
148  * Insert a list element before a given list element
149  *
150  * @param list  Linked list
151  * @param le    Given list element
152  * @param ile   List element to insert
153  * @param data  Element data
154  */
list_insert_before(struct list * list,struct le * le,struct le * ile,void * data)155 void list_insert_before(struct list *list, struct le *le, struct le *ile,
156 		       void *data)
157 {
158 	if (!list || !le || !ile)
159 		return;
160 
161 	if (ile->list) {
162 		DEBUG_WARNING("insert_before: le linked to %p\n", le->list);
163 		return;
164 	}
165 
166 	if (le->prev)
167 		le->prev->next = ile;
168 	else if (list->head == le)
169 		list->head = ile;
170 
171 	ile->prev = le->prev;
172 	ile->next = le;
173 	ile->list = list;
174 	ile->data = data;
175 
176 	le->prev = ile;
177 }
178 
179 
180 /**
181  * Insert a list element after a given list element
182  *
183  * @param list  Linked list
184  * @param le    Given list element
185  * @param ile   List element to insert
186  * @param data  Element data
187  */
list_insert_after(struct list * list,struct le * le,struct le * ile,void * data)188 void list_insert_after(struct list *list, struct le *le, struct le *ile,
189 		       void *data)
190 {
191 	if (!list || !le || !ile)
192 		return;
193 
194 	if (ile->list) {
195 		DEBUG_WARNING("insert_after: le linked to %p\n", le->list);
196 		return;
197 	}
198 
199 	if (le->next)
200 		le->next->prev = ile;
201 	else if (list->tail == le)
202 		list->tail = ile;
203 
204 	ile->prev = le;
205 	ile->next = le->next;
206 	ile->list = list;
207 	ile->data = data;
208 
209 	le->next = ile;
210 }
211 
212 
213 /**
214  * Remove a list element from a linked list
215  *
216  * @param le    List element to remove
217  */
list_unlink(struct le * le)218 void list_unlink(struct le *le)
219 {
220 	struct list *list;
221 
222 	if (!le || !le->list)
223 		return;
224 
225 	list = le->list;
226 
227 	if (le->prev)
228 		le->prev->next = le->next;
229 	else
230 		list->head = le->next;
231 
232 	if (le->next)
233 		le->next->prev = le->prev;
234 	else
235 		list->tail = le->prev;
236 
237 	le->next = NULL;
238 	le->prev = NULL;
239 	le->list = NULL;
240 }
241 
242 
243 /**
244  * Sort a linked list in an order defined by the sort handler
245  *
246  * @param list  Linked list
247  * @param sh    Sort handler
248  * @param arg   Handler argument
249  */
list_sort(struct list * list,list_sort_h * sh,void * arg)250 void list_sort(struct list *list, list_sort_h *sh, void *arg)
251 {
252 	struct le *le;
253 	bool sort;
254 
255 	if (!list || !sh)
256 		return;
257 
258  retry:
259 	le = list->head;
260 	sort = false;
261 
262 	while (le && le->next) {
263 
264 		if (sh(le, le->next, arg)) {
265 
266 			le = le->next;
267 		}
268 		else {
269 			struct le *tle = le->next;
270 
271 			list_unlink(le);
272 			list_insert_after(list, tle, le, le->data);
273 			sort = true;
274 		}
275 	}
276 
277 	if (sort) {
278 		goto retry;
279 	}
280 }
281 
282 
283 /**
284  * Call the apply handler for each element in a linked list
285  *
286  * @param list  Linked list
287  * @param fwd   true to traverse from head to tail, false for reverse
288  * @param ah    Apply handler
289  * @param arg   Handler argument
290  *
291  * @return Current list element if handler returned true
292  */
list_apply(const struct list * list,bool fwd,list_apply_h * ah,void * arg)293 struct le *list_apply(const struct list *list, bool fwd,
294 		      list_apply_h *ah, void *arg)
295 {
296 	struct le *le;
297 
298 	if (!list || !ah)
299 		return NULL;
300 
301 	le = fwd ? list->head : list->tail;
302 
303 	while (le) {
304 		struct le *cur = le;
305 
306 		le = fwd ? le->next : le->prev;
307 
308 		if (ah(cur, arg))
309 			return cur;
310 	}
311 
312 	return NULL;
313 }
314 
315 
316 /**
317  * Get the first element in a linked list
318  *
319  * @param list  Linked list
320  *
321  * @return First list element (NULL if empty)
322  */
list_head(const struct list * list)323 struct le *list_head(const struct list *list)
324 {
325 	return list ? list->head : NULL;
326 }
327 
328 
329 /**
330  * Get the last element in a linked list
331  *
332  * @param list  Linked list
333  *
334  * @return Last list element (NULL if empty)
335  */
list_tail(const struct list * list)336 struct le *list_tail(const struct list *list)
337 {
338 	return list ? list->tail : NULL;
339 }
340 
341 
342 /**
343  * Get the number of elements in a linked list
344  *
345  * @param list  Linked list
346  *
347  * @return Number of list elements
348  */
list_count(const struct list * list)349 uint32_t list_count(const struct list *list)
350 {
351 	uint32_t n = 0;
352 	struct le *le;
353 
354 	if (!list)
355 		return 0;
356 
357 	for (le = list->head; le; le = le->next)
358 		++n;
359 
360 	return n;
361 }
362