1 /**
2 * @file amp_list.h
3 * @copyright Copyright (C) 2015-2018 Alibaba Group Holding Limited
4 */
5
6 #ifndef AMP_LIST_H
7 #define AMP_LIST_H
8
9 #ifdef __cplusplus
10 extern "C" {
11 #endif
12
13 /** @addtogroup amp_list LIST
14 * list data structure manage.
15 *
16 * @{
17 */
18
19 /*
20 * Get offset of a member variable.
21 *
22 * @param[in] type the type of the struct this is embedded in.
23 * @param[in] member the name of the variable within the struct.
24 */
25 #define amp_offsetof(type, member) ((size_t)&(((type *)0)->member))
26
27 /*
28 * Get the struct for this entry.
29 *
30 * @param[in] ptr the list head to take the element from.
31 * @param[in] type the type of the struct this is embedded in.
32 * @param[in] member the name of the variable within the struct.
33 */
34 #define amp_container_of(ptr, type, member) \
35 ((type *)((char *)(ptr) - amp_offsetof(type, member)))
36
37 /* for double link list */
38 typedef struct dlist_s {
39 struct dlist_s *prev;
40 struct dlist_s *next;
41 } dlist_t;
42
43 /*
44 * add one node into data list.
45 *
46 * @param[in] node the data node to be inserted.
47 * @param[in] prev previous data node address.
48 * @param[in] next next data node address.
49 */
__dlist_add(dlist_t * node,dlist_t * prev,dlist_t * next)50 static inline void __dlist_add(dlist_t *node, dlist_t *prev, dlist_t *next)
51 {
52 node->next = next;
53 node->prev = prev;
54
55 prev->next = node;
56 next->prev = node;
57 }
58
59 /*
60 * Get the struct for this entry.
61 *
62 * @param[in] addr the list head to take the element from.
63 * @param[in] type the type of the struct this is embedded in.
64 * @param[in] member the name of the dlist_t within the struct.
65 */
66 #define dlist_entry(addr, type, member) \
67 ((type *)((long)addr - amp_offsetof(type, member)))
68
69 /*
70 * add one node just behind specified node.
71 *
72 * @param[in] node the data node to be inserted.
73 * @param[in] queue the specified last node.
74 */
dlist_add(dlist_t * node,dlist_t * queue)75 static inline void dlist_add(dlist_t *node, dlist_t *queue)
76 {
77 __dlist_add(node, queue, queue->next);
78 }
79
80 /*
81 * add one node just before specified node.
82 *
83 * @param[in] node the data node to be inserted.
84 * @param[in] queue the specified next node before which new node should be inserted.
85 */
dlist_add_tail(dlist_t * node,dlist_t * queue)86 static inline void dlist_add_tail(dlist_t *node, dlist_t *queue)
87 {
88 __dlist_add(node, queue->prev, queue);
89 }
90
91 /*
92 * delete one node from the data list.
93 *
94 * @param[in] node the data node to be deleted.
95 */
dlist_del(dlist_t * node)96 static inline void dlist_del(dlist_t *node)
97 {
98 dlist_t *prev = node->prev;
99 dlist_t *next = node->next;
100
101 prev->next = next;
102 next->prev = prev;
103 }
104
105 /*
106 * initialize one node.
107 *
108 * @param[in] node the data node to be initialized.
109 */
dlist_init(dlist_t * node)110 static inline void dlist_init(dlist_t *node)
111 {
112 node->next = node->prev = node;
113 }
114
115 /*
116 * initialize one node.
117 *
118 * @param[in] list the data node to be initialized.
119 */
INIT_AMP_DLIST_HEAD(dlist_t * list)120 static inline void INIT_AMP_DLIST_HEAD(dlist_t *list)
121 {
122 list->next = list;
123 list->prev = list;
124 }
125
126 /*
127 * Judge whether data list is empty.
128 *
129 * @param[in] head the head node of data list.
130 *
131 * @return 1 on empty, 0 FALSE.
132 */
dlist_empty(const dlist_t * head)133 static inline int dlist_empty(const dlist_t *head)
134 {
135 return head->next == head;
136 }
137
138 /*
139 * Initialise the list.
140 *
141 * @param[in] list the list to be inited.
142 */
143 #define AMP_DLIST_INIT(list) {&(list), &(list)}
144
145 /*
146 * Get the first element from a list
147 *
148 * @param[in] ptr the list head to take the element from.
149 * @param[in] type the type of the struct this is embedded in.
150 * @param[in] member the name of the dlist_t within the struct.
151 */
152 #define dlist_first_entry(ptr, type, member) dlist_entry((ptr)->next, type, member)
153
154 /*
155 * Iterate over a list.
156 *
157 * @param[in] pos the &struct dlist_t to use as a loop cursor.
158 * @param[in] head he head for your list.
159 */
160 #define dlist_for_each(pos, head) for (pos = (head)->next; pos != (head); pos = pos->next)
161
162 /*
163 * Iterate over a list safe against removal of list entry.
164 *
165 * @param[in] pos the &struct dlist_t to use as a loop cursor.
166 * @param[in] n another &struct dlist_t to use as temporary storage.
167 * @param[in] head he head for your list.
168 */
169 #define dlist_for_each_safe(pos, n, head) \
170 for (pos = (head)->next, n = pos->next; pos != (head); pos = n, n = pos->next)
171
172 /*
173 * Iterate over list of given type.
174 *
175 * @param[in] queue he head for your list.
176 * @param[in] node the &struct dlist_t to use as a loop cursor.
177 * @param[in] type the type of the struct this is embedded in.
178 * @param[in] member the name of the dlist_t within the struct.
179 */
180 #define dlist_for_each_entry(queue, node, type, member) \
181 for (node = amp_container_of((queue)->next, type, member); \
182 &node->member != (queue); \
183 node = amp_container_of(node->member.next, type, member))
184
185 /*
186 * Iterate over list of given type safe against removal of list entry.
187 *
188 * @param[in] queue the head for your list.
189 * @param[in] n the type * to use as a temp.
190 * @param[in] node the type * to use as a loop cursor.
191 * @param[in] type the type of the struct this is embedded in.
192 * @param[in] member the name of the dlist_t within the struct.
193 */
194 #define dlist_for_each_entry_safe(queue, n, node, type, member) \
195 for (node = amp_container_of((queue)->next, type, member), \
196 n = (queue)->next ? (queue)->next->next : NULL; \
197 &node->member != (queue); \
198 node = amp_container_of(n, type, member), n = n ? n->next : NULL)
199
200 /*
201 * Get the struct for this entry.
202 * @param[in] ptr the list head to take the element from.
203 * @param[in] type the type of the struct this is embedded in.
204 * @param[in] member the name of the variable within the struct.
205 */
206 #define list_entry(ptr, type, member) amp_container_of(ptr, type, member)
207
208 /*
209 * Iterate backwards over list of given type.
210 *
211 * @param[in] pos the type * to use as a loop cursor.
212 * @param[in] head he head for your list.
213 * @param[in] member the name of the dlist_t within the struct.
214 * @param[in] type the type of the struct this is embedded in.
215 */
216 #define dlist_for_each_entry_reverse(pos, head, member, type) \
217 for (pos = list_entry((head)->prev, type, member); \
218 &pos->member != (head); \
219 pos = list_entry(pos->member.prev, type, member))
220
221 /*
222 * Get the list length.
223 *
224 * @param[in] queue the head for your list.
225 *
226 * @return list length.
227 */
dlist_entry_number(dlist_t * queue)228 static inline int dlist_entry_number(dlist_t *queue)
229 {
230 int num;
231
232 dlist_t *cur = queue;
233
234 for (num = 0; cur->next != queue; cur = cur->next, num++)
235 ;
236
237 return num;
238 }
239
240 /*
241 * Initialise the list.
242 *
243 * @param[in] name the list to be initialized.
244 */
245 #define AMP_DLIST_HEAD_INIT(name) {&(name), &(name)}
246
247 /*
248 * Initialise the list.
249 *
250 * @param[in] name the list to be initialized.
251 */
252 #define AMP_DLIST_HEAD(name) dlist_t name = AMP_DLIST_HEAD_INIT(name)
253
254 /* for single link list */
255 typedef struct slist_s {
256 struct slist_s *next;
257 } slist_t;
258
259 /*
260 * add one node into a signle link list at head.
261 *
262 * @param[in] node the data node to be inserted.
263 * @param[in] head the specified head node.
264 */
slist_add(slist_t * node,slist_t * head)265 static inline void slist_add(slist_t *node, slist_t *head)
266 {
267 node->next = head->next;
268 head->next = node;
269 }
270
271 /*
272 * add one node into a signle link list at tail.
273 *
274 * @param[in] node the data node to be inserted.
275 * @param[in] head the specified head node.
276 */
slist_add_tail(slist_t * node,slist_t * head)277 static inline void slist_add_tail(slist_t *node, slist_t *head)
278 {
279 while (head->next) {
280 head = head->next;
281 }
282
283 slist_add(node, head);
284 }
285
286 /*
287 * delete one node from the head list.
288 *
289 * @param[in] node the data node to be deleted.
290 * @param[in] head the specified head node.
291 */
slist_del(slist_t * node,slist_t * head)292 static inline void slist_del(slist_t *node, slist_t *head)
293 {
294 while (head->next) {
295 if (head->next == node) {
296 head->next = node->next;
297 break;
298 }
299
300 head = head->next;
301 }
302 }
303
304 /*
305 * Judge whether data list is empty.
306 *
307 * @param[in] head the head node of data list.
308 *
309 * @return 1 on empty, 0 FALSE.
310 */
slist_empty(const slist_t * head)311 static inline int slist_empty(const slist_t *head)
312 {
313 return !head->next;
314 }
315
316 /*
317 * initialize one node.
318 *
319 * @param[in] head the data node to be initialized.
320 */
slist_init(slist_t * head)321 static inline void slist_init(slist_t *head)
322 {
323 head->next = 0;
324 }
325
326 /*
327 * Iterate over list of given type.
328 *
329 * @param[in] queue he head for your list.
330 * @param[in] node the type * to use as a loop cursor.
331 * @param[in] type the type of the struct this is embedded in.
332 * @param[in] member the name of the slist_t within the struct.
333 */
334 #define slist_for_each_entry(queue, node, type, member) \
335 for (node = amp_container_of((queue)->next, type, member); \
336 (uintptr_t)node + amp_offsetof(type, member) != 0; \
337 node = amp_container_of(node->member.next, type, member))
338
339 /*
340 * Iterate over list of given type safe against removal of list entry.
341 *
342 * @param[in] queue the head for your list.
343 * @param[in] tmp the type * to use as a temp.
344 * @param[in] node the type * to use as a loop cursor.
345 * @param[in] type the type of the struct this is embedded in.
346 * @param[in] member the name of the slist_t within the struct.
347 */
348 #define slist_for_each_entry_safe(queue, tmp, node, type, member) \
349 for (node = amp_container_of((queue)->next, type, member), \
350 tmp = (queue)->next ? (queue)->next->next : NULL; \
351 (uintptr_t)node + amp_offsetof(type, member) != 0; \
352 node = amp_container_of(tmp, type, member), tmp = tmp ? tmp->next : tmp)
353
354 /*
355 * Initialise the list.
356 *
357 * @param[in] name the list to be initialized.
358 */
359 #define AMP_SLIST_HEAD_INIT(name) {0}
360
361 /*
362 * Initialise the list.
363 *
364 * @param[in] name the list to be initialized.
365 */
366 #define AMP_SLIST_HEAD(name) slist_t name = AMP_SLIST_HEAD_INIT(name)
367
368 /*
369 * Get the struct for this entry.
370 *
371 * @param[in] addr the list head to take the element from.
372 * @param[in] type the type of the struct this is embedded in.
373 * @param[in] member the name of the slist_t within the struct.
374 */
375 #define slist_entry(addr, type, member) \
376 (addr ? (type *)((long)addr - amp_offsetof(type, member)) : (type *)addr)
377
378 /*
379 * Get the first element from a list.
380 *
381 * @param[in] ptr the list head to take the element from.
382 * @param[in] type the type of the struct this is embedded in.
383 * @param[in] member the name of the slist_t within the struct.
384 */
385 #define slist_first_entry(ptr, type, member) slist_entry((ptr)->next, type, member)
386
387 /*
388 * Get the list length.
389 *
390 * @param[in] queue the head for your list.
391 *
392 * @return list length.
393 */
slist_entry_number(slist_t * queue)394 static inline int slist_entry_number(slist_t *queue)
395 {
396 int num;
397
398 slist_t *cur = queue;
399
400 for (num = 0; cur->next; cur = cur->next, num++)
401 ;
402
403 return num;
404 }
405
406 /** @} */
407
408 #ifdef __cplusplus
409 }
410 #endif
411
412 #endif /* AMP_LIST_H */