1 /*
2  * Copyright (c) 2008 Travis Geiselbrecht
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files
6  * (the "Software"), to deal in the Software without restriction,
7  * including without limitation the rights to use, copy, modify, merge,
8  * publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be
13  * included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  */
23 #ifndef __LIST_H
24 #define __LIST_H
25 
26 #include <lk/compiler.h>
27 #include <lk/macros.h>
28 #include <stddef.h>
29 #include <stdint.h>
30 #include <stdbool.h>
31 
32 __BEGIN_CDECLS;
33 
34 struct list_node {
35     struct list_node *prev;
36     struct list_node *next;
37 };
38 
39 #define LIST_INITIAL_VALUE(list) { &(list), &(list) }
40 #define LIST_INITIAL_CLEARED_VALUE { NULL, NULL }
41 
list_initialize(struct list_node * list)42 static inline void list_initialize(struct list_node *list)
43 {
44     list->prev = list->next = list;
45 }
46 
list_clear_node(struct list_node * item)47 static inline void list_clear_node(struct list_node *item)
48 {
49     item->prev = item->next = 0;
50 }
51 
list_in_list(struct list_node * item)52 static inline bool list_in_list(struct list_node *item)
53 {
54     if (item->prev == 0 && item->next == 0)
55         return false;
56     else
57         return true;
58 }
59 
list_add_head(struct list_node * list,struct list_node * item)60 static inline void list_add_head(struct list_node *list, struct list_node *item)
61 {
62     item->next = list->next;
63     item->prev = list;
64     list->next->prev = item;
65     list->next = item;
66 }
67 
68 #define list_add_after(entry, new_entry) list_add_head(entry, new_entry)
69 
list_add_tail(struct list_node * list,struct list_node * item)70 static inline void list_add_tail(struct list_node *list, struct list_node *item)
71 {
72     item->prev = list->prev;
73     item->next = list;
74     list->prev->next = item;
75     list->prev = item;
76 }
77 
78 #define list_add_before(entry, new_entry) list_add_tail(entry, new_entry)
79 
list_delete(struct list_node * item)80 static inline void list_delete(struct list_node *item)
81 {
82     item->next->prev = item->prev;
83     item->prev->next = item->next;
84     item->prev = item->next = 0;
85 }
86 
list_remove_head(struct list_node * list)87 static inline struct list_node *list_remove_head(struct list_node *list)
88 {
89     if (list->next != list) {
90         struct list_node *item = list->next;
91         list_delete(item);
92         return item;
93     } else {
94         return NULL;
95     }
96 }
97 
98 #define list_remove_head_type(list, type, element) \
99     containerof_null_safe(list_remove_head(list), type, element)
100 
list_remove_tail(struct list_node * list)101 static inline struct list_node *list_remove_tail(struct list_node *list)
102 {
103     if (list->prev != list) {
104         struct list_node *item = list->prev;
105         list_delete(item);
106         return item;
107     } else {
108         return NULL;
109     }
110 }
111 
112 #define list_remove_tail_type(list, type, element) \
113     containerof_null_safe(list_remove_tail(list), type, element)
114 
list_peek_head(struct list_node * list)115 static inline struct list_node *list_peek_head(struct list_node *list)
116 {
117     if (list->next != list) {
118         return list->next;
119     } else {
120         return NULL;
121     }
122 }
123 
124 #define list_peek_head_type(list, type, element) \
125     containerof_null_safe(list_peek_head(list), type, element)
126 
list_peek_tail(struct list_node * list)127 static inline struct list_node *list_peek_tail(struct list_node *list)
128 {
129     if (list->prev != list) {
130         return list->prev;
131     } else {
132         return NULL;
133     }
134 }
135 
136 #define list_peek_tail_type(list, type, element) \
137     containerof_null_safe(list_peek_tail(list), type, element)
138 
list_prev(struct list_node * list,struct list_node * item)139 static inline struct list_node *list_prev(struct list_node *list, struct list_node *item)
140 {
141     if (item->prev != list)
142         return item->prev;
143     else
144         return NULL;
145 }
146 
147 #define list_prev_type(list, item, type, element) \
148     containerof_null_safe(list_prev(list, item), type, element)
149 
list_prev_wrap(struct list_node * list,struct list_node * item)150 static inline struct list_node *list_prev_wrap(struct list_node *list, struct list_node *item)
151 {
152     if (item->prev != list)
153         return item->prev;
154     else if (item->prev->prev != list)
155         return item->prev->prev;
156     else
157         return NULL;
158 }
159 
160 #define list_prev_wrap_type(list, item, type, element) \
161     containerof_null_safe(list_prev_wrap(list, item), type, element)
162 
list_next(struct list_node * list,struct list_node * item)163 static inline struct list_node *list_next(struct list_node *list, struct list_node *item)
164 {
165     if (item->next != list)
166         return item->next;
167     else
168         return NULL;
169 }
170 
171 #define list_next_type(list, item, type, element) \
172     containerof_null_safe(list_next(list, item), type, element)
173 
list_next_wrap(struct list_node * list,struct list_node * item)174 static inline struct list_node *list_next_wrap(struct list_node *list, struct list_node *item)
175 {
176     if (item->next != list)
177         return item->next;
178     else if (item->next->next != list)
179         return item->next->next;
180     else
181         return NULL;
182 }
183 
184 #define list_next_wrap_type(list, item, type, element) \
185     containerof_null_safe(list_next_wrap(list, item), type, element)
186 
187 // iterates over the list, node should be struct list_node*
188 #define list_for_every(list, node) \
189     for(node = (list)->next; node != (list); node = node->next)
190 
191 // iterates over the list in a safe way for deletion of current node
192 // node and temp_node should be struct list_node*
193 #define list_for_every_safe(list, node, temp_node) \
194     for(node = (list)->next, temp_node = (node)->next;\
195     node != (list);\
196     node = temp_node, temp_node = (node)->next)
197 
198 // iterates over the list, entry should be the container structure type *
199 //
200 // Iterating over (entry) rather than the list can add UB when the list node is
201 // not inside of the enclosing type, as may be the case for the list terminator.
202 // We avoid this by iterating over the list node and only constructing the new
203 // entry if it was not the list terminator, otherwise setting it to null.
204 #define list_for_every_entry(list, entry, type, member) \
205     for (struct list_node *_list_for_every_cursor = (list)->next; \
206             ((entry) = NULL, _list_for_every_cursor != (list)) && \
207             ((entry) = containerof(_list_for_every_cursor, type, member)); \
208             _list_for_every_cursor = _list_for_every_cursor->next)
209 
210 
211 // iterates over the list in a safe way for deletion of current node
212 // entry should be the container structure type *
213 // See list_for_every_entry to see why we don't iterate over entries
214 #define list_for_every_entry_safe(list, entry, unused, type, member) \
215     (void) unused; \
216     for(struct list_node *_list_for_every_cursor = (list)->next; \
217             ((entry) = NULL, _list_for_every_cursor != (list)) && \
218             ((entry) = containerof(_list_for_every_cursor, type, member)) && \
219             (_list_for_every_cursor = _list_for_every_cursor->next);)
220 
list_is_empty(struct list_node * list)221 static inline bool list_is_empty(struct list_node *list)
222 {
223     return (list->next == list) ? true : false;
224 }
225 
list_length(struct list_node * list)226 static inline size_t list_length(struct list_node *list)
227 {
228     size_t cnt = 0;
229     struct list_node *node = list;
230     list_for_every(list, node) {
231         cnt++;
232     }
233 
234     return cnt;
235 }
236 
237 /**
238  * list_splice_after - Move all entries from one list to another list.
239  * @dest_item:  Items from @src_list are inserted after this item.
240  * @src_list:   List containing items to be moved.
241  *
242  * This function also serves as the helper function for list_splice_before,
243  * list_splice_head and list_splice_tail. In this case @dest_item can be the
244  * list node instead of an item in the list.
245  *
246  * Empty source and destination lists are both supported. The destination list
247  * or item should not be in the source list.
248  */
list_splice_after(struct list_node * dest_item,struct list_node * src_list)249 static inline void list_splice_after(struct list_node *dest_item,
250                                      struct list_node *src_list)
251 {
252     /*
253      * We need to read prev from @src_list before writing to src_next->prev in
254      * case @src_list is empty (src_next->prev and src_list->prev are the same
255      * in that case).
256      */
257     struct list_node *src_next = src_list->next;
258     struct list_node *src_prev = src_list->prev;
259 
260     /*
261      * Link to @dest_item at the start of &src_list and &dest_item->next at the
262      * end of @src_list. If src_list is empty, this will stash the existing
263      * @dest_item and @dest_item->next values into the head of source_list.
264      */
265     src_next->prev = dest_item;
266     src_prev->next = dest_item->next;
267 
268     /*
269      * List @src_list after @dest_item. If @src_list was empty this is a nop as
270      * we are reading back the same values we stored.
271      */
272     dest_item->next->prev = src_list->prev;
273     dest_item->next = src_list->next;
274 
275     /* Clear &src_list so we don't leave it in a corrupt state */
276     list_initialize(src_list);
277 }
278 
279 /**
280  * list_splice_before - Move all entries from one list to another list.
281  * @dest_item:  Items from @src_list are inserted before this item.
282  * @src_list:   List containing times to be moved.
283  */
list_splice_before(struct list_node * dest_item,struct list_node * src_list)284 static inline void list_splice_before(struct list_node *dest_item,
285                                       struct list_node *src_list)
286 {
287     list_splice_after(dest_item->prev, src_list);
288 }
289 
290 /**
291  * list_splice_head - Move all entries from one list to another list.
292  * @dest_list:  Items from @src_list are inserted at the head of this list.
293  * @src_list:   List containing times to be moved.
294  */
list_splice_head(struct list_node * dest_list,struct list_node * src_list)295 static inline void list_splice_head(struct list_node *dest_list,
296                                     struct list_node *src_list)
297 {
298     list_splice_after(dest_list, src_list);
299 }
300 
301 /**
302  * list_splice_tail - Move all entries from one list to another list.
303  * @dest_list:  Items from @src_list are inserted at the tail of this list.
304  * @src_list:   List containing times to be moved.
305  */
list_splice_tail(struct list_node * dest_list,struct list_node * src_list)306 static inline void list_splice_tail(struct list_node *dest_list,
307                                     struct list_node *src_list)
308 {
309     list_splice_after(dest_list->prev, src_list);
310 }
311 
312 __END_CDECLS;
313 
314 #endif
315