source: mainline/uspace/lib/c/include/adt/list.h@ 8e7c9fe

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 8e7c9fe was 8e7c9fe, checked in by Jan Vesely <jano.vesely@…>, 11 years ago

merge mainline changes

most usb changes were reverted. blink and usbmass were fixed
known problems:
ehci won't initialize
usbmast asserts on unmount (happens on mainline too)

  • Property mode set to 100644
File size: 10.1 KB
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
3 * Copyright (c) 2013 Jiri Svoboda
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libc
31 * @{
32 */
33/** @file
34 */
35
36#ifndef LIBC_LIST_H_
37#define LIBC_LIST_H_
38
39#include <assert.h>
40#include <stdbool.h>
41#include <stddef.h>
42
43/** Doubly linked list link. */
44typedef struct link {
45 struct link *prev; /**< Pointer to the previous item in the list. */
46 struct link *next; /**< Pointer to the next item in the list. */
47} link_t;
48
49/** Doubly linked list. */
50typedef struct list {
51 link_t head; /**< List head. Does not have any data. */
52} list_t;
53
54/** Declare and initialize statically allocated list.
55 *
56 * @param name Name of the new statically allocated list.
57 *
58 */
59#define LIST_INITIALIZE(name) \
60 list_t name = { \
61 .head = { \
62 .prev = &(name).head, \
63 .next = &(name).head \
64 } \
65 }
66
67#define list_get_instance(link, type, member) \
68 ((type *) (((void *)(link)) - list_link_to_void(&(((type *) NULL)->member))))
69
70#define list_foreach(list, member, itype, iterator) \
71 for (itype *iterator = NULL; iterator == NULL; iterator = (itype *) 1) \
72 for (link_t *_link = (list).head.next; \
73 iterator = list_get_instance(_link, itype, member), \
74 _link != &(list).head; _link = _link->next)
75
76#define list_foreach_rev(list, member, itype, iterator) \
77 for (itype *iterator = NULL; iterator == NULL; iterator = (itype *) 1) \
78 for (link_t *_link = (list).head.prev; \
79 iterator = list_get_instance(_link, itype, member), \
80 _link != &(list).head; _link = _link->prev)
81
82/** Unlike list_foreach(), allows removing items while traversing a list.
83 *
84 * @code
85 * list_t mylist;
86 * typedef struct item {
87 * int value;
88 * link_t item_link;
89 * } item_t;
90 *
91 * //..
92 *
93 * // Print each list element's value and remove the element from the list.
94 * list_foreach_safe(mylist, cur_link, next_link) {
95 * item_t *cur_item = list_get_instance(cur_link, item_t, item_link);
96 * printf("%d\n", cur_item->value);
97 * list_remove(cur_link);
98 * }
99 * @endcode
100 *
101 * @param list List to traverse.
102 * @param iterator Iterator to the current element of the list.
103 * The item this iterator points may be safely removed
104 * from the list.
105 * @param next_iter Iterator to the next element of the list.
106 */
107#define list_foreach_safe(list, iterator, next_iter) \
108 for (link_t *iterator = (list).head.next, \
109 *next_iter = iterator->next; \
110 iterator != &(list).head; \
111 iterator = next_iter, next_iter = iterator->next)
112
113#define assert_link_not_used(link) \
114 assert(!link_used(link))
115
116/** Returns true if the link is definitely part of a list. False if not sure. */
117static inline int link_in_use(const link_t *link)
118{
119 return link->prev != NULL && link->next != NULL;
120}
121
122/** Initialize doubly-linked circular list link
123 *
124 * Initialize doubly-linked list link.
125 *
126 * @param link Pointer to link_t structure to be initialized.
127 *
128 */
129static inline void link_initialize(link_t *link)
130{
131 link->prev = NULL;
132 link->next = NULL;
133}
134
135/** Initialize doubly-linked circular list
136 *
137 * Initialize doubly-linked circular list.
138 *
139 * @param list Pointer to list_t structure.
140 *
141 */
142static inline void list_initialize(list_t *list)
143{
144 list->head.prev = &list->head;
145 list->head.next = &list->head;
146}
147
148/** Insert item before another item in doubly-linked circular list.
149 *
150 */
151static inline void list_insert_before(link_t *lnew, link_t *lold)
152{
153 lnew->next = lold;
154 lnew->prev = lold->prev;
155 lold->prev->next = lnew;
156 lold->prev = lnew;
157}
158
159/** Insert item after another item in doubly-linked circular list.
160 *
161 */
162static inline void list_insert_after(link_t *lnew, link_t *lold)
163{
164 lnew->prev = lold;
165 lnew->next = lold->next;
166 lold->next->prev = lnew;
167 lold->next = lnew;
168}
169
170/** Add item to the beginning of doubly-linked circular list
171 *
172 * Add item to the beginning of doubly-linked circular list.
173 *
174 * @param link Pointer to link_t structure to be added.
175 * @param list Pointer to list_t structure.
176 *
177 */
178static inline void list_prepend(link_t *link, list_t *list)
179{
180 list_insert_after(link, &list->head);
181}
182
183/** Add item to the end of doubly-linked circular list
184 *
185 * Add item to the end of doubly-linked circular list.
186 *
187 * @param link Pointer to link_t structure to be added.
188 * @param list Pointer to list_t structure.
189 *
190 */
191static inline void list_append(link_t *link, list_t *list)
192{
193 list_insert_before(link, &list->head);
194}
195
196/** Remove item from doubly-linked circular list
197 *
198 * Remove item from doubly-linked circular list.
199 *
200 * @param link Pointer to link_t structure to be removed from the list
201 * it is contained in.
202 *
203 */
204static inline void list_remove(link_t *link)
205{
206 if ((link->prev != NULL) && (link->next != NULL)) {
207 link->next->prev = link->prev;
208 link->prev->next = link->next;
209 }
210
211 link_initialize(link);
212}
213
214/** Query emptiness of doubly-linked circular list
215 *
216 * Query emptiness of doubly-linked circular list.
217 *
218 * @param list Pointer to lins_t structure.
219 *
220 */
221static inline int list_empty(const list_t *list)
222{
223 return (list->head.next == &list->head);
224}
225
226/** Get first item in list.
227 *
228 * @param list Pointer to list_t structure.
229 *
230 * @return Head item of the list.
231 * @return NULL if the list is empty.
232 *
233 */
234static inline link_t *list_first(const list_t *list)
235{
236 return ((list->head.next == &list->head) ? NULL : list->head.next);
237}
238
239/** Get last item in list.
240 *
241 * @param list Pointer to list_t structure.
242 *
243 * @return Head item of the list.
244 * @return NULL if the list is empty.
245 *
246 */
247static inline link_t *list_last(const list_t *list)
248{
249 return (list->head.prev == &list->head) ? NULL : list->head.prev;
250}
251
252/** Get next item in list.
253 *
254 * @param link Current item link
255 * @param list List containing @a link
256 *
257 * @return Next item or NULL if @a link is the last item.
258 *
259 */
260static inline link_t *list_next(const link_t *link, const list_t *list)
261{
262 return (link->next == &list->head) ? NULL : link->next;
263}
264
265/** Get previous item in list.
266 *
267 * @param link Current item link
268 * @param list List containing @a link
269 *
270 * @return Previous item or NULL if @a link is the first item.
271 *
272 */
273static inline link_t *list_prev(const link_t *link, const list_t *list)
274{
275 return (link->prev == &list->head) ? NULL : link->prev;
276}
277
278/** Split or concatenate headless doubly-linked circular list
279 *
280 * Split or concatenate headless doubly-linked circular list.
281 *
282 * Note that the algorithm works both directions:
283 * concatenates splitted lists and splits concatenated lists.
284 *
285 * @param part1 Pointer to link_t structure leading the first
286 * (half of the headless) list.
287 * @param part2 Pointer to link_t structure leading the second
288 * (half of the headless) list.
289 *
290 */
291static inline void headless_list_split_or_concat(link_t *part1, link_t *part2)
292{
293 part1->prev->next = part2;
294 part2->prev->next = part1;
295
296 link_t *hlp = part1->prev;
297
298 part1->prev = part2->prev;
299 part2->prev = hlp;
300}
301
302/** Split headless doubly-linked circular list
303 *
304 * Split headless doubly-linked circular list.
305 *
306 * @param part1 Pointer to link_t structure leading
307 * the first half of the headless list.
308 * @param part2 Pointer to link_t structure leading
309 * the second half of the headless list.
310 *
311 */
312static inline void headless_list_split(link_t *part1, link_t *part2)
313{
314 headless_list_split_or_concat(part1, part2);
315}
316
317/** Concatenate two headless doubly-linked circular lists
318 *
319 * Concatenate two headless doubly-linked circular lists.
320 *
321 * @param part1 Pointer to link_t structure leading
322 * the first headless list.
323 * @param part2 Pointer to link_t structure leading
324 * the second headless list.
325 *
326 */
327static inline void headless_list_concat(link_t *part1, link_t *part2)
328{
329 headless_list_split_or_concat(part1, part2);
330}
331
332/** Get n-th item in a list.
333 *
334 * @param list Pointer to link_t structure representing the list.
335 * @param n Item number (indexed from zero).
336 *
337 * @return n-th item of the list.
338 * @return NULL if no n-th item found.
339 *
340 */
341static inline link_t *list_nth(const list_t *list, unsigned int n)
342{
343 unsigned int cnt = 0;
344
345 link_t *link = list_first(list);
346 while (link != NULL) {
347 if (cnt == n)
348 return link;
349
350 cnt++;
351 link = list_next(link, list);
352 }
353
354 return NULL;
355}
356
357/** Verify that argument type is a pointer to link_t (at compile time).
358 *
359 * This can be used to check argument type in a macro.
360 */
361static inline const void *list_link_to_void(const link_t *link)
362{
363 return link;
364}
365
366/** Determine if link is used.
367 *
368 * @param link Link
369 * @return @c true if link is used, @c false if not.
370 */
371static inline bool link_used(link_t *link)
372{
373 if (link->prev == NULL && link->next == NULL)
374 return false;
375
376 assert(link->prev != NULL && link->next != NULL);
377 return true;
378}
379
380extern int list_member(const link_t *, const list_t *);
381extern void list_concat(list_t *, list_t *);
382extern unsigned int list_count(const list_t *);
383
384#endif
385
386/** @}
387 */
Note: See TracBrowser for help on using the repository browser.