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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 75701004 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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