source: mainline/common/include/adt/list.h@ 694ca3d6

topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 694ca3d6 was ad9178bf, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 20 months ago

Deduplicate ADT

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