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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5b382774 was 5b382774, checked in by Adam Hraska <adam.hraska+hos@…>, 13 years ago

Added member_to_inst() to macros.h in uspace and kernel.

  • Property mode set to 100644
File size: 8.4 KB
Line 
1/*
2 * Copyright (c) 2001-2004 Jakub Jermar
3 * Copyright (c) 2011 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 <unistd.h>
41
42/** Doubly linked list link. */
43typedef struct link {
44 struct link *prev; /**< Pointer to the previous item in the list. */
45 struct link *next; /**< Pointer to the next item in the list. */
46} link_t;
47
48/** Doubly linked list. */
49typedef struct list {
50 link_t head; /**< List head. Does not have any data. */
51} list_t;
52
53/** Declare and initialize statically allocated list.
54 *
55 * @param name Name of the new statically allocated list.
56 *
57 */
58#define LIST_INITIALIZE(name) \
59 list_t name = { \
60 .head = { \
61 .prev = &(name).head, \
62 .next = &(name).head \
63 } \
64 }
65
66#define list_get_instance(link, type, member) \
67 ((type *) (((void *)(link)) - ((void *) &(((type *) NULL)->member))))
68
69#define list_foreach(list, iterator) \
70 for (link_t *iterator = (list).head.next; \
71 iterator != &(list).head; iterator = iterator->next)
72
73/** Unlike list_foreach(), allows removing items while traversing a list.
74 *
75 * @code
76 * list_t mylist;
77 * typedef struct item {
78 * int value;
79 * link_t item_link;
80 * } item_t;
81 *
82 * //..
83 *
84 * // Print each list element's value and remove the element from the list.
85 * list_foreach_safe(mylist, cur_link, next_link) {
86 * item_t *cur_item = list_get_instance(cur_link, item_t, item_link);
87 * printf("%d\n", cur_item->value);
88 * list_remove(cur_link);
89 * }
90 * @endcode
91 *
92 * @param list List to traverse.
93 * @param iterator Iterator to the current element of the list.
94 * The item this iterator points may be safely removed
95 * from the list.
96 * @param next_iter Iterator to the next element of the list.
97 */
98#define list_foreach_safe(list, iterator, next_iter) \
99 for (link_t *iterator = (list).head.next, \
100 *next_iter = iterator->next; \
101 iterator != &(list).head; \
102 iterator = next_iter, next_iter = iterator->next)
103
104#define assert_link_not_used(link) \
105 assert(((link)->prev == NULL) && ((link)->next == NULL))
106
107/** Initialize doubly-linked circular list link
108 *
109 * Initialize doubly-linked list link.
110 *
111 * @param link Pointer to link_t structure to be initialized.
112 *
113 */
114static inline void link_initialize(link_t *link)
115{
116 link->prev = NULL;
117 link->next = NULL;
118}
119
120/** Initialize doubly-linked circular list
121 *
122 * Initialize doubly-linked circular list.
123 *
124 * @param list Pointer to list_t structure.
125 *
126 */
127static inline void list_initialize(list_t *list)
128{
129 list->head.prev = &list->head;
130 list->head.next = &list->head;
131}
132
133/** Insert item before another item in doubly-linked circular list.
134 *
135 */
136static inline void list_insert_before(link_t *lnew, link_t *lold)
137{
138 lnew->next = lold;
139 lnew->prev = lold->prev;
140 lold->prev->next = lnew;
141 lold->prev = lnew;
142}
143
144/** Insert item after another item in doubly-linked circular list.
145 *
146 */
147static inline void list_insert_after(link_t *lnew, link_t *lold)
148{
149 lnew->prev = lold;
150 lnew->next = lold->next;
151 lold->next->prev = lnew;
152 lold->next = lnew;
153}
154
155/** Add item to the beginning of doubly-linked circular list
156 *
157 * Add item to the beginning of doubly-linked circular list.
158 *
159 * @param link Pointer to link_t structure to be added.
160 * @param list Pointer to list_t structure.
161 *
162 */
163static inline void list_prepend(link_t *link, list_t *list)
164{
165 list_insert_after(link, &list->head);
166}
167
168/** Add item to the end of doubly-linked circular list
169 *
170 * Add item to the end of doubly-linked circular list.
171 *
172 * @param link Pointer to link_t structure to be added.
173 * @param list Pointer to list_t structure.
174 *
175 */
176static inline void list_append(link_t *link, list_t *list)
177{
178 list_insert_before(link, &list->head);
179}
180
181/** Remove item from doubly-linked circular list
182 *
183 * Remove item from doubly-linked circular list.
184 *
185 * @param link Pointer to link_t structure to be removed from the list
186 * it is contained in.
187 *
188 */
189static inline void list_remove(link_t *link)
190{
191 if ((link->prev != NULL) && (link->next != NULL)) {
192 link->next->prev = link->prev;
193 link->prev->next = link->next;
194 }
195
196 link_initialize(link);
197}
198
199/** Query emptiness of doubly-linked circular list
200 *
201 * Query emptiness of doubly-linked circular list.
202 *
203 * @param list Pointer to lins_t structure.
204 *
205 */
206static inline int list_empty(const list_t *list)
207{
208 return (list->head.next == &list->head);
209}
210
211/** Get first item in list.
212 *
213 * @param list Pointer to list_t structure.
214 *
215 * @return Head item of the list.
216 * @return NULL if the list is empty.
217 *
218 */
219static inline link_t *list_first(const list_t *list)
220{
221 return ((list->head.next == &list->head) ? NULL : list->head.next);
222}
223
224/** Get last item in list.
225 *
226 * @param list Pointer to list_t structure.
227 *
228 * @return Head item of the list.
229 * @return NULL if the list is empty.
230 *
231 */
232static inline link_t *list_last(list_t *list)
233{
234 return ((list->head.prev == &list->head) ? NULL : list->head.prev);
235}
236
237/** Split or concatenate headless doubly-linked circular list
238 *
239 * Split or concatenate headless doubly-linked circular list.
240 *
241 * Note that the algorithm works both directions:
242 * concatenates splitted lists and splits concatenated lists.
243 *
244 * @param part1 Pointer to link_t structure leading the first
245 * (half of the headless) list.
246 * @param part2 Pointer to link_t structure leading the second
247 * (half of the headless) list.
248 *
249 */
250static inline void headless_list_split_or_concat(link_t *part1, link_t *part2)
251{
252 part1->prev->next = part2;
253 part2->prev->next = part1;
254
255 link_t *hlp = part1->prev;
256
257 part1->prev = part2->prev;
258 part2->prev = hlp;
259}
260
261/** Split headless doubly-linked circular list
262 *
263 * Split headless doubly-linked circular list.
264 *
265 * @param part1 Pointer to link_t structure leading
266 * the first half of the headless list.
267 * @param part2 Pointer to link_t structure leading
268 * the second half of the headless list.
269 *
270 */
271static inline void headless_list_split(link_t *part1, link_t *part2)
272{
273 headless_list_split_or_concat(part1, part2);
274}
275
276/** Concatenate two headless doubly-linked circular lists
277 *
278 * Concatenate two headless doubly-linked circular lists.
279 *
280 * @param part1 Pointer to link_t structure leading
281 * the first headless list.
282 * @param part2 Pointer to link_t structure leading
283 * the second headless list.
284 *
285 */
286static inline void headless_list_concat(link_t *part1, link_t *part2)
287{
288 headless_list_split_or_concat(part1, part2);
289}
290
291/** Get n-th item in a list.
292 *
293 * @param list Pointer to link_t structure representing the list.
294 * @param n Item number (indexed from zero).
295 *
296 * @return n-th item of the list.
297 * @return NULL if no n-th item found.
298 *
299 */
300static inline link_t *list_nth(list_t *list, unsigned int n)
301{
302 unsigned int cnt = 0;
303
304 list_foreach(*list, link) {
305 if (cnt == n)
306 return link;
307
308 cnt++;
309 }
310
311 return NULL;
312}
313
314extern int list_member(const link_t *, const list_t *);
315extern void list_concat(list_t *, list_t *);
316extern unsigned int list_count(const list_t *);
317
318#endif
319
320/** @}
321 */
Note: See TracBrowser for help on using the repository browser.