1 /*
2  * Copyright (c) 2016 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #ifndef ZEPHYR_INCLUDE_SYS_LIST_GEN_H_
8 #define ZEPHYR_INCLUDE_SYS_LIST_GEN_H_
9 
10 #include <stddef.h>
11 #include <stdbool.h>
12 #include <sys/util.h>
13 
14 #define Z_GENLIST_FOR_EACH_NODE(__lname, __l, __sn)			\
15 	for (__sn = sys_ ## __lname ## _peek_head(__l); __sn != NULL;	\
16 	     __sn = sys_ ## __lname ## _peek_next(__sn))
17 
18 
19 #define Z_GENLIST_ITERATE_FROM_NODE(__lname, __l, __sn)			\
20 	for (__sn = __sn ? sys_ ## __lname ## _peek_next_no_check(__sn)	\
21 			 : sys_ ## __lname ## _peek_head(__l);		\
22 	     __sn != NULL;						\
23 	     __sn = sys_ ## __lname ## _peek_next(__sn))
24 
25 #define Z_GENLIST_FOR_EACH_NODE_SAFE(__lname, __l, __sn, __sns)		\
26 	for (__sn = sys_ ## __lname ## _peek_head(__l),			\
27 		     __sns = sys_ ## __lname ## _peek_next(__sn);	\
28 	     __sn != NULL ; __sn = __sns,				\
29 		     __sns = sys_ ## __lname ## _peek_next(__sn))
30 
31 #define Z_GENLIST_CONTAINER(__ln, __cn, __n)				\
32 	((__ln) ? CONTAINER_OF((__ln), __typeof__(*(__cn)), __n) : NULL)
33 
34 #define Z_GENLIST_PEEK_HEAD_CONTAINER(__lname, __l, __cn, __n)		\
35 	Z_GENLIST_CONTAINER(sys_ ## __lname ## _peek_head(__l), __cn, __n)
36 
37 #define Z_GENLIST_PEEK_TAIL_CONTAINER(__lname, __l, __cn, __n)		\
38 	Z_GENLIST_CONTAINER(sys_ ## __lname ## _peek_tail(__l), __cn, __n)
39 
40 #define Z_GENLIST_PEEK_NEXT_CONTAINER(__lname, __cn, __n)		\
41 	((__cn) ? Z_GENLIST_CONTAINER(					\
42 			sys_ ## __lname ## _peek_next(&((__cn)->__n)),	\
43 			__cn, __n) : NULL)
44 
45 #define Z_GENLIST_FOR_EACH_CONTAINER(__lname, __l, __cn, __n)		\
46 	for (__cn = Z_GENLIST_PEEK_HEAD_CONTAINER(__lname, __l, __cn,	\
47 						  __n);			\
48 	     __cn != NULL;						\
49 	     __cn = Z_GENLIST_PEEK_NEXT_CONTAINER(__lname, __cn, __n))
50 
51 #define Z_GENLIST_FOR_EACH_CONTAINER_SAFE(__lname, __l, __cn, __cns, __n)     \
52 	for (__cn = Z_GENLIST_PEEK_HEAD_CONTAINER(__lname, __l, __cn, __n),   \
53 	     __cns = Z_GENLIST_PEEK_NEXT_CONTAINER(__lname, __cn, __n); \
54 	     __cn != NULL; __cn = __cns,				\
55 	     __cns = Z_GENLIST_PEEK_NEXT_CONTAINER(__lname, __cn, __n))
56 
57 #define Z_GENLIST_IS_EMPTY(__lname)					\
58 	static inline bool						\
59 	sys_ ## __lname ## _is_empty(sys_ ## __lname ## _t *list)	\
60 	{								\
61 		return (sys_ ## __lname ## _peek_head(list) == NULL);	\
62 	}
63 
64 #define Z_GENLIST_PEEK_NEXT_NO_CHECK(__lname, __nname)			    \
65 	static inline sys_ ## __nname ## _t *				    \
66 	sys_ ## __lname ## _peek_next_no_check(sys_ ## __nname ## _t *node) \
67 	{								    \
68 		return z_ ## __nname ## _next_peek(node);		    \
69 	}
70 
71 #define Z_GENLIST_PEEK_NEXT(__lname, __nname)				     \
72 	static inline sys_ ## __nname ## _t *				     \
73 	sys_ ## __lname ## _peek_next(sys_ ## __nname ## _t *node)	     \
74 	{								     \
75 		return node != NULL ?                                        \
76 			sys_ ## __lname ## _peek_next_no_check(node) :       \
77 			      NULL;					     \
78 	}
79 
80 #define Z_GENLIST_PREPEND(__lname, __nname)				      \
81 	static inline void						      \
82 	sys_ ## __lname ## _prepend(sys_ ## __lname ## _t *list,	      \
83 				    sys_ ## __nname ## _t *node)	      \
84 	{								      \
85 		z_ ## __nname ## _next_set(node,			      \
86 					sys_ ## __lname ## _peek_head(list)); \
87 		z_ ## __lname ## _head_set(list, node);			      \
88 									      \
89 		if (sys_ ## __lname ## _peek_tail(list) == NULL) {	      \
90 			z_ ## __lname ## _tail_set(list,		      \
91 					sys_ ## __lname ## _peek_head(list)); \
92 		}							      \
93 	}
94 
95 #define Z_GENLIST_APPEND(__lname, __nname)				\
96 	static inline void						\
97 	sys_ ## __lname ## _append(sys_ ## __lname ## _t *list,		\
98 				   sys_ ## __nname ## _t *node)		\
99 	{								\
100 		z_ ## __nname ## _next_set(node, NULL);			\
101 									\
102 		if (sys_ ## __lname ## _peek_tail(list) == NULL) {	\
103 			z_ ## __lname ## _tail_set(list, node);		\
104 			z_ ## __lname ## _head_set(list, node);		\
105 		} else {						\
106 			z_ ## __nname ## _next_set(			\
107 				sys_ ## __lname ## _peek_tail(list),	\
108 				node);					\
109 			z_ ## __lname ## _tail_set(list, node);		\
110 		}							\
111 	}
112 
113 #define Z_GENLIST_APPEND_LIST(__lname, __nname)				\
114 	static inline void						\
115 	sys_ ## __lname ## _append_list(sys_ ## __lname ## _t *list,	\
116 					void *head, void *tail)		\
117 {									\
118 	if (sys_ ## __lname ## _peek_tail(list) == NULL) {		\
119 		z_ ## __lname ## _head_set(list,			\
120 					(sys_ ## __nname ## _t *)head); \
121 	} else {							\
122 		z_ ## __nname ## _next_set(				\
123 			sys_ ## __lname ## _peek_tail(list),		\
124 			(sys_ ## __nname ## _t *)head);			\
125 	}								\
126 	z_ ## __lname ## _tail_set(list,				\
127 				     (sys_ ## __nname ## _t *)tail);	\
128 }
129 
130 #define Z_GENLIST_MERGE_LIST(__lname, __nname)				\
131 	static inline void						\
132 	sys_ ## __lname ## _merge_ ## __lname (				\
133 				sys_ ## __lname ## _t *list,		\
134 				sys_ ## __lname ## _t *list_to_append)	\
135 	{								\
136 		sys_ ## __nname ## _t *head, *tail;			\
137 		head = sys_ ## __lname ## _peek_head(list_to_append);	\
138 		tail = sys_ ## __lname ## _peek_tail(list_to_append);	\
139 		sys_ ## __lname ## _append_list(list, head, tail);	\
140 		sys_ ## __lname ## _init(list_to_append);		\
141 	}
142 
143 #define Z_GENLIST_INSERT(__lname, __nname)				\
144 	static inline void						\
145 	sys_ ## __lname ## _insert(sys_ ## __lname ## _t *list,		\
146 				   sys_ ## __nname ## _t *prev,		\
147 				   sys_ ## __nname ## _t *node)		\
148 	{								\
149 		if (prev == NULL) {					\
150 			sys_ ## __lname ## _prepend(list, node);	\
151 		} else if (z_ ## __nname ## _next_peek(prev) == NULL) {	\
152 			sys_ ## __lname ## _append(list, node);		\
153 		} else {						\
154 			z_ ## __nname ## _next_set(node,		\
155 				z_ ## __nname ## _next_peek(prev));	\
156 			z_ ## __nname ## _next_set(prev, node);		\
157 		}							\
158 	}
159 
160 #define Z_GENLIST_GET_NOT_EMPTY(__lname, __nname)			\
161 	static inline sys_ ## __nname ## _t *				\
162 	sys_ ## __lname ## _get_not_empty(sys_ ## __lname ## _t *list)	\
163 	{								\
164 		sys_ ## __nname ## _t *node =				\
165 				sys_ ## __lname ## _peek_head(list);	\
166 									\
167 		z_ ## __lname ## _head_set(list,			\
168 				z_ ## __nname ## _next_peek(node));	\
169 		if (sys_ ## __lname ## _peek_tail(list) == node) {	\
170 			z_ ## __lname ## _tail_set(list,		\
171 				sys_ ## __lname ## _peek_head(list));	\
172 		}							\
173 									\
174 		return node;						\
175 	}
176 
177 #define Z_GENLIST_GET(__lname, __nname)					\
178 	static inline sys_ ## __nname ## _t *				\
179 	sys_ ## __lname ## _get(sys_ ## __lname ## _t *list)		\
180 	{								\
181 		return sys_ ## __lname ## _is_empty(list) ? NULL :	\
182 			sys_ ## __lname ## _get_not_empty(list);	\
183 	}
184 
185 #define Z_GENLIST_REMOVE(__lname, __nname)				      \
186 	static inline void						      \
187 	sys_ ## __lname ## _remove(sys_ ## __lname ## _t *list,		      \
188 				   sys_ ## __nname ## _t *prev_node,	      \
189 				   sys_ ## __nname ## _t *node)		      \
190 	{								      \
191 		if (prev_node == NULL) {				      \
192 			z_ ## __lname ## _head_set(list,		      \
193 				z_ ## __nname ## _next_peek(node));	      \
194 									      \
195 			/* Was node also the tail? */			      \
196 			if (sys_ ## __lname ## _peek_tail(list) == node) {    \
197 				z_ ## __lname ## _tail_set(list,	      \
198 					sys_ ## __lname ## _peek_head(list)); \
199 			}						      \
200 		} else {						      \
201 			z_ ## __nname ## _next_set(prev_node,		      \
202 				z_ ## __nname ## _next_peek(node));	      \
203 									      \
204 			/* Was node the tail? */			      \
205 			if (sys_ ## __lname ## _peek_tail(list) == node) {    \
206 				z_ ## __lname ## _tail_set(list,	      \
207 							     prev_node);      \
208 			}						      \
209 		}							      \
210 									      \
211 		z_ ## __nname ## _next_set(node, NULL);			      \
212 	}
213 
214 #define Z_GENLIST_FIND_AND_REMOVE(__lname, __nname)			 \
215 	static inline bool						 \
216 	sys_ ## __lname ## _find_and_remove(sys_ ## __lname ## _t *list, \
217 					    sys_ ## __nname ## _t *node) \
218 	{								 \
219 		sys_ ## __nname ## _t *prev = NULL;			 \
220 		sys_ ## __nname ## _t *test;				 \
221 									 \
222 		Z_GENLIST_FOR_EACH_NODE(__lname, list, test) {		 \
223 			if (test == node) {				 \
224 				sys_ ## __lname ## _remove(list, prev,	 \
225 							   node);	 \
226 				return true;				 \
227 			}						 \
228 									 \
229 			prev = test;					 \
230 		}							 \
231 									 \
232 		return false;						 \
233 	}
234 
235 #endif /* ZEPHYR_INCLUDE_SYS_LIST_GEN_H_ */
236