blob: 428109049635f191d3174c59d69579573def3c27 [file] [log] [blame]
Florin Corasb957d802019-07-09 19:02:33 -07001/*
2 * Copyright (c) 2019 Cisco and/or its affiliates.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at:
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 *
15 * @file
16 * @brief Circular doubly linked list with head sentinel.
17 * List entries are allocated out of a "supporting" pool and all pool entries
18 * must contain a list anchor struct for each list they pertain to.
19 */
20
21#ifndef SRC_VPPINFRA_CLIB_LLIST_H_
22#define SRC_VPPINFRA_CLIB_LLIST_H_
23
24#include <vppinfra/types.h>
25#include <vppinfra/pool.h>
26
27typedef u32 clib_llist_index_t;
28
29typedef struct clib_llist_anchor
30{
31 clib_llist_index_t prev;
32 clib_llist_index_t next;
33} clib_llist_anchor_t;
34
35#define CLIB_LLIST_INVALID_INDEX ((u32)~0)
36
37/**
38 * Local variable naming macro.
39 */
40#define _ll_var(v) _llist_##v
41/**
42 * Local macros to grab llist anchor next and prev from pool entry
43 */
44#define _lnext(E,name) ((E)->name).next
45#define _lprev(E,name) ((E)->name).prev
46/**
47 * Get list entry index
48 *
49 * @param LP linked list pool
50 * @param E pool entry
51 * @return pool entry index
52 */
53#define clib_llist_entry_index(LP,E) ((E) - (LP))
54/**
Florin Corasfa3bd302021-05-17 18:16:44 -070055 * Alloc new element
56 *
57 * @param LP linked list pool
58 * @param E element to be returned
59 */
60#define clib_llist_get(LP, E) pool_get (LP, E)
61/**
62 * Free element
63 *
64 * @param LP linked list pool
65 * @param E element to be freed
66 */
67#define clib_llist_put(LP, E) pool_put (LP, E)
68/**
69 * Free list supporting container
70 *
71 * @param LP linked list pool
72 */
73#define clib_llist_free(LP) pool_free (LP)
74/**
75 * Get list elt at index
76 *
77 * @param LP linked list pool
78 * @param EI element index
79 * @return element
80 */
81#define clib_llist_elt(LP, EI) pool_elt_at_index (LP, EI)
82/**
83 * Get number of elements in supporting container
84 *
85 * This is NOT the elements linked in the list but the number of
86 * elements consumed out of the supporting pool
87 *
88 * @param LP linked list pool
89 * @return number of elements
90 */
91#define clib_llist_elts(LP) pool_elts (LP)
92/**
Florin Corasb0ffbee2019-07-21 19:23:46 -070093 * Get prev list entry index
94 *
95 * @param E pool entry
96 * @name list anchor name
97 * @return previous index
98 */
99#define clib_llist_prev_index(E,name) _lprev(E,name)
100/**
101 * Get next list entry index
102 *
103 * @param E pool entry
104 * @name list anchor name
105 * @return next index
106 */
107#define clib_llist_next_index(E,name) _lnext(E,name)
108/**
Florin Corasb957d802019-07-09 19:02:33 -0700109 * Get next pool entry
110 *
111 * @param LP linked list pool
112 * @param name list anchor name
113 * @param E pool entry
114 * @return next pool entry
115 */
116#define clib_llist_next(LP,name,E) pool_elt_at_index((LP),_lnext((E),name))
117/**
118 * Get previous pool entry
119 *
120 * @param LP linked list pool
121 * @param name list anchor name
122 * @param E pool entry
123 * @return previous pool entry
124 */
125#define clib_llist_prev(LP,name,E) pool_elt_at_index((LP),_lprev((E),name))
126/**
127 * Initialize element in llist for entry
128 *
129 * @param LP linked list pool
130 * @param name list anchor name
131 * @param E entry whose ll anchor is to be initialized
132 */
133#define clib_llist_anchor_init(LP,name,E) \
134do { \
135 _lprev ((E),name) = clib_llist_entry_index ((LP), (E)); \
136 _lnext ((E),name) = _lprev ((E),name); \
137} while (0)
138/**
139 * Initialize llist head
140 *
141 * @param LP linked list pool
142 * @param name list anchor name
143 */
144#define clib_llist_make_head(LP,name) \
145({ \
146 typeof (LP) _ll_var (head); \
147 pool_get_zero ((LP), _ll_var (head)); \
148 clib_llist_anchor_init ((LP),name,_ll_var (head)); \
149 clib_llist_entry_index ((LP), _ll_var (head)); \
150})
151/**
152 * Check is list is empty
153 *
154 * @param LP linked list pool
155 * @param name list anchor name
156 * @param H list head
157 * @return 1 if sentinel is the only node part of the list, 0 otherwise
158 */
Florin Coras2062ec02019-07-15 13:15:18 -0700159#define clib_llist_is_empty(LP,name,H) \
160 (clib_llist_entry_index (LP,H) == (H)->name.next)
161/**
162 * Check if element is linked in a list
163 *
164 * @param E list element
165 * @param name list anchor name
166 */
167#define clib_llist_elt_is_linked(E,name) \
168 ((E)->name.next != CLIB_LLIST_INVALID_INDEX \
169 && (E)->name.prev != CLIB_LLIST_INVALID_INDEX)
Florin Corasb957d802019-07-09 19:02:33 -0700170/**
171 * Insert entry between previous and next
172 *
173 * Internal use.
174 *
175 * @param LP linked list pool
176 * @param name list anchor name
177 * @param E new entry
178 * @param P previous in list
179 * @param N next in list
180 */
181#define _llist_insert(LP,name,E,P,N) \
182do { \
183 _lprev (E,name) = _lprev(N,name); \
184 _lnext (E,name) = _lnext(P,name); \
185 _lprev ((N),name) = clib_llist_entry_index ((LP),(E)); \
186 _lnext ((P),name) = clib_llist_entry_index ((LP),(E)); \
187} while (0)
188/**
189 * Insert entry after previous
190 *
191 * @param LP linked list pool
192 * @param name list anchor name
193 * @param E new entry
194 * @param P previous in list
195 */
196#define clib_llist_insert(LP,name,E,P) \
197do { \
198 typeof (LP) _ll_var (N) = clib_llist_next (LP,name,P); \
199 _llist_insert ((LP),name,(E),(P), _ll_var (N)); \
200} while (0)
201
202/**
203 * Add entry after head
204 *
205 * @param LP linked list pool
206 * @param name list anchor name
207 * @param E new entry
208 * @param H list head
209 */
210#define clib_llist_add(LP,name,E,H) clib_llist_insert ((LP),name,(E),(H))
211/**
212 * Add entry after tail
213 *
214 * @param LP linked list pool
215 * @param name list anchor name
216 * @param E new entry
217 * @param H list head
218 */
219#define clib_llist_add_tail(LP,name,E,H) \
220do { \
221 typeof (LP) _ll_var (P) = clib_llist_prev ((LP),name,(H)); \
222 _llist_insert ((LP),name,(E),_ll_var (P),(H)); \
223} while (0)
224/**
225 * Remove entry from list
226 *
227 * @param LP linked list pool
228 * @param name list anchor name
229 * @param E entry to be removed
230 */
231#define clib_llist_remove(LP,name,E) \
232do { \
233 ASSERT ((E) != clib_llist_next (LP,name,E));/* don't remove sentinel */\
234 ASSERT (_lnext (E,name) != CLIB_LLIST_INVALID_INDEX); \
235 ASSERT (_lprev (E,name) != CLIB_LLIST_INVALID_INDEX); \
236 typeof (LP) _ll_var (P) = clib_llist_prev ((LP),name,E); \
237 typeof (LP) _ll_var (N) = clib_llist_next ((LP),name,E); \
238 _lnext (_ll_var (P),name) = _lnext (E,name); \
239 _lprev (_ll_var (N),name) = _lprev (E,name); \
240 _lnext (E,name) = _lprev (E,name) = CLIB_LLIST_INVALID_INDEX; \
241}while (0)
Florin Coras2062ec02019-07-15 13:15:18 -0700242/**
243 * Removes and returns the first element in the list.
244 *
245 * The element is not freed. It's the responsability of the caller to
246 * free it.
247 *
248 * @param LP linked list pool
249 * @param name list anchor name
250 * @param E storage the first entry
251 * @param H list head entry
252 */
253#define clib_llist_pop_first(LP,name,E,H) \
254do { \
255 E = clib_llist_next (LP,name,H); \
256 clib_llist_remove (LP,name,E); \
257} while (0)
Florin Corasb957d802019-07-09 19:02:33 -0700258/**
259 * Splice two lists at a given position
260 *
261 * List spliced into destination list is left with 0 entries, i.e., head
262 * is made to point to itself.
263 *
264 * @param LP linked list pool
265 * @param name list anchor name
266 * @param P position in destination where source list is spliced
267 * @param H head of source list that will be spliced into destination
268 */
269#define clib_llist_splice(LP,name,P,H) \
270do { \
271 typeof (LP) _ll_var (fe) = clib_llist_next (LP,name,H); \
272 if (_ll_var (fe) != (H)) \
273 { \
274 typeof (LP) _ll_var (le) = clib_llist_prev (LP,name,H); \
275 typeof (LP) _ll_var (ne) = clib_llist_next (LP,name,P); \
276 _lprev (_ll_var (fe),name) = clib_llist_entry_index(LP,P); \
277 _lnext (_ll_var (le),name) = clib_llist_entry_index(LP,_ll_var (ne));\
278 _lnext (P,name) = clib_llist_entry_index (LP,_ll_var (fe)); \
279 _lprev (_ll_var (ne),name) = clib_llist_entry_index(LP,_ll_var (le));\
280 _lnext (H,name) = clib_llist_entry_index(LP,H); \
281 _lprev (H,name) = _lnext (H,name); \
282 } \
283} while (0)
284/**
285 * Walk list starting at head
286 *
287 * @param LP linked list pool
288 * @param name list anchor name
289 * @param H head entry
290 * @param E entry iterator
291 * @param body code to be executed
292 */
293#define clib_llist_foreach(LP,name,H,E,body) \
294do { \
295 typeof (LP) _ll_var (n); \
296 (E) = clib_llist_next (LP,name,H); \
297 while (E != H) \
298 { \
299 _ll_var (n) = clib_llist_next (LP,name,E); \
300 do { body; } while (0); \
301 (E) = _ll_var (n); \
302 } \
303} while (0)
304/**
Florin Corasb0ffbee2019-07-21 19:23:46 -0700305 * Walk list starting at head safe
306 *
307 * @param LP linked list pool
308 * @param name list anchor name
309 * @param HI head index
310 * @param EI entry index iterator
311 * @param body code to be executed
312 */
313#define clib_llist_foreach_safe(LP,name,H,E,body) \
314do { \
315 clib_llist_index_t _ll_var (HI) = clib_llist_entry_index (LP, H); \
316 clib_llist_index_t _ll_var (EI), _ll_var (NI); \
317 _ll_var (EI) = _lnext ((H),name); \
318 while (_ll_var (EI) != _ll_var (HI)) \
319 { \
320 (E) = pool_elt_at_index (LP, _ll_var (EI)); \
321 _ll_var (NI) = _lnext ((E),name); \
322 do { body; } while (0); \
323 _ll_var (EI) = _ll_var (NI); \
324 } \
325} while (0)
326/**
Florin Corasb957d802019-07-09 19:02:33 -0700327 * Walk list starting at head in reverse order
328 *
329 * @param LP linked list pool
330 * @param name list anchor name
331 * @param H head entry
332 * @param E entry iterator
333 * @param body code to be executed
334 */
335#define clib_llist_foreach_reverse(LP,name,H,E,body) \
336do { \
337 typeof (LP) _ll_var (p); \
338 (E) = clib_llist_prev (LP,name,H); \
339 while (E != H) \
340 { \
341 _ll_var (p) = clib_llist_prev (LP,name,E); \
342 do { body; } while (0); \
343 (E) = _ll_var (p); \
344 } \
345} while (0)
346
347#endif /* SRC_VPPINFRA_CLIB_LLIST_H_ */
348
349/*
350 * fd.io coding-style-patch-verification: ON
351 *
352 * Local Variables:
353 * eval: (c-set-style "gnu")
354 * End:
355 */