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