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

Last change on this file since c64e254 was bc56f30, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 6 years ago

Make some libc and libposix headers usable in C++

These headers either get included from standard C++ headers,
or are standard themselves, which means any unnamespaced nonstandard
identifiers are a problem. This commit attempts to fix those
issues, and removes hacks previously used in libcpp to work around it.

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