1 /**
2 * @file bflb_list.h
3 *
4 * Copyright (c) 2021 Bouffalolab team
5 *
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements. See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership. The
9 * ASF licenses this file to you under the Apache License, Version 2.0 (the
10 * "License"); you may not use this file except in compliance with the
11 * License. You may obtain a copy of the License at
12 *
13 * http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
17 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
18 * License for the specific language governing permissions and limitations
19 * under the License.
20 *
21 */
22 #ifndef _BFLB_LIST_H
23 #define _BFLB_LIST_H
24
25 #include "string.h"
26 #include "stdint.h"
27
28 #ifdef __cplusplus
29 extern "C" {
30 #endif
31
32 /**
33 * container_of - return the member address of ptr, if the type of ptr is the
34 * struct type.
35 */
36 #define bflb_container_of(ptr, type, member) \
37 ((type *)((char *)(ptr) - (unsigned long)(&((type *)0)->member)))
38
39 /**
40 * Double List structure
41 */
42 struct bflb_dlist_node {
43 struct bflb_dlist_node *next; /**< point to next node. */
44 struct bflb_dlist_node *prev; /**< point to prev node. */
45 };
46 typedef struct bflb_dlist_node bflb_dlist_t; /**< Type for lists. */
47
48 /**
49 * @brief initialize a list
50 *
51 * @param l list to be initialized
52 */
bflb_dlist_init(bflb_dlist_t * l)53 static inline void bflb_dlist_init(bflb_dlist_t *l)
54 {
55 l->next = l->prev = l;
56 }
57
58 /**
59 * @brief insert a node after a list
60 *
61 * @param l list to insert it
62 * @param n new node to be inserted
63 */
bflb_dlist_insert_after(bflb_dlist_t * l,bflb_dlist_t * n)64 static inline void bflb_dlist_insert_after(bflb_dlist_t *l, bflb_dlist_t *n)
65 {
66 l->next->prev = n;
67 n->next = l->next;
68
69 l->next = n;
70 n->prev = l;
71 }
72
73 /**
74 * @brief insert a node before a list
75 *
76 * @param n new node to be inserted
77 * @param l list to insert it
78 */
bflb_dlist_insert_before(bflb_dlist_t * l,bflb_dlist_t * n)79 static inline void bflb_dlist_insert_before(bflb_dlist_t *l, bflb_dlist_t *n)
80 {
81 l->prev->next = n;
82 n->prev = l->prev;
83
84 l->prev = n;
85 n->next = l;
86 }
87
88 /**
89 * @brief remove node from list.
90 * @param n the node to remove from the list.
91 */
bflb_dlist_remove(bflb_dlist_t * n)92 static inline void bflb_dlist_remove(bflb_dlist_t *n)
93 {
94 n->next->prev = n->prev;
95 n->prev->next = n->next;
96
97 n->next = n->prev = n;
98 }
99
100 /**
101 * @brief move node from list.
102 * @param n the node to remove from the list.
103 */
bflb_dlist_move_head(bflb_dlist_t * l,bflb_dlist_t * n)104 static inline void bflb_dlist_move_head(bflb_dlist_t *l, bflb_dlist_t *n)
105 {
106 bflb_dlist_remove(n);
107 bflb_dlist_insert_after(l, n);
108 }
109
110 /**
111 * @brief move node from list.
112 * @param n the node to remove from the list.
113 */
bflb_dlist_move_tail(bflb_dlist_t * l,bflb_dlist_t * n)114 static inline void bflb_dlist_move_tail(bflb_dlist_t *l, bflb_dlist_t *n)
115 {
116 bflb_dlist_remove(n);
117 bflb_dlist_insert_before(l, n);
118 }
119
120 /**
121 * @brief tests whether a list is empty
122 * @param l the list to test.
123 */
bflb_dlist_isempty(const bflb_dlist_t * l)124 static inline int bflb_dlist_isempty(const bflb_dlist_t *l)
125 {
126 return l->next == l;
127 }
128
129 /**
130 * @brief get the list length
131 * @param l the list to get.
132 */
bflb_dlist_len(const bflb_dlist_t * l)133 static inline unsigned int bflb_dlist_len(const bflb_dlist_t *l)
134 {
135 unsigned int len = 0;
136 const bflb_dlist_t *p = l;
137
138 while (p->next != l) {
139 p = p->next;
140 len++;
141 }
142
143 return len;
144 }
145
146 /**
147 * @brief initialize a dlist object
148 */
149 #define DLIST_OBJECT_INIT(object) \
150 { \
151 &(object), &(object) \
152 }
153 /**
154 * @brief initialize a dlist object
155 */
156 #define DLIST_DEFINE(list) \
157 bflb_dlist_t list = { &(list), &(list) }
158
159 /**
160 * @brief get the struct for this entry
161 * @param node the entry point
162 * @param type the type of structure
163 * @param member the name of list in structure
164 */
165 #define bflb_dlist_entry(node, type, member) \
166 bflb_container_of(node, type, member)
167
168 /**
169 * dlist_first_entry - get the first element from a list
170 * @ptr: the list head to take the element from.
171 * @type: the type of the struct this is embedded in.
172 * @member: the name of the list_struct within the struct.
173 *
174 * Note, that list is expected to be not empty.
175 */
176 #define bflb_dlist_first_entry(ptr, type, member) \
177 bflb_dlist_entry((ptr)->next, type, member)
178 /**
179 * dlist_first_entry_or_null - get the first element from a list
180 * @ptr: the list head to take the element from.
181 * @type: the type of the struct this is embedded in.
182 * @member: the name of the list_struct within the struct.
183 *
184 * Note, that list is expected to be not empty.
185 */
186 #define bflb_dlist_first_entry_or_null(ptr, type, member) \
187 (bflb_dlist_isempty(ptr) ? NULL : bflb_dlist_first_entry(ptr, type, member))
188
189 /**
190 * dlist_for_each - iterate over a list
191 * @pos: the dlist_t * to use as a loop cursor.
192 * @head: the head for your list.
193 */
194 #define bflb_dlist_for_each(pos, head) \
195 for (pos = (head)->next; pos != (head); pos = pos->next)
196
197 /**
198 * dlist_for_each_prev - iterate over a list
199 * @pos: the dlist_t * to use as a loop cursor.
200 * @head: the head for your list.
201 */
202 #define bflb_dlist_for_each_prev(pos, head) \
203 for (pos = (head)->prev; pos != (head); pos = pos->prev)
204
205 /**
206 * dlist_for_each_safe - iterate over a list safe against removal of list entry
207 * @pos: the dlist_t * to use as a loop cursor.
208 * @n: another dlist_t * to use as temporary storage
209 * @head: the head for your list.
210 */
211 #define bflb_dlist_for_each_safe(pos, n, head) \
212 for (pos = (head)->next, n = pos->next; pos != (head); \
213 pos = n, n = pos->next)
214
215 #define bflb_dlist_for_each_prev_safe(pos, n, head) \
216 for (pos = (head)->prev, n = pos->prev; pos != (head); \
217 pos = n, n = pos->prev)
218 /**
219 * dlist_for_each_entry - iterate over list of given type
220 * @pos: the type * to use as a loop cursor.
221 * @head: the head for your list.
222 * @member: the name of the list_struct within the struct.
223 */
224 #define bflb_dlist_for_each_entry(pos, head, member) \
225 for (pos = bflb_dlist_entry((head)->next, typeof(*pos), member); \
226 &pos->member != (head); \
227 pos = bflb_dlist_entry(pos->member.next, typeof(*pos), member))
228
229 /**
230 * dlist_for_each_entry_reverse - iterate over list of given type
231 * @pos: the type * to use as a loop cursor.
232 * @head: the head for your list.
233 * @member: the name of the list_struct within the struct.
234 */
235 #define bflb_dlist_for_each_entry_reverse(pos, head, member) \
236 for (pos = bflb_dlist_entry((head)->prev, typeof(*pos), member); \
237 &pos->member != (head); \
238 pos = bflb_dlist_entry(pos->member.prev, typeof(*pos), member))
239
240 /**
241 * dlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
242 * @pos: the type * to use as a loop cursor.
243 * @n: another type * to use as temporary storage
244 * @head: the head for your list.
245 * @member: the name of the list_struct within the struct.
246 */
247 #define bflb_dlist_for_each_entry_safe(pos, n, head, member) \
248 for (pos = bflb_dlist_entry((head)->next, typeof(*pos), member), \
249 n = bflb_dlist_entry(pos->member.next, typeof(*pos), member); \
250 &pos->member != (head); \
251 pos = n, n = bflb_dlist_entry(n->member.next, typeof(*n), member))
252
253 /**
254 * dlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
255 * @pos: the type * to use as a loop cursor.
256 * @n: another type * to use as temporary storage
257 * @head: the head for your list.
258 * @member: the name of the list_struct within the struct.
259 */
260 #define bflb_dlist_for_each_entry_safe_reverse(pos, n, head, member) \
261 for (pos = bflb_dlist_entry((head)->prev, typeof(*pos), field), \
262 n = bflb_dlist_entry(pos->member.prev, typeof(*pos), member); \
263 &pos->member != (head); \
264 pos = n, n = bflb_dlist_entry(pos->member.prev, typeof(*pos), member))
265
266 #ifdef __cplusplus
267 }
268 #endif
269
270 #endif