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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
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.
21 #ifndef SRC_VPPINFRA_CLIB_LLIST_H_
22 #define SRC_VPPINFRA_CLIB_LLIST_H_
24 #include <vppinfra/types.h>
25 #include <vppinfra/pool.h>
27 typedef u32 clib_llist_index_t;
29 typedef struct clib_llist_anchor
31 clib_llist_index_t prev;
32 clib_llist_index_t next;
33 } clib_llist_anchor_t;
35 #define CLIB_LLIST_INVALID_INDEX ((u32)~0)
38 * Local variable naming macro.
40 #define _ll_var(v) _llist_##v
42 * Local macros to grab llist anchor next and prev from pool entry
44 #define _lnext(E,name) ((E)->name).next
45 #define _lprev(E,name) ((E)->name).prev
47 * Get list entry index
49 * @param LP linked list pool
51 * @return pool entry index
53 #define clib_llist_entry_index(LP,E) ((E) - (LP))
57 * @param LP linked list pool
58 * @param name list anchor name
60 * @return next pool entry
62 #define clib_llist_next(LP,name,E) pool_elt_at_index((LP),_lnext((E),name))
64 * Get previous pool entry
66 * @param LP linked list pool
67 * @param name list anchor name
69 * @return previous pool entry
71 #define clib_llist_prev(LP,name,E) pool_elt_at_index((LP),_lprev((E),name))
73 * Initialize element in llist for entry
75 * @param LP linked list pool
76 * @param name list anchor name
77 * @param E entry whose ll anchor is to be initialized
79 #define clib_llist_anchor_init(LP,name,E) \
81 _lprev ((E),name) = clib_llist_entry_index ((LP), (E)); \
82 _lnext ((E),name) = _lprev ((E),name); \
85 * Initialize llist head
87 * @param LP linked list pool
88 * @param name list anchor name
90 #define clib_llist_make_head(LP,name) \
92 typeof (LP) _ll_var (head); \
93 pool_get_zero ((LP), _ll_var (head)); \
94 clib_llist_anchor_init ((LP),name,_ll_var (head)); \
95 clib_llist_entry_index ((LP), _ll_var (head)); \
98 * Check is list is empty
100 * @param LP linked list pool
101 * @param name list anchor name
103 * @return 1 if sentinel is the only node part of the list, 0 otherwise
105 #define clib_llist_is_empty(LP,name,H) ((H) == clib_llist_next((LP),name,(H)))
107 * Insert entry between previous and next
111 * @param LP linked list pool
112 * @param name list anchor name
114 * @param P previous in list
115 * @param N next in list
117 #define _llist_insert(LP,name,E,P,N) \
119 _lprev (E,name) = _lprev(N,name); \
120 _lnext (E,name) = _lnext(P,name); \
121 _lprev ((N),name) = clib_llist_entry_index ((LP),(E)); \
122 _lnext ((P),name) = clib_llist_entry_index ((LP),(E)); \
125 * Insert entry after previous
127 * @param LP linked list pool
128 * @param name list anchor name
130 * @param P previous in list
132 #define clib_llist_insert(LP,name,E,P) \
134 typeof (LP) _ll_var (N) = clib_llist_next (LP,name,P); \
135 _llist_insert ((LP),name,(E),(P), _ll_var (N)); \
139 * Add entry after head
141 * @param LP linked list pool
142 * @param name list anchor name
146 #define clib_llist_add(LP,name,E,H) clib_llist_insert ((LP),name,(E),(H))
148 * Add entry after tail
150 * @param LP linked list pool
151 * @param name list anchor name
155 #define clib_llist_add_tail(LP,name,E,H) \
157 typeof (LP) _ll_var (P) = clib_llist_prev ((LP),name,(H)); \
158 _llist_insert ((LP),name,(E),_ll_var (P),(H)); \
161 * Remove entry from list
163 * @param LP linked list pool
164 * @param name list anchor name
165 * @param E entry to be removed
167 #define clib_llist_remove(LP,name,E) \
169 ASSERT ((E) != clib_llist_next (LP,name,E));/* don't remove sentinel */\
170 ASSERT (_lnext (E,name) != CLIB_LLIST_INVALID_INDEX); \
171 ASSERT (_lprev (E,name) != CLIB_LLIST_INVALID_INDEX); \
172 typeof (LP) _ll_var (P) = clib_llist_prev ((LP),name,E); \
173 typeof (LP) _ll_var (N) = clib_llist_next ((LP),name,E); \
174 _lnext (_ll_var (P),name) = _lnext (E,name); \
175 _lprev (_ll_var (N),name) = _lprev (E,name); \
176 _lnext (E,name) = _lprev (E,name) = CLIB_LLIST_INVALID_INDEX; \
180 * Splice two lists at a given position
182 * List spliced into destination list is left with 0 entries, i.e., head
183 * is made to point to itself.
185 * @param LP linked list pool
186 * @param name list anchor name
187 * @param P position in destination where source list is spliced
188 * @param H head of source list that will be spliced into destination
190 #define clib_llist_splice(LP,name,P,H) \
192 typeof (LP) _ll_var (fe) = clib_llist_next (LP,name,H); \
193 if (_ll_var (fe) != (H)) \
195 typeof (LP) _ll_var (le) = clib_llist_prev (LP,name,H); \
196 typeof (LP) _ll_var (ne) = clib_llist_next (LP,name,P); \
197 _lprev (_ll_var (fe),name) = clib_llist_entry_index(LP,P); \
198 _lnext (_ll_var (le),name) = clib_llist_entry_index(LP,_ll_var (ne));\
199 _lnext (P,name) = clib_llist_entry_index (LP,_ll_var (fe)); \
200 _lprev (_ll_var (ne),name) = clib_llist_entry_index(LP,_ll_var (le));\
201 _lnext (H,name) = clib_llist_entry_index(LP,H); \
202 _lprev (H,name) = _lnext (H,name); \
206 * Walk list starting at head
208 * @param LP linked list pool
209 * @param name list anchor name
210 * @param H head entry
211 * @param E entry iterator
212 * @param body code to be executed
214 #define clib_llist_foreach(LP,name,H,E,body) \
216 typeof (LP) _ll_var (n); \
217 (E) = clib_llist_next (LP,name,H); \
220 _ll_var (n) = clib_llist_next (LP,name,E); \
221 do { body; } while (0); \
226 * Walk list starting at head in reverse order
228 * @param LP linked list pool
229 * @param name list anchor name
230 * @param H head entry
231 * @param E entry iterator
232 * @param body code to be executed
234 #define clib_llist_foreach_reverse(LP,name,H,E,body) \
236 typeof (LP) _ll_var (p); \
237 (E) = clib_llist_prev (LP,name,H); \
240 _ll_var (p) = clib_llist_prev (LP,name,E); \
241 do { body; } while (0); \
246 #endif /* SRC_VPPINFRA_CLIB_LLIST_H_ */
249 * fd.io coding-style-patch-verification: ON
252 * eval: (c-set-style "gnu")