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