source: mainline/kernel/generic/include/adt/list.h@ b1c57a8

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since b1c57a8 was b1c57a8, checked in by Jakub Jermar <jakub@…>, 11 years ago

Merge from lp:~adam-hraska+lp/helenos/rcu/.

Only merge from the feature branch and resolve all conflicts.

  • Property mode set to 100644
File size: 10.4 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 genericadt
31 * @{
32 */
33/** @file
34 */
35
36#ifndef KERN_LIST_H_
37#define KERN_LIST_H_
38
39#include <debug.h>
40#include <typedefs.h>
41#include <trace.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
55extern int list_member(const link_t *, const list_t *);
56extern void list_splice(list_t *, link_t *);
57extern unsigned int list_count(const list_t *);
58
59
60/** Declare and initialize statically allocated list.
61 *
62 * @param name Name of the new statically allocated list.
63 *
64 */
65#define LIST_INITIALIZE(name) \
66 list_t name = { \
67 .head = { \
68 .prev = &(name).head, \
69 .next = &(name).head \
70 } \
71 }
72
73#define list_get_instance(link, type, member) \
74 ((type *) (((void *)(link)) - list_link_to_void(&(((type *) NULL)->member))))
75
76#define list_foreach(list, member, itype, iterator) \
77 for (itype *iterator = NULL; iterator == NULL; iterator = (itype *) 1) \
78 for (link_t *_link = (list).head.next; \
79 iterator = list_get_instance(_link, itype, member), \
80 _link != &(list).head; _link = _link->next)
81
82#define list_foreach_rev(list, member, itype, iterator) \
83 for (itype *iterator = NULL; iterator == NULL; iterator = (itype *) 1) \
84 for (link_t *_link = (list).head.prev; \
85 iterator = list_get_instance(_link, itype, member), \
86 _link != &(list).head; _link = _link->prev)
87
88/** Unlike list_foreach(), allows removing items while traversing a list.
89 *
90 * @code
91 * list_t mylist;
92 * typedef struct item {
93 * int value;
94 * link_t item_link;
95 * } item_t;
96 *
97 * //..
98 *
99 * // Print each list element's value and remove the element from the list.
100 * list_foreach_safe(mylist, cur_link, next_link) {
101 * item_t *cur_item = list_get_instance(cur_link, item_t, item_link);
102 * printf("%d\n", cur_item->value);
103 * list_remove(cur_link);
104 * }
105 * @endcode
106 *
107 * @param list List to traverse.
108 * @param iterator Iterator to the current element of the list.
109 * The item this iterator points may be safely removed
110 * from the list.
111 * @param next_iter Iterator to the next element of the list.
112 */
113#define list_foreach_safe(list, iterator, next_iter) \
114 for (link_t *iterator = (list).head.next, \
115 *next_iter = iterator->next; \
116 iterator != &(list).head; \
117 iterator = next_iter, next_iter = iterator->next)
118
119
120#define assert_link_not_used(link) \
121 ASSERT(!link_used(link))
122
123/** Initialize doubly-linked circular list link
124 *
125 * Initialize doubly-linked list link.
126 *
127 * @param link Pointer to link_t structure to be initialized.
128 *
129 */
130NO_TRACE static inline void link_initialize(link_t *link)
131{
132 link->prev = NULL;
133 link->next = NULL;
134}
135
136/** Initialize doubly-linked circular list
137 *
138 * Initialize doubly-linked circular list.
139 *
140 * @param list Pointer to list_t structure.
141 *
142 */
143NO_TRACE static inline void list_initialize(list_t *list)
144{
145 list->head.prev = &list->head;
146 list->head.next = &list->head;
147}
148
149/** Insert item before another item in doubly-linked circular list.
150 *
151 */
152static inline void list_insert_before(link_t *lnew, link_t *lold)
153{
154 lnew->next = lold;
155 lnew->prev = lold->prev;
156 lold->prev->next = lnew;
157 lold->prev = lnew;
158}
159
160/** Insert item after another item in doubly-linked circular list.
161 *
162 */
163static inline void list_insert_after(link_t *lnew, link_t *lold)
164{
165 lnew->prev = lold;
166 lnew->next = lold->next;
167 lold->next->prev = lnew;
168 lold->next = lnew;
169}
170
171/** Add item to the beginning of doubly-linked circular list
172 *
173 * Add item to the beginning of doubly-linked circular list.
174 *
175 * @param link Pointer to link_t structure to be added.
176 * @param list Pointer to list_t structure.
177 *
178 */
179NO_TRACE static inline void list_prepend(link_t *link, list_t *list)
180{
181 list_insert_after(link, &list->head);
182}
183
184/** Add item to the end of doubly-linked circular list
185 *
186 * Add item to the end of doubly-linked circular list.
187 *
188 * @param link Pointer to link_t structure to be added.
189 * @param list Pointer to list_t structure.
190 *
191 */
192NO_TRACE static inline void list_append(link_t *link, list_t *list)
193{
194 list_insert_before(link, &list->head);
195}
196
197/** Remove item from doubly-linked circular list
198 *
199 * Remove item from doubly-linked circular list.
200 *
201 * @param link Pointer to link_t structure to be removed from the list
202 * it is contained in.
203 *
204 */
205NO_TRACE static inline void list_remove(link_t *link)
206{
207 if ((link->prev != NULL) && (link->next != NULL)) {
208 link->next->prev = link->prev;
209 link->prev->next = link->next;
210 }
211
212 link_initialize(link);
213}
214
215/** Query emptiness of doubly-linked circular list
216 *
217 * Query emptiness of doubly-linked circular list.
218 *
219 * @param list Pointer to lins_t structure.
220 *
221 */
222NO_TRACE static inline int list_empty(const list_t *list)
223{
224 return (list->head.next == &list->head);
225}
226
227/** Get first item in list.
228 *
229 * @param list Pointer to list_t structure.
230 *
231 * @return Head item of the list.
232 * @return NULL if the list is empty.
233 *
234 */
235static inline link_t *list_first(const list_t *list)
236{
237 return ((list->head.next == &list->head) ? NULL : list->head.next);
238}
239
240/** Get last item in list.
241 *
242 * @param list Pointer to list_t structure.
243 *
244 * @return Head item of the list.
245 * @return NULL if the list is empty.
246 *
247 */
248static inline link_t *list_last(list_t *list)
249{
250 return ((list->head.prev == &list->head) ? NULL : list->head.prev);
251}
252
253/** Get next item in list.
254 *
255 * @param link Current item link
256 * @param list List containing @a link
257 *
258 * @return Next item or NULL if @a link is the last item.
259 */
260static inline link_t *list_next(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 */
272static inline link_t *list_prev(link_t *link, const list_t *list)
273{
274 return (link->prev == &list->head) ? NULL : link->prev;
275}
276
277/** Split or concatenate headless doubly-linked circular list
278 *
279 * Split or concatenate headless doubly-linked circular list.
280 *
281 * Note that the algorithm works both directions:
282 * concatenates splitted lists and splits concatenated lists.
283 *
284 * @param part1 Pointer to link_t structure leading the first
285 * (half of the headless) list.
286 * @param part2 Pointer to link_t structure leading the second
287 * (half of the headless) list.
288 *
289 */
290NO_TRACE static inline void headless_list_split_or_concat(link_t *part1, link_t *part2)
291{
292 part1->prev->next = part2;
293 part2->prev->next = part1;
294
295 link_t *hlp = part1->prev;
296
297 part1->prev = part2->prev;
298 part2->prev = hlp;
299}
300
301/** Split headless doubly-linked circular list
302 *
303 * Split headless doubly-linked circular list.
304 *
305 * @param part1 Pointer to link_t structure leading
306 * the first half of the headless list.
307 * @param part2 Pointer to link_t structure leading
308 * the second half of the headless list.
309 *
310 */
311NO_TRACE static inline void headless_list_split(link_t *part1, link_t *part2)
312{
313 headless_list_split_or_concat(part1, part2);
314}
315
316/** Concatenate two headless doubly-linked circular lists
317 *
318 * Concatenate two headless doubly-linked circular lists.
319 *
320 * @param part1 Pointer to link_t structure leading
321 * the first headless list.
322 * @param part2 Pointer to link_t structure leading
323 * the second headless list.
324 *
325 */
326NO_TRACE static inline void headless_list_concat(link_t *part1, link_t *part2)
327{
328 headless_list_split_or_concat(part1, part2);
329}
330
331/** Concatenate two lists
332 *
333 * Concatenate lists @a list1 and @a list2, producing a single
334 * list @a list1 containing items from both (in @a list1, @a list2
335 * order) and empty list @a list2.
336 *
337 * @param list1 First list and concatenated output
338 * @param list2 Second list and empty output.
339 *
340 */
341NO_TRACE static inline void list_concat(list_t *list1, list_t *list2)
342{
343 list_splice(list2, list1->head.prev);
344}
345
346/** Get n-th item in a list.
347 *
348 * @param list Pointer to link_t structure representing the list.
349 * @param n Item number (indexed from zero).
350 *
351 * @return n-th item of the list.
352 * @return NULL if no n-th item found.
353 *
354 */
355static inline link_t *list_nth(list_t *list, unsigned int n)
356{
357 unsigned int cnt = 0;
358 link_t *link;
359
360 link = list_first(list);
361 while (link != NULL) {
362 if (cnt == n)
363 return link;
364
365 cnt++;
366 link = list_next(link, list);
367 }
368
369 return NULL;
370}
371
372/** Verify that argument type is a pointer to link_t (at compile time).
373 *
374 * This can be used to check argument type in a macro.
375 */
376static inline const void *list_link_to_void(const link_t *link)
377{
378 return link;
379}
380
381/** Determine if link is used.
382 *
383 * @param link Link
384 * @return @c true if link is used, @c false if not.
385 */
386static inline bool link_used(link_t *link)
387{
388 if (link->prev == NULL && link->next == NULL)
389 return false;
390
391 ASSERT(link->prev != NULL && link->next != NULL);
392 return true;
393}
394
395#endif
396
397/** @}
398 */
Note: See TracBrowser for help on using the repository browser.