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

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

Use bool for boolean values, unsigned long for counting heap objects.

  • Property mode set to 100644
File size: 10.4 KB
RevLine 
[f761f1eb]1/*
[df4ed85]2 * Copyright (c) 2001-2004 Jakub Jermar
[a74d0ad]3 * Copyright (c) 2013 Jiri Svoboda
[f761f1eb]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
[06e1e95]30/** @addtogroup genericadt
[b45c443]31 * @{
32 */
33/** @file
34 */
35
[06e1e95]36#ifndef KERN_LIST_H_
37#define KERN_LIST_H_
[f761f1eb]38
[7856d09]39#include <debug.h>
[7ac426e]40#include <typedefs.h>
[7a0359b]41#include <trace.h>
[f761f1eb]42
[55b77d9]43/** Doubly linked list link. */
[b3f8fb7]44typedef struct link {
[0a02653]45 struct link *prev; /**< Pointer to the previous item in the list. */
46 struct link *next; /**< Pointer to the next item in the list. */
[b3f8fb7]47} link_t;
[f761f1eb]48
[55b77d9]49/** Doubly linked list. */
50typedef struct list {
51 link_t head; /**< List head. Does not have any data. */
52} list_t;
53
[c14762e]54
[df13836]55extern bool list_member(const link_t *, const list_t *);
[c14762e]56extern void list_splice(list_t *, link_t *);
[df13836]57extern unsigned long list_count(const list_t *);
[c14762e]58
59
[7dd2561]60/** Declare and initialize statically allocated list.
61 *
62 * @param name Name of the new statically allocated list.
[0a02653]63 *
[7dd2561]64 */
[80bcaed]65#define LIST_INITIALIZE(name) \
[55b77d9]66 list_t name = { \
67 .head = { \
68 .prev = &(name).head, \
69 .next = &(name).head \
70 } \
[0a02653]71 }
72
73#define list_get_instance(link, type, member) \
[a74d0ad]74 ((type *) (((void *)(link)) - list_link_to_void(&(((type *) NULL)->member))))
[0a02653]75
[feeac0d]76#define list_foreach(list, member, itype, iterator) \
[07525cd]77 for (itype *iterator = NULL; iterator == NULL; iterator = (itype *) 1) \
[feeac0d]78 for (link_t *_link = (list).head.next; \
79 iterator = list_get_instance(_link, itype, member), \
80 _link != &(list).head; _link = _link->next)
[7dd2561]81
[7856d09]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
[ef1603b]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
[b72efe8]120#define assert_link_not_used(link) \
[7856d09]121 ASSERT(!link_used(link))
[b72efe8]122
[40a468a]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.
[0a02653]128 *
[40a468a]129 */
[7a0359b]130NO_TRACE static inline void link_initialize(link_t *link)
[c0a91d1]131{
132 link->prev = NULL;
133 link->next = NULL;
[f761f1eb]134}
135
[40a468a]136/** Initialize doubly-linked circular list
137 *
138 * Initialize doubly-linked circular list.
139 *
[55b77d9]140 * @param list Pointer to list_t structure.
[0a02653]141 *
[40a468a]142 */
[55b77d9]143NO_TRACE static inline void list_initialize(list_t *list)
[c0a91d1]144{
[55b77d9]145 list->head.prev = &list->head;
146 list->head.next = &list->head;
[f761f1eb]147}
148
[55b77d9]149/** Insert item before another item in doubly-linked circular list.
[0a02653]150 *
[40a468a]151 */
[55b77d9]152static inline void list_insert_before(link_t *lnew, link_t *lold)
[c0a91d1]153{
[55b77d9]154 lnew->next = lold;
155 lnew->prev = lold->prev;
156 lold->prev->next = lnew;
157 lold->prev = lnew;
[f761f1eb]158}
159
[55b77d9]160/** Insert item after another item in doubly-linked circular list.
[0a02653]161 *
[40a468a]162 */
[55b77d9]163static inline void list_insert_after(link_t *lnew, link_t *lold)
[c0a91d1]164{
[55b77d9]165 lnew->prev = lold;
166 lnew->next = lold->next;
167 lold->next->prev = lnew;
168 lold->next = lnew;
[0a02653]169}
170
[55b77d9]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.
[0a02653]177 *
178 */
[55b77d9]179NO_TRACE static inline void list_prepend(link_t *link, list_t *list)
[0a02653]180{
[55b77d9]181 list_insert_after(link, &list->head);
[0a02653]182}
183
[55b77d9]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.
[0a02653]190 *
191 */
[55b77d9]192NO_TRACE static inline void list_append(link_t *link, list_t *list)
[0a02653]193{
[55b77d9]194 list_insert_before(link, &list->head);
[f761f1eb]195}
196
[40a468a]197/** Remove item from doubly-linked circular list
198 *
199 * Remove item from doubly-linked circular list.
200 *
[0a02653]201 * @param link Pointer to link_t structure to be removed from the list
202 * it is contained in.
203 *
[40a468a]204 */
[7a0359b]205NO_TRACE static inline void list_remove(link_t *link)
[c0a91d1]206{
[14a60e3]207 if ((link->prev != NULL) && (link->next != NULL)) {
208 link->next->prev = link->prev;
209 link->prev->next = link->next;
210 }
211
[c0a91d1]212 link_initialize(link);
[f761f1eb]213}
214
[40a468a]215/** Query emptiness of doubly-linked circular list
216 *
217 * Query emptiness of doubly-linked circular list.
218 *
[55b77d9]219 * @param list Pointer to lins_t structure.
[0a02653]220 *
[40a468a]221 */
[df13836]222NO_TRACE static inline bool list_empty(const list_t *list)
[40a468a]223{
[55b77d9]224 return (list->head.next == &list->head);
[40a468a]225}
226
[55b77d9]227/** Get first item in list.
[0a02653]228 *
[55b77d9]229 * @param list Pointer to list_t structure.
230 *
231 * @return Head item of the list.
232 * @return NULL if the list is empty.
[85147f3]233 *
[55b77d9]234 */
[4748038]235static inline link_t *list_first(const list_t *list)
[55b77d9]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.
[0a02653]243 *
244 * @return Head item of the list.
245 * @return NULL if the list is empty.
[85147f3]246 *
[0a02653]247 */
[55b77d9]248static inline link_t *list_last(list_t *list)
[0a02653]249{
[55b77d9]250 return ((list->head.prev == &list->head) ? NULL : list->head.prev);
[0a02653]251}
[40a468a]252
[feeac0d]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
[40a468a]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 *
[0a02653]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 *
[40a468a]289 */
[7a0359b]290NO_TRACE static inline void headless_list_split_or_concat(link_t *part1, link_t *part2)
[40a468a]291{
292 part1->prev->next = part2;
[0a02653]293 part2->prev->next = part1;
294
295 link_t *hlp = part1->prev;
296
[40a468a]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 *
[0a02653]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 *
[40a468a]310 */
[7a0359b]311NO_TRACE static inline void headless_list_split(link_t *part1, link_t *part2)
[40a468a]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 *
[0a02653]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 *
[40a468a]325 */
[7a0359b]326NO_TRACE static inline void headless_list_concat(link_t *part1, link_t *part2)
[40a468a]327{
328 headless_list_split_or_concat(part1, part2);
329}
[f761f1eb]330
[c14762e]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 *
[ff90f5f]340 */
[c14762e]341NO_TRACE static inline void list_concat(list_t *list1, list_t *list2)
[ff90f5f]342{
[c14762e]343 list_splice(list2, list1->head.prev);
[ff90f5f]344}
345
[55b77d9]346/** Get n-th item in a list.
[0a02653]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 */
[df13836]355static inline link_t *list_nth(list_t *list, unsigned long n)
[0a02653]356{
[df13836]357 unsigned long cnt = 0;
[feeac0d]358 link_t *link;
[0a02653]359
[feeac0d]360 link = list_first(list);
361 while (link != NULL) {
[0a02653]362 if (cnt == n)
363 return link;
364
365 cnt++;
[feeac0d]366 link = list_next(link, list);
[0a02653]367 }
368
369 return NULL;
370}
[f761f1eb]371
[a74d0ad]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
[7856d09]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
[f761f1eb]395#endif
[b45c443]396
[06e1e95]397/** @}
[b45c443]398 */
Note: See TracBrowser for help on using the repository browser.