source: mainline/uspace/lib/c/include/adt/list.h@ 063a74b9

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 063a74b9 was a74d0ad, checked in by Jiri Svoboda <jiri@…>, 12 years ago

Type check the member argument of list_get_instance macro.

  • Property mode set to 100644
File size: 8.8 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 <unistd.h>
41
42/** Doubly linked list link. */
43typedef struct link {
44 struct link *prev; /**< Pointer to the previous item in the list. */
45 struct link *next; /**< Pointer to the next item in the list. */
46} link_t;
47
48/** Doubly linked list. */
49typedef struct list {
50 link_t head; /**< List head. Does not have any data. */
51} list_t;
52
53/** Declare and initialize statically allocated list.
54 *
55 * @param name Name of the new statically allocated list.
56 *
57 */
58#define LIST_INITIALIZE(name) \
59 list_t name = { \
60 .head = { \
61 .prev = &(name).head, \
62 .next = &(name).head \
63 } \
64 }
65
66#define list_get_instance(link, type, member) \
67 ((type *) (((void *)(link)) - list_link_to_void(&(((type *) NULL)->member))))
68
69#define list_foreach(list, iterator) \
70 for (link_t *iterator = (list).head.next; \
71 iterator != &(list).head; iterator = iterator->next)
72
73/** Unlike list_foreach(), allows removing items while traversing a list.
74 *
75 * @code
76 * list_t mylist;
77 * typedef struct item {
78 * int value;
79 * link_t item_link;
80 * } item_t;
81 *
82 * //..
83 *
84 * // Print each list element's value and remove the element from the list.
85 * list_foreach_safe(mylist, cur_link, next_link) {
86 * item_t *cur_item = list_get_instance(cur_link, item_t, item_link);
87 * printf("%d\n", cur_item->value);
88 * list_remove(cur_link);
89 * }
90 * @endcode
91 *
92 * @param list List to traverse.
93 * @param iterator Iterator to the current element of the list.
94 * The item this iterator points may be safely removed
95 * from the list.
96 * @param next_iter Iterator to the next element of the list.
97 */
98#define list_foreach_safe(list, iterator, next_iter) \
99 for (link_t *iterator = (list).head.next, \
100 *next_iter = iterator->next; \
101 iterator != &(list).head; \
102 iterator = next_iter, next_iter = iterator->next)
103
104#define assert_link_not_used(link) \
105 assert(((link)->prev == NULL) && ((link)->next == NULL))
106
107/** Returns true if the link is definitely part of a list. False if not sure. */
108static inline int link_in_use(link_t *link)
109{
110 return link->prev != NULL && link->next != NULL;
111}
112
113/** Initialize doubly-linked circular list link
114 *
115 * Initialize doubly-linked list link.
116 *
117 * @param link Pointer to link_t structure to be initialized.
118 *
119 */
120static inline void link_initialize(link_t *link)
121{
122 link->prev = NULL;
123 link->next = NULL;
124}
125
126/** Initialize doubly-linked circular list
127 *
128 * Initialize doubly-linked circular list.
129 *
130 * @param list Pointer to list_t structure.
131 *
132 */
133static inline void list_initialize(list_t *list)
134{
135 list->head.prev = &list->head;
136 list->head.next = &list->head;
137}
138
139/** Insert item before another item in doubly-linked circular list.
140 *
141 */
142static inline void list_insert_before(link_t *lnew, link_t *lold)
143{
144 lnew->next = lold;
145 lnew->prev = lold->prev;
146 lold->prev->next = lnew;
147 lold->prev = lnew;
148}
149
150/** Insert item after another item in doubly-linked circular list.
151 *
152 */
153static inline void list_insert_after(link_t *lnew, link_t *lold)
154{
155 lnew->prev = lold;
156 lnew->next = lold->next;
157 lold->next->prev = lnew;
158 lold->next = lnew;
159}
160
161/** Add item to the beginning of doubly-linked circular list
162 *
163 * Add item to the beginning of doubly-linked circular list.
164 *
165 * @param link Pointer to link_t structure to be added.
166 * @param list Pointer to list_t structure.
167 *
168 */
169static inline void list_prepend(link_t *link, list_t *list)
170{
171 list_insert_after(link, &list->head);
172}
173
174/** Add item to the end of doubly-linked circular list
175 *
176 * Add item to the end of doubly-linked circular list.
177 *
178 * @param link Pointer to link_t structure to be added.
179 * @param list Pointer to list_t structure.
180 *
181 */
182static inline void list_append(link_t *link, list_t *list)
183{
184 list_insert_before(link, &list->head);
185}
186
187/** Remove item from doubly-linked circular list
188 *
189 * Remove item from doubly-linked circular list.
190 *
191 * @param link Pointer to link_t structure to be removed from the list
192 * it is contained in.
193 *
194 */
195static inline void list_remove(link_t *link)
196{
197 if ((link->prev != NULL) && (link->next != NULL)) {
198 link->next->prev = link->prev;
199 link->prev->next = link->next;
200 }
201
202 link_initialize(link);
203}
204
205/** Query emptiness of doubly-linked circular list
206 *
207 * Query emptiness of doubly-linked circular list.
208 *
209 * @param list Pointer to lins_t structure.
210 *
211 */
212static inline int list_empty(const list_t *list)
213{
214 return (list->head.next == &list->head);
215}
216
217/** Get first item in list.
218 *
219 * @param list Pointer to list_t structure.
220 *
221 * @return Head item of the list.
222 * @return NULL if the list is empty.
223 *
224 */
225static inline link_t *list_first(const list_t *list)
226{
227 return ((list->head.next == &list->head) ? NULL : list->head.next);
228}
229
230/** Get last item in list.
231 *
232 * @param list Pointer to list_t structure.
233 *
234 * @return Head item of the list.
235 * @return NULL if the list is empty.
236 *
237 */
238static inline link_t *list_last(list_t *list)
239{
240 return ((list->head.prev == &list->head) ? NULL : list->head.prev);
241}
242
243/** Split or concatenate headless doubly-linked circular list
244 *
245 * Split or concatenate headless doubly-linked circular list.
246 *
247 * Note that the algorithm works both directions:
248 * concatenates splitted lists and splits concatenated lists.
249 *
250 * @param part1 Pointer to link_t structure leading the first
251 * (half of the headless) list.
252 * @param part2 Pointer to link_t structure leading the second
253 * (half of the headless) list.
254 *
255 */
256static inline void headless_list_split_or_concat(link_t *part1, link_t *part2)
257{
258 part1->prev->next = part2;
259 part2->prev->next = part1;
260
261 link_t *hlp = part1->prev;
262
263 part1->prev = part2->prev;
264 part2->prev = hlp;
265}
266
267/** Split headless doubly-linked circular list
268 *
269 * Split headless doubly-linked circular list.
270 *
271 * @param part1 Pointer to link_t structure leading
272 * the first half of the headless list.
273 * @param part2 Pointer to link_t structure leading
274 * the second half of the headless list.
275 *
276 */
277static inline void headless_list_split(link_t *part1, link_t *part2)
278{
279 headless_list_split_or_concat(part1, part2);
280}
281
282/** Concatenate two headless doubly-linked circular lists
283 *
284 * Concatenate two headless doubly-linked circular lists.
285 *
286 * @param part1 Pointer to link_t structure leading
287 * the first headless list.
288 * @param part2 Pointer to link_t structure leading
289 * the second headless list.
290 *
291 */
292static inline void headless_list_concat(link_t *part1, link_t *part2)
293{
294 headless_list_split_or_concat(part1, part2);
295}
296
297/** Get n-th item in a list.
298 *
299 * @param list Pointer to link_t structure representing the list.
300 * @param n Item number (indexed from zero).
301 *
302 * @return n-th item of the list.
303 * @return NULL if no n-th item found.
304 *
305 */
306static inline link_t *list_nth(list_t *list, unsigned int n)
307{
308 unsigned int cnt = 0;
309
310 list_foreach(*list, link) {
311 if (cnt == n)
312 return link;
313
314 cnt++;
315 }
316
317 return NULL;
318}
319
320/** Verify that argument type is a pointer to link_t (at compile time).
321 *
322 * This can be used to check argument type in a macro.
323 */
324static inline const void *list_link_to_void(const link_t *link)
325{
326 return link;
327}
328
329extern int list_member(const link_t *, const list_t *);
330extern void list_concat(list_t *, list_t *);
331extern unsigned int list_count(const list_t *);
332
333#endif
334
335/** @}
336 */
Note: See TracBrowser for help on using the repository browser.