blob: e90c27c1bc1118dcfd995a5aee4a38837498591c [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
2 * Copyright (c) 2015 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/*
16 Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus
17
18 Permission is hereby granted, free of charge, to any person obtaining
19 a copy of this software and associated documentation files (the
20 "Software"), to deal in the Software without restriction, including
21 without limitation the rights to use, copy, modify, merge, publish,
22 distribute, sublicense, and/or sell copies of the Software, and to
23 permit persons to whom the Software is furnished to do so, subject to
24 the following conditions:
25
26 The above copyright notice and this permission notice shall be
27 included in all copies or substantial portions of the Software.
28
29 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
30 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
31 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
32 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
33 LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
34 OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
35 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36*/
37
38#ifndef included_vec_h
39#define included_vec_h
40
Dave Barachc3799992016-08-15 11:12:27 -040041#include <vppinfra/clib.h> /* word, etc */
42#include <vppinfra/mem.h> /* clib_mem_free */
Ed Warnickecb9cada2015-12-08 15:45:58 -070043#include <vppinfra/string.h> /* memcpy, memmove */
44#include <vppinfra/vec_bootstrap.h>
45
46/** \file
47
48 CLIB vectors are ubiquitous dynamically resized arrays with by user
49 defined "headers". Many CLIB data structures (e.g. hash, heap,
50 pool) are vectors with various different headers.
51
52 The memory layout looks like this:
53
54~~~~~~~~
Damjan Marion299571a2022-03-19 00:07:52 +010055 user header (start of memory allocation)
56 padding
57 vector header: number of elements, header size
Ed Warnickecb9cada2015-12-08 15:45:58 -070058 user's pointer-> vector element #0
Damjan Marion299571a2022-03-19 00:07:52 +010059 vector element #1
60 ...
Ed Warnickecb9cada2015-12-08 15:45:58 -070061~~~~~~~~
62
Dave Barach2bc1eba2016-01-19 15:10:27 -050063 The user pointer contains the address of vector element # 0. Null
Dave Barachc3799992016-08-15 11:12:27 -040064 pointer vectors are valid and mean a zero length vector.
Dave Barach2bc1eba2016-01-19 15:10:27 -050065
66 You can reset the length of an allocated vector to zero via the
67 vec_reset_length(v) macro, or by setting the vector length field to
68 zero (e.g. _vec_len (v) = 0). Vec_reset_length(v) preferred: it
69 understands Null pointers.
Ed Warnickecb9cada2015-12-08 15:45:58 -070070
71 Typically, the header is not present. Headers allow for other
72 data structures to be built atop CLIB vectors.
73
Damjan Marion299571a2022-03-19 00:07:52 +010074 While users may specify the alignment for first data element of a vector
75 via the vec_*_aligned macros that is typically not needed as alignment
76 is set based on native alignment of the data structure used.
Ed Warnickecb9cada2015-12-08 15:45:58 -070077
Dave Wallace4659d0e2018-12-13 12:29:44 -050078 Vector elements can be any C type e.g. (int, double, struct bar).
Ed Warnickecb9cada2015-12-08 15:45:58 -070079 This is also true for data types built atop vectors (e.g. heap,
80 pool, etc.).
81
Dave Wallace4659d0e2018-12-13 12:29:44 -050082 Many macros have \_a variants supporting alignment of vector elements
83 and \_h variants supporting non-zero-length vector headers. The \_ha
84 variants support both. Additionally cacheline alignment within a
85 vector element structure can be specified using the
86 CLIB_CACHE_LINE_ALIGN_MARK() macro.
Ed Warnickecb9cada2015-12-08 15:45:58 -070087
Dave Barachc3799992016-08-15 11:12:27 -040088 Standard programming error: memorize a pointer to the ith element
Ed Warnickecb9cada2015-12-08 15:45:58 -070089 of a vector then expand it. Vectors expand by 3/2, so such code
90 may appear to work for a period of time. Memorize vector indices
Dave Barachc3799992016-08-15 11:12:27 -040091 which are invariant.
Ed Warnickecb9cada2015-12-08 15:45:58 -070092 */
93
Damjan Marion299571a2022-03-19 00:07:52 +010094/** \brief Low-level (re)allocation function, usually not called directly
Ed Warnickecb9cada2015-12-08 15:45:58 -070095
96 @param v pointer to a vector
Damjan Marion299571a2022-03-19 00:07:52 +010097 @param n_elts requested number of elements
98 @param elt_sz requested size of one element
99 @param hdr_sz header size in bytes (may be zero)
100 @param align alignment (may be zero)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700101 @return v_prime pointer to resized vector, may or may not equal v
102*/
Damjan Marion299571a2022-03-19 00:07:52 +0100103void *_vec_realloc (void *v, uword n_elts, uword elt_sz, uword hdr_sz,
104 uword align, void *heap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700105
Damjan Marion299571a2022-03-19 00:07:52 +0100106/* calculate minimum alignment out of data natural alignment and provided
107 * value, should not be < VEC_MIN_ALIGN */
108static_always_inline uword
109__vec_align (uword data_align, uword configuered_align)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700110{
Damjan Marion299571a2022-03-19 00:07:52 +0100111 data_align = clib_max (data_align, configuered_align);
112 ASSERT (count_set_bits (data_align) == 1);
113 return clib_max (VEC_MIN_ALIGN, data_align);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700114}
115
Damjan Marion299571a2022-03-19 00:07:52 +0100116/* function used t o catch cases where vec_* macros on used on void * */
117static_always_inline uword
118__vec_elt_sz (uword elt_sz, int is_void)
119{
120 /* vector macro operations on void * are not allowed */
121 ASSERT (is_void == 0);
122 return elt_sz;
123}
Dave Barach614ac5d2017-02-06 09:28:03 -0500124
Damjan Marion299571a2022-03-19 00:07:52 +0100125static_always_inline void
126_vec_update_pointer (void **vp, void *v)
127{
128 /* avoid store if not needed */
129 if (v != vp[0])
130 vp[0] = v;
131}
Dave Barach614ac5d2017-02-06 09:28:03 -0500132
Damjan Marion299571a2022-03-19 00:07:52 +0100133always_inline void *
134_vec_realloc_inline (void *v, uword n_elts, uword elt_sz, uword hdr_sz,
135 uword align, void *heap)
Dave Barach614ac5d2017-02-06 09:28:03 -0500136{
Dave Barach614ac5d2017-02-06 09:28:03 -0500137 if (PREDICT_TRUE (v != 0))
138 {
Dave Barach614ac5d2017-02-06 09:28:03 -0500139 /* Vector header must start heap object. */
Damjan Marion66d4cb52022-03-17 18:59:46 +0100140 ASSERT (clib_mem_is_heap_object (vec_header (v)));
Dave Barach614ac5d2017-02-06 09:28:03 -0500141
Damjan Marion299571a2022-03-19 00:07:52 +0100142 /* Typically we'll not need to resize. */
143 if ((n_elts * elt_sz) <= vec_max_bytes (v))
144 {
145 _vec_set_len (v, n_elts, elt_sz);
146 return v;
147 }
Dave Barach614ac5d2017-02-06 09:28:03 -0500148 }
Damjan Marion299571a2022-03-19 00:07:52 +0100149
150 /* Slow path: call helper function. */
151 return _vec_realloc (v, n_elts, elt_sz, hdr_sz, align, heap);
152}
153
154always_inline int
155_vec_resize_will_expand (void *v, uword n_elts, uword elt_sz)
156{
157 if (v == 0)
158 return 1;
159
160 /* Vector header must start heap object. */
161 ASSERT (clib_mem_is_heap_object (vec_header (v)));
162
163 n_elts += _vec_len (v);
164 if ((n_elts * elt_sz) <= vec_max_bytes (v))
165 return 0;
166
Dave Barach614ac5d2017-02-06 09:28:03 -0500167 return 1;
168}
169
Miklos Tirpake700df82021-01-13 10:00:38 +0100170/** \brief Determine if vector will resize with next allocation
171
172 @param V pointer to a vector
173 @param N number of elements to add
174 @return 1 if vector will resize 0 otherwise
175*/
176
177#define vec_resize_will_expand(V, N) \
Damjan Marion299571a2022-03-19 00:07:52 +0100178 _vec_resize_will_expand (V, N, _vec_elt_sz (V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700179
Ed Warnickecb9cada2015-12-08 15:45:58 -0700180/* Local variable naming macro (prevents collisions with other macro naming). */
181#define _v(var) _vec_##var
182
183/** \brief Resize a vector (general version).
184 Add N elements to end of given vector V, return pointer to start of vector.
185 Vector will have room for H header bytes and will have user's data aligned
186 at alignment A (rounded to next power of 2).
187
188 @param V pointer to a vector
189 @param N number of elements to add
190 @param H header size in bytes (may be zero)
191 @param A alignment (may be zero)
192 @return V (value-result macro parameter)
193*/
194
Damjan Marion299571a2022-03-19 00:07:52 +0100195static_always_inline void
196_vec_resize (void **vp, uword n_add, uword hdr_sz, uword align, uword elt_sz)
197{
198 void *v = vp[0];
199 v = _vec_realloc_inline (v, vec_len (v) + n_add, elt_sz, hdr_sz, align, 0);
200 _vec_update_pointer (vp, v);
201}
202
Damjan Marion3cfd5292022-03-18 15:48:12 +0100203#define vec_resize_ha(V, N, H, A) \
Damjan Marion299571a2022-03-19 00:07:52 +0100204 _vec_resize ((void **) &(V), N, H, _vec_align (V, A), _vec_elt_sz (V))
Dave Baracha690fdb2020-01-21 12:34:55 -0500205
Ed Warnickecb9cada2015-12-08 15:45:58 -0700206/** \brief Resize a vector (no header, unspecified alignment)
207 Add N elements to end of given vector V, return pointer to start of vector.
208 Vector will have room for H header bytes and will have user's data aligned
209 at alignment A (rounded to next power of 2).
210
211 @param V pointer to a vector
212 @param N number of elements to add
213 @return V (value-result macro parameter)
214*/
215#define vec_resize(V,N) vec_resize_ha(V,N,0,0)
216
217/** \brief Resize a vector (no header, alignment specified).
218 Add N elements to end of given vector V, return pointer to start of vector.
219 Vector will have room for H header bytes and will have user's data aligned
220 at alignment A (rounded to next power of 2).
221
222 @param V pointer to a vector
223 @param N number of elements to add
224 @param A alignment (may be zero)
225 @return V (value-result macro parameter)
226*/
227
228#define vec_resize_aligned(V,N,A) vec_resize_ha(V,N,0,A)
229
Dave Barachc3799992016-08-15 11:12:27 -0400230/** \brief Allocate space for N more elements
Ed Warnickecb9cada2015-12-08 15:45:58 -0700231
232 @param V pointer to a vector
233 @param N number of elements to add
234 @param H header size in bytes (may be zero)
235 @param A alignment (may be zero)
236 @return V (value-result macro parameter)
237*/
238
Damjan Marion299571a2022-03-19 00:07:52 +0100239#define vec_alloc_ha(V, N, H, A) \
240 do \
241 { \
242 uword _v (l) = vec_len (V); \
243 vec_resize_ha (V, N, H, A); \
244 vec_set_len (V, _v (l)); \
245 } \
246 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700247
Dave Barachc3799992016-08-15 11:12:27 -0400248/** \brief Allocate space for N more elements
249 (no header, unspecified alignment)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700250
251 @param V pointer to a vector
252 @param N number of elements to add
253 @return V (value-result macro parameter)
254*/
255#define vec_alloc(V,N) vec_alloc_ha(V,N,0,0)
256
257/** \brief Allocate space for N more elements (no header, given alignment)
258 @param V pointer to a vector
259 @param N number of elements to add
260 @param A alignment (may be zero)
261 @return V (value-result macro parameter)
262*/
263
264#define vec_alloc_aligned(V,N,A) vec_alloc_ha(V,N,0,A)
265
266/** \brief Create new vector of given type and length (general version).
267 @param T type of elements in new vector
268 @param N number of elements to add
269 @param H header size in bytes (may be zero)
270 @param A alignment (may be zero)
271 @return V new vector
272*/
Damjan Marion299571a2022-03-19 00:07:52 +0100273#define vec_new_ha(T, N, H, A) \
274 _vec_realloc (0, N, sizeof (T), H, _vec_align ((T *) 0, A), 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700275
Dave Barachc3799992016-08-15 11:12:27 -0400276/** \brief Create new vector of given type and length
Ed Warnickecb9cada2015-12-08 15:45:58 -0700277 (unspecified alignment, no header).
278
279 @param T type of elements in new vector
280 @param N number of elements to add
281 @return V new vector
282*/
283#define vec_new(T,N) vec_new_ha(T,N,0,0)
Dave Barachc3799992016-08-15 11:12:27 -0400284/** \brief Create new vector of given type and length
285 (alignment specified, no header).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700286
287 @param T type of elements in new vector
288 @param N number of elements to add
289 @param A alignment (may be zero)
290 @return V new vector
291*/
292#define vec_new_aligned(T,N,A) vec_new_ha(T,N,0,A)
293
Damjan Marion05563c92022-03-17 18:29:32 +0100294/** \brief Free vector's memory (no header).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700295 @param V pointer to a vector
Ed Warnickecb9cada2015-12-08 15:45:58 -0700296 @return V (value-result parameter, V=0)
297*/
Damjan Marion299571a2022-03-19 00:07:52 +0100298
299static_always_inline void
300_vec_free (void **vp)
301{
302 if (vp[0] == 0)
303 return;
304 clib_mem_free (vec_header (vp[0]));
305 vp[0] = 0;
306}
307
308#define vec_free(V) _vec_free ((void **) &(V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700309
Dave Barache09ae012020-08-19 06:59:53 -0400310void vec_free_not_inline (void *v);
311
Ed Warnickecb9cada2015-12-08 15:45:58 -0700312/**\brief Free vector user header (syntactic sugar)
313 @param h vector header
314 @void
315*/
316#define vec_free_header(h) clib_mem_free (h)
317
318/** \brief Return copy of vector (general version).
319
320 @param V pointer to a vector
321 @param H size of header in bytes
322 @param A alignment (may be zero)
323
324 @return Vdup copy of vector
325*/
326
Damjan Marion299571a2022-03-19 00:07:52 +0100327static_always_inline void *
328_vec_dup (void *v, uword hdr_size, uword align, uword elt_sz)
329{
330 uword len = vec_len (v);
331 void *n = 0;
332
333 if (len)
334 {
335 n = _vec_realloc (0, len, elt_sz, hdr_size, align, 0);
336 clib_memcpy_fast (n, v, len * elt_sz);
337 }
338 return n;
339}
340
Damjan Marion3cfd5292022-03-18 15:48:12 +0100341#define vec_dup_ha(V, H, A) \
Damjan Marion299571a2022-03-19 00:07:52 +0100342 _vec_dup ((void *) (V), H, _vec_align (V, A), _vec_elt_sz (V))
Dave Baracha690fdb2020-01-21 12:34:55 -0500343
Ed Warnickecb9cada2015-12-08 15:45:58 -0700344/** \brief Return copy of vector (no header, no alignment)
345
346 @param V pointer to a vector
347 @return Vdup copy of vector
348*/
349#define vec_dup(V) vec_dup_ha(V,0,0)
350
351/** \brief Return copy of vector (no header, alignment specified).
352
353 @param V pointer to a vector
354 @param A alignment (may be zero)
355
356 @return Vdup copy of vector
357*/
358#define vec_dup_aligned(V,A) vec_dup_ha(V,0,A)
359
360/** \brief Copy a vector, memcpy wrapper. Assumes sizeof(SRC[0]) ==
361 sizeof(DST[0])
362
Dave Barachc3799992016-08-15 11:12:27 -0400363 @param DST destination
Ed Warnickecb9cada2015-12-08 15:45:58 -0700364 @param SRC source
365*/
Dave Barach178cf492018-11-13 16:34:13 -0500366#define vec_copy(DST,SRC) clib_memcpy_fast (DST, SRC, vec_len (DST) * \
Damjan Marionf1213b82016-03-13 02:22:06 +0100367 sizeof ((DST)[0]))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368
Dave Barachc3799992016-08-15 11:12:27 -0400369/** \brief Clone a vector. Make a new vector with the
Ed Warnickecb9cada2015-12-08 15:45:58 -0700370 same size as a given vector but possibly with a different type.
371
372 @param NEW_V pointer to new vector
373 @param OLD_V pointer to old vector
374*/
Damjan Marion299571a2022-03-19 00:07:52 +0100375
376static_always_inline void
377_vec_clone (void **v1p, void *v2, uword align, uword elt_sz)
378{
379 v1p[0] = _vec_realloc (0, vec_len (v2), elt_sz, 0, align, 0);
380}
381#define vec_clone(NEW_V, OLD_V) \
382 _vec_clone ((void **) &(NEW_V), OLD_V, _vec_align (NEW_V, 0), \
383 _vec_elt_sz (NEW_V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700384
385/** \brief Make sure vector is long enough for given index (general version).
386
Dave Barachc3799992016-08-15 11:12:27 -0400387 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700388 @param I vector index which will be valid upon return
389 @param H header size in bytes (may be zero)
390 @param A alignment (may be zero)
391 @return V (value-result macro parameter)
392*/
393
Damjan Marion299571a2022-03-19 00:07:52 +0100394always_inline void
395_vec_zero_elts (void *v, uword first, uword count, uword elt_sz)
396{
397 clib_memset_u8 (v + (first * elt_sz), 0, count * elt_sz);
398}
399#define vec_zero_elts(V, F, C) _vec_zero_elts (V, F, C, sizeof ((V)[0]))
400
401static_always_inline void *
402_vec_validate_ha (void *v, uword index, uword header_size, uword align,
403 uword elt_sz)
404{
405 uword vl = vec_len (v);
406 if (index >= vl)
407 {
408 v = _vec_realloc_inline (v, index + 1, elt_sz, header_size, align, 0);
409 _vec_zero_elts (v, vl, index - vl + 1, elt_sz);
410 }
411 return v;
412}
413
Damjan Marion3cfd5292022-03-18 15:48:12 +0100414#define vec_validate_ha(V, I, H, A) \
Damjan Marion299571a2022-03-19 00:07:52 +0100415 (V) = \
416 _vec_validate_ha ((void *) (V), I, H, _vec_align (V, A), sizeof ((V)[0]))
Dave Baracha690fdb2020-01-21 12:34:55 -0500417
Dave Barachc3799992016-08-15 11:12:27 -0400418/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700419 (no header, unspecified alignment)
420
Dave Barachc3799992016-08-15 11:12:27 -0400421 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700422 @param I vector index which will be valid upon return
423 @return V (value-result macro parameter)
424*/
425#define vec_validate(V,I) vec_validate_ha(V,I,0,0)
426
Dave Barachc3799992016-08-15 11:12:27 -0400427/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700428 (no header, specified alignment)
429
Dave Barachc3799992016-08-15 11:12:27 -0400430 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700431 @param I vector index which will be valid upon return
432 @param A alignment (may be zero)
433 @return V (value-result macro parameter)
434*/
435
436#define vec_validate_aligned(V,I,A) vec_validate_ha(V,I,0,A)
437
Dave Barachc3799992016-08-15 11:12:27 -0400438/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700439 and initialize empty space (general version)
440
Dave Barachc3799992016-08-15 11:12:27 -0400441 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700442 @param I vector index which will be valid upon return
443 @param INIT initial value (can be a complex expression!)
444 @param H header size in bytes (may be zero)
445 @param A alignment (may be zero)
446 @return V (value-result macro parameter)
447*/
Damjan Marion299571a2022-03-19 00:07:52 +0100448#define vec_validate_init_empty_ha(V, I, INIT, H, A) \
449 do \
450 { \
451 word _v (i) = (I); \
452 word _v (l) = vec_len (V); \
453 if (_v (i) >= _v (l)) \
454 { \
455 vec_resize_ha (V, 1 + (_v (i) - _v (l)), H, A); \
456 while (_v (l) <= _v (i)) \
457 { \
458 (V)[_v (l)] = (INIT); \
459 _v (l)++; \
460 } \
461 } \
462 } \
463 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700464
Dave Barachc3799992016-08-15 11:12:27 -0400465/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700466 and initialize empty space (no header, unspecified alignment)
467
Dave Barachc3799992016-08-15 11:12:27 -0400468 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700469 @param I vector index which will be valid upon return
470 @param INIT initial value (can be a complex expression!)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700471 @return V (value-result macro parameter)
472*/
473
474#define vec_validate_init_empty(V,I,INIT) \
475 vec_validate_init_empty_ha(V,I,INIT,0,0)
476
Dave Barachc3799992016-08-15 11:12:27 -0400477/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700478 and initialize empty space (no header, alignment alignment)
479
Dave Barachc3799992016-08-15 11:12:27 -0400480 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700481 @param I vector index which will be valid upon return
482 @param INIT initial value (can be a complex expression!)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700483 @param A alignment (may be zero)
484 @return V (value-result macro parameter)
485*/
Damjan Marion7d272182017-06-05 21:53:39 +0200486#define vec_validate_init_empty_aligned(V,I,INIT,A) \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700487 vec_validate_init_empty_ha(V,I,INIT,0,A)
488
Dave Barachc3799992016-08-15 11:12:27 -0400489/** \brief Add 1 element to end of vector (general version).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490
491 @param V pointer to a vector
492 @param E element to add
493 @param H header size in bytes (may be zero)
494 @param A alignment (may be zero)
495 @return V (value-result macro parameter)
496*/
Damjan Marion299571a2022-03-19 00:07:52 +0100497
498static_always_inline void *
499_vec_add1 (void **vp, uword hdr_sz, uword align, uword elt_sz)
500{
501 void *v = vp[0];
502 uword len = vec_len (v);
503 v = _vec_realloc_inline (v, len + 1, elt_sz, hdr_sz, align, 0);
504
505 _vec_update_pointer (vp, v);
506
507 return v + len * elt_sz;
508}
509
510#define vec_add1_ha(V, E, H, A) \
511 ((__typeof__ ((V)[0]) *) _vec_add1 ((void **) &(V), H, _vec_align (V, A), \
512 _vec_elt_sz (V)))[0] = (E)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700513
Dave Barachc3799992016-08-15 11:12:27 -0400514/** \brief Add 1 element to end of vector (unspecified alignment).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515
516 @param V pointer to a vector
517 @param E element to add
518 @return V (value-result macro parameter)
519*/
520#define vec_add1(V,E) vec_add1_ha(V,E,0,0)
521
Dave Barachc3799992016-08-15 11:12:27 -0400522/** \brief Add 1 element to end of vector (alignment specified).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700523
524 @param V pointer to a vector
525 @param E element to add
Ed Warnickecb9cada2015-12-08 15:45:58 -0700526 @param A alignment (may be zero)
527 @return V (value-result macro parameter)
528*/
529#define vec_add1_aligned(V,E,A) vec_add1_ha(V,E,0,A)
530
Dave Barachc3799992016-08-15 11:12:27 -0400531/** \brief Add N elements to end of vector V,
532 return pointer to new elements in P. (general version)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700533
534 @param V pointer to a vector
535 @param P pointer to new vector element(s)
536 @param N number of elements to add
537 @param H header size in bytes (may be zero)
538 @param A alignment (may be zero)
539 @return V and P (value-result macro parameters)
540*/
Damjan Marion299571a2022-03-19 00:07:52 +0100541
542static_always_inline void
543_vec_add2 (void **vp, void **pp, uword n_add, uword hdr_sz, uword align,
544 uword elt_sz)
545{
546 void *v = vp[0];
547 uword len = vec_len (vp[0]);
548 v = _vec_realloc_inline (v, len + n_add, elt_sz, hdr_sz, align, 0);
549 _vec_update_pointer (vp, v);
550 pp[0] = v + len * elt_sz;
551}
552
553#define vec_add2_ha(V, P, N, H, A) \
554 _vec_add2 ((void **) &(V), (void **) &(P), N, H, _vec_align (V, A), \
555 _vec_elt_sz (V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700556
Dave Barachc3799992016-08-15 11:12:27 -0400557/** \brief Add N elements to end of vector V,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700558 return pointer to new elements in P. (no header, unspecified alignment)
559
560 @param V pointer to a vector
561 @param P pointer to new vector element(s)
562 @param N number of elements to add
563 @return V and P (value-result macro parameters)
564*/
565
566#define vec_add2(V,P,N) vec_add2_ha(V,P,N,0,0)
567
Dave Barachc3799992016-08-15 11:12:27 -0400568/** \brief Add N elements to end of vector V,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700569 return pointer to new elements in P. (no header, alignment specified)
570
571 @param V pointer to a vector
572 @param P pointer to new vector element(s)
573 @param N number of elements to add
574 @param A alignment (may be zero)
575 @return V and P (value-result macro parameters)
576*/
577
578#define vec_add2_aligned(V,P,N,A) vec_add2_ha(V,P,N,0,A)
579
Dave Barachc3799992016-08-15 11:12:27 -0400580/** \brief Add N elements to end of vector V (general version)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700581
582 @param V pointer to a vector
583 @param E pointer to element(s) to add
584 @param N number of elements to add
585 @param H header size in bytes (may be zero)
586 @param A alignment (may be zero)
587 @return V (value-result macro parameter)
588*/
Damjan Marion299571a2022-03-19 00:07:52 +0100589static_always_inline void
590_vec_add (void **vp, void *e, word n_add, uword hdr_sz, uword align,
591 uword elt_sz)
592{
593 void *v = vp[0];
594 uword len = vec_len (v);
595
596 ASSERT (n_add >= 0);
597
598 if (n_add < 1)
599 return;
600
601 v = _vec_realloc_inline (v, len + n_add, elt_sz, hdr_sz, align, 0);
602 clib_memcpy_fast (v + len * elt_sz, e, n_add * elt_sz);
603 _vec_update_pointer (vp, v);
604}
605
Benoît Ganne1a3e08a2021-02-11 19:46:43 +0100606#define vec_add_ha(V, E, N, H, A) \
Damjan Marion299571a2022-03-19 00:07:52 +0100607 _vec_add ((void **) &(V), (void *) (E), N, H, _vec_align (V, A), \
608 _vec_elt_sz (V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700609
610/** \brief Add N elements to end of vector V (no header, unspecified alignment)
611
612 @param V pointer to a vector
613 @param E pointer to element(s) to add
614 @param N number of elements to add
615 @return V (value-result macro parameter)
616*/
617#define vec_add(V,E,N) vec_add_ha(V,E,N,0,0)
618
619/** \brief Add N elements to end of vector V (no header, specified alignment)
620
621 @param V pointer to a vector
622 @param E pointer to element(s) to add
623 @param N number of elements to add
624 @param A alignment (may be zero)
625 @return V (value-result macro parameter)
626*/
627#define vec_add_aligned(V,E,N,A) vec_add_ha(V,E,N,0,A)
628
Dave Barachc3799992016-08-15 11:12:27 -0400629/** \brief Returns last element of a vector and decrements its length
Ed Warnickecb9cada2015-12-08 15:45:58 -0700630
631 @param V pointer to a vector
632 @return E element removed from the end of the vector
633*/
Damjan Marion299571a2022-03-19 00:07:52 +0100634#define vec_pop(V) \
635 ({ \
636 uword _v (l) = vec_len (V); \
637 __typeof__ ((V)[0]) _v (rv); \
638 ASSERT (_v (l) > 0); \
639 _v (l) -= 1; \
640 _v (rv) = (V)[_v (l)]; \
641 vec_set_len (V, _v (l)); \
642 (_v (rv)); \
643 })
Ed Warnickecb9cada2015-12-08 15:45:58 -0700644
Dave Barachc3799992016-08-15 11:12:27 -0400645/** \brief Set E to the last element of a vector, decrement vector length
Ed Warnickecb9cada2015-12-08 15:45:58 -0700646 @param V pointer to a vector
647 @param E pointer to the last vector element
Dave Barachc3799992016-08-15 11:12:27 -0400648 @return E element removed from the end of the vector
Ed Warnickecb9cada2015-12-08 15:45:58 -0700649 (value-result macro parameter
650*/
651
652#define vec_pop2(V,E) \
653({ \
654 uword _v(l) = vec_len (V); \
655 if (_v(l) > 0) (E) = vec_pop (V); \
656 _v(l) > 0; \
657})
658
Dave Barachc3799992016-08-15 11:12:27 -0400659/** \brief Insert N vector elements starting at element M,
660 initialize new elements (general version).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700661
Dave Barachc3799992016-08-15 11:12:27 -0400662 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700663 @param N number of elements to insert
664 @param M insertion point
665 @param INIT initial value (can be a complex expression!)
666 @param H header size in bytes (may be zero)
667 @param A alignment (may be zero)
668 @return V (value-result macro parameter)
669*/
Damjan Marion299571a2022-03-19 00:07:52 +0100670
671static_always_inline void
672_vec_insert (void **vp, uword n_insert, uword ins_pt, u8 init, uword hdr_sz,
673 uword align, uword elt_sz)
674{
675 void *v = vp[0];
676 uword len = vec_len (v);
677
678 ASSERT (ins_pt <= len);
679
680 v = _vec_realloc_inline (v, len + n_insert, elt_sz, hdr_sz, align, 0);
681 clib_memmove (v + elt_sz * (ins_pt + n_insert), v + ins_pt * elt_sz,
682 (len - ins_pt) * elt_sz);
683 _vec_zero_elts (v, ins_pt, n_insert, elt_sz);
684 _vec_update_pointer (vp, v);
685}
686
687#define vec_insert_init_empty_ha(V, N, M, INIT, H, A) \
688 _vec_insert ((void **) &(V), N, M, INIT, H, _vec_align (V, A), \
689 _vec_elt_sz (V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700690
Dave Barachc3799992016-08-15 11:12:27 -0400691/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700692 initialize new elements to zero (general version)
693
Dave Barachc3799992016-08-15 11:12:27 -0400694 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700695 @param N number of elements to insert
696 @param M insertion point
697 @param H header size in bytes (may be zero)
698 @param A alignment (may be zero)
699 @return V (value-result macro parameter)
700*/
701#define vec_insert_ha(V,N,M,H,A) vec_insert_init_empty_ha(V,N,M,0,H,A)
702
Dave Barachc3799992016-08-15 11:12:27 -0400703/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700704 initialize new elements to zero (no header, unspecified alignment)
705
Dave Barachc3799992016-08-15 11:12:27 -0400706 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700707 @param N number of elements to insert
708 @param M insertion point
709 @return V (value-result macro parameter)
710*/
711#define vec_insert(V,N,M) vec_insert_ha(V,N,M,0,0)
712
Dave Barachc3799992016-08-15 11:12:27 -0400713/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700714 initialize new elements to zero (no header, alignment specified)
715
Dave Barachc3799992016-08-15 11:12:27 -0400716 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700717 @param N number of elements to insert
718 @param M insertion point
719 @param A alignment (may be zero)
720 @return V (value-result macro parameter)
721*/
722#define vec_insert_aligned(V,N,M,A) vec_insert_ha(V,N,M,0,A)
723
Dave Barachc3799992016-08-15 11:12:27 -0400724/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700725 initialize new elements (no header, unspecified alignment)
726
Dave Barachc3799992016-08-15 11:12:27 -0400727 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700728 @param N number of elements to insert
729 @param M insertion point
730 @param INIT initial value (can be a complex expression!)
731 @return V (value-result macro parameter)
732*/
733
734#define vec_insert_init_empty(V,N,M,INIT) \
735 vec_insert_init_empty_ha(V,N,M,INIT,0,0)
736/* Resize vector by N elements starting from element M, initialize new elements to INIT (alignment specified, no header). */
737
Dave Barachc3799992016-08-15 11:12:27 -0400738/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700739 initialize new elements (no header, specified alignment)
740
Dave Barachc3799992016-08-15 11:12:27 -0400741 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700742 @param N number of elements to insert
743 @param M insertion point
744 @param INIT initial value (can be a complex expression!)
745 @param A alignment (may be zero)
746 @return V (value-result macro parameter)
747*/
748#define vec_insert_init_empty_aligned(V,N,M,INIT,A) \
749 vec_insert_init_empty_ha(V,N,M,INIT,0,A)
750
Dave Barachc3799992016-08-15 11:12:27 -0400751/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700752 insert given elements (general version)
753
Dave Barachc3799992016-08-15 11:12:27 -0400754 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700755 @param E element(s) to insert
756 @param N number of elements to insert
757 @param M insertion point
758 @param H header size in bytes (may be zero)
759 @param A alignment (may be zero)
760 @return V (value-result macro parameter)
761*/
762
Damjan Marion299571a2022-03-19 00:07:52 +0100763static_always_inline void
764_vec_insert_elts (void **vp, void *e, uword n_insert, uword ins_pt,
765 uword hdr_sz, uword align, uword elt_sz)
766{
767 void *v = vp[0];
768 uword len = vec_len (v);
769
770 ASSERT (ins_pt <= len);
771
772 v = _vec_realloc_inline (v, len + n_insert, elt_sz, hdr_sz, align, 0);
773 clib_memmove (v + elt_sz * (ins_pt + n_insert), v + ins_pt * elt_sz,
774 (len - ins_pt) * elt_sz);
775 _vec_zero_elts (v, ins_pt, n_insert, elt_sz);
776 clib_memcpy_fast (v + ins_pt * elt_sz, e, n_insert * elt_sz);
777 _vec_update_pointer (vp, v);
778}
779
Benoît Ganne1a3e08a2021-02-11 19:46:43 +0100780#define vec_insert_elts_ha(V, E, N, M, H, A) \
Damjan Marion299571a2022-03-19 00:07:52 +0100781 _vec_insert_elts ((void **) &(V), E, N, M, H, _vec_align (V, A), \
782 _vec_elt_sz (V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700783
Dave Barachc3799992016-08-15 11:12:27 -0400784/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700785 insert given elements (no header, unspecified alignment)
786
Dave Barachc3799992016-08-15 11:12:27 -0400787 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700788 @param E element(s) to insert
789 @param N number of elements to insert
790 @param M insertion point
791 @return V (value-result macro parameter)
792*/
793#define vec_insert_elts(V,E,N,M) vec_insert_elts_ha(V,E,N,M,0,0)
794
Dave Barachc3799992016-08-15 11:12:27 -0400795/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700796 insert given elements (no header, specified alignment)
797
Dave Barachc3799992016-08-15 11:12:27 -0400798 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700799 @param E element(s) to insert
800 @param N number of elements to insert
801 @param M insertion point
802 @param A alignment (may be zero)
803 @return V (value-result macro parameter)
804*/
805#define vec_insert_elts_aligned(V,E,N,M,A) vec_insert_elts_ha(V,E,N,M,0,A)
806
Dave Barachc3799992016-08-15 11:12:27 -0400807/** \brief Delete N elements starting at element M
Ed Warnickecb9cada2015-12-08 15:45:58 -0700808
809 @param V pointer to a vector
810 @param N number of elements to delete
811 @param M first element to delete
812 @return V (value-result macro parameter)
813*/
Damjan Marion299571a2022-03-19 00:07:52 +0100814
815static_always_inline void
816_vec_delete (void *v, uword n_del, uword first, uword elt_sz)
817{
818 word n_bytes_del, n_bytes_to_move, len = vec_len (v);
819 u8 *dst;
820
821 if (n_del == 0)
822 return;
823
824 ASSERT (first + n_del <= len);
825
826 n_bytes_del = n_del * elt_sz;
827 n_bytes_to_move = (len - first - n_del) * elt_sz;
828 dst = v + first * elt_sz;
829
830 if (n_bytes_to_move > 0)
831 clib_memmove (dst, dst + n_bytes_del, n_bytes_to_move);
832 clib_memset (dst + n_bytes_to_move, 0, n_bytes_del);
833
834 _vec_set_len (v, _vec_len (v) - n_del, elt_sz);
835}
836
837#define vec_delete(V, N, M) _vec_delete ((void *) (V), N, M, _vec_elt_sz (V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700838
839/** \brief Delete the element at index I
840
841 @param V pointer to a vector
842 @param I index to delete
843*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700844
Damjan Marion299571a2022-03-19 00:07:52 +0100845static_always_inline void
846_vec_del1 (void *v, uword index, uword elt_sz)
847{
848 uword len = _vec_len (v) - 1;
Dave Barachc3799992016-08-15 11:12:27 -0400849
Damjan Marion299571a2022-03-19 00:07:52 +0100850 if (index < len)
851 clib_memcpy_fast (v + index * elt_sz, v + len * elt_sz, elt_sz);
852
853 _vec_set_len (v, len, elt_sz);
854}
855
856#define vec_del1(v, i) _vec_del1 ((void *) (v), i, _vec_elt_sz (v))
857
858static_always_inline void
859_vec_append (void **v1p, void *v2, uword v1_elt_sz, uword v2_elt_sz,
860 uword align)
861{
862 void *v1 = v1p[0];
863 uword len1 = vec_len (v1);
864 uword len2 = vec_len (v2);
865
866 if (PREDICT_TRUE (len2 > 0))
867 {
868 v1 = _vec_realloc_inline (v1, len1 + len2, v2_elt_sz, 0, align, 0);
869 clib_memcpy_fast (v1 + len1 * v1_elt_sz, v2, len2 * v2_elt_sz);
870 _vec_update_pointer (v1p, v1);
871 }
872}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700873
874/** \brief Append v2 after v1. Result in v1. Specified alignment.
875 @param V1 target vector
876 @param V2 vector to append
877 @param align required alignment
878*/
Dave Barachc3799992016-08-15 11:12:27 -0400879
Benoît Ganne1a3e08a2021-02-11 19:46:43 +0100880#define vec_append_aligned(v1, v2, align) \
Damjan Marion299571a2022-03-19 00:07:52 +0100881 _vec_append ((void **) &(v1), (void *) (v2), _vec_elt_sz (v1), \
882 _vec_elt_sz (v2), _vec_align (v1, align))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700883
Damjan Marion299571a2022-03-19 00:07:52 +0100884/** \brief Append v2 after v1. Result in v1.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700885 @param V1 target vector
Damjan Marion299571a2022-03-19 00:07:52 +0100886 @param V2 vector to append
Ed Warnickecb9cada2015-12-08 15:45:58 -0700887*/
888
Damjan Marion299571a2022-03-19 00:07:52 +0100889#define vec_append(v1, v2) vec_append_aligned (v1, v2, 0)
890
891static_always_inline void
892_vec_prepend (void **v1p, void *v2, uword v1_elt_sz, uword v2_elt_sz,
893 uword align)
894{
895 void *v1 = v1p[0];
896 uword len1 = vec_len (v1);
897 uword len2 = vec_len (v2);
898
899 if (PREDICT_TRUE (len2 > 0))
900 {
901 v1 = _vec_realloc_inline (v1, len1 + len2, v2_elt_sz, 0, align, 0);
902 clib_memmove (v1 + len2 * v2_elt_sz, v1p[0], len1 * v1_elt_sz);
903 clib_memcpy_fast (v1, v2, len2 * v2_elt_sz);
904 _vec_update_pointer (v1p, v1);
905 }
906}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700907
908/** \brief Prepend v2 before v1. Result in v1. Specified alignment
909 @param V1 target vector
910 @param V2 vector to prepend
911 @param align required alignment
912*/
913
Benoît Ganne1a3e08a2021-02-11 19:46:43 +0100914#define vec_prepend_aligned(v1, v2, align) \
Damjan Marion299571a2022-03-19 00:07:52 +0100915 _vec_prepend ((void **) &(v1), (void *) (v2), _vec_elt_sz (v1), \
916 _vec_elt_sz (v2), _vec_align (v1, align))
917
918/** \brief Prepend v2 before v1. Result in v1.
919 @param V1 target vector
920 @param V2 vector to prepend
921*/
922
923#define vec_prepend(v1, v2) vec_prepend_aligned (v1, v2, 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700924
925/** \brief Zero all vector elements. Null-pointer tolerant.
926 @param var Vector to zero
927*/
Damjan Marion299571a2022-03-19 00:07:52 +0100928static_always_inline void
929_vec_zero (void *v, uword elt_sz)
930{
931 uword len = vec_len (v);
932
933 if (len)
934 clib_memset_u8 (v, 0, len * elt_sz);
935}
936
937#define vec_zero(var) _vec_zero ((void *) (var), _vec_elt_sz (var))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700938
939/** \brief Set all vector elements to given value. Null-pointer tolerant.
940 @param v vector to set
941 @param val value for each vector element
942*/
943#define vec_set(v,val) \
944do { \
945 word _v(i); \
946 __typeof__ ((v)[0]) _val = (val); \
947 for (_v(i) = 0; _v(i) < vec_len (v); _v(i)++) \
948 (v)[_v(i)] = _val; \
949} while (0)
950
951#ifdef CLIB_UNIX
952#include <stdlib.h> /* for qsort */
953#endif
954
955/** \brief Compare two vectors, not NULL-pointer tolerant
956
957 @param v1 Pointer to a vector
958 @param v2 Pointer to a vector
959 @return 1 if equal, 0 if unequal
960*/
Damjan Marion299571a2022-03-19 00:07:52 +0100961static_always_inline int
962_vec_is_equal (void *v1, void *v2, uword v1_elt_sz, uword v2_elt_sz)
963{
964 uword vec_len_v1 = vec_len (v1);
965
966 if ((vec_len_v1 != vec_len (v2)) || (v1_elt_sz != v2_elt_sz))
967 return 0;
968
969 if ((vec_len_v1 == 0) || (memcmp (v1, v2, vec_len_v1 * v1_elt_sz) == 0))
970 return 1;
971
972 return 0;
973}
974
975#define vec_is_equal(v1, v2) \
976 _vec_is_equal ((void *) (v1), (void *) (v2), _vec_elt_sz (v1), \
977 _vec_elt_sz (v2))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700978
979/** \brief Compare two vectors (only applicable to vectors of signed numbers).
Dave Barachc3799992016-08-15 11:12:27 -0400980 Used in qsort compare functions.
981
Ed Warnickecb9cada2015-12-08 15:45:58 -0700982 @param v1 Pointer to a vector
983 @param v2 Pointer to a vector
984 @return -1, 0, +1
985*/
986#define vec_cmp(v1,v2) \
987({ \
988 word _v(i), _v(cmp), _v(l); \
989 _v(l) = clib_min (vec_len (v1), vec_len (v2)); \
990 _v(cmp) = 0; \
991 for (_v(i) = 0; _v(i) < _v(l); _v(i)++) { \
992 _v(cmp) = (v1)[_v(i)] - (v2)[_v(i)]; \
993 if (_v(cmp)) \
994 break; \
995 } \
996 if (_v(cmp) == 0 && _v(l) > 0) \
997 _v(cmp) = vec_len(v1) - vec_len(v2); \
998 (_v(cmp) < 0 ? -1 : (_v(cmp) > 0 ? +1 : 0)); \
999})
1000
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001001/** \brief Search a vector for the index of the entry that matches.
1002
Dave Wallace64b3cc22019-04-05 10:30:44 -04001003 @param v Pointer to a vector
1004 @param E Entry to match
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001005 @return index of match or ~0
1006*/
1007#define vec_search(v,E) \
1008({ \
1009 word _v(i) = 0; \
1010 while (_v(i) < vec_len(v)) \
1011 { \
Andrew Yourtchenkof908a032017-06-20 12:26:23 +02001012 if ((v)[_v(i)] == E) \
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001013 break; \
1014 _v(i)++; \
1015 } \
1016 if (_v(i) == vec_len(v)) \
1017 _v(i) = ~0; \
1018 _v(i); \
1019})
1020
Neale Ranns947ea622018-06-07 23:48:20 -07001021/** \brief Search a vector for the index of the entry that matches.
1022
Dave Wallace64b3cc22019-04-05 10:30:44 -04001023 @param v Pointer to a vector
1024 @param E Pointer to entry to match
Neale Ranns947ea622018-06-07 23:48:20 -07001025 @param fn Comparison function !0 => match
1026 @return index of match or ~0
1027*/
1028#define vec_search_with_function(v,E,fn) \
1029({ \
1030 word _v(i) = 0; \
1031 while (_v(i) < vec_len(v)) \
1032 { \
1033 if (0 != fn(&(v)[_v(i)], (E))) \
1034 break; \
1035 _v(i)++; \
1036 } \
1037 if (_v(i) == vec_len(v)) \
1038 _v(i) = ~0; \
1039 _v(i); \
1040})
1041
Ed Warnickecb9cada2015-12-08 15:45:58 -07001042/** \brief Sort a vector using the supplied element comparison function
1043
Dave Barachf593b572020-04-24 16:07:37 -04001044 Does not depend on the underlying implementation to deal correctly
1045 with null, zero-long, or 1-long vectors
1046
Ed Warnickecb9cada2015-12-08 15:45:58 -07001047 @param vec vector to sort
1048 @param f comparison function
1049*/
Dave Barachf593b572020-04-24 16:07:37 -04001050#define vec_sort_with_function(vec,f) \
1051do { \
1052 if (vec_len (vec) > 1) \
1053 qsort (vec, vec_len (vec), sizeof (vec[0]), (void *) (f)); \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001054} while (0)
1055
1056/** \brief Make a vector containing a NULL terminated c-string.
1057
Dave Barachc3799992016-08-15 11:12:27 -04001058 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001059 @param S pointer to string buffer.
1060 @param L string length (NOT including the terminating NULL; a la strlen())
1061*/
Damjan Marion299571a2022-03-19 00:07:52 +01001062#define vec_validate_init_c_string(V, S, L) \
1063 do \
1064 { \
1065 vec_reset_length (V); \
1066 vec_validate (V, (L)); \
1067 if ((S) && (L)) \
1068 clib_memcpy_fast (V, (S), (L)); \
1069 (V)[(L)] = 0; \
1070 } \
1071 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001072
Chris Lukeb5850972016-05-03 16:34:59 -04001073/** \brief Test whether a vector is a NULL terminated c-string.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001074
Dave Barachc3799992016-08-15 11:12:27 -04001075 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001076 @return BOOLEAN indicating if the vector c-string is null terminated.
1077*/
1078#define vec_c_string_is_terminated(V) \
1079 (((V) != 0) && (vec_len (V) != 0) && ((V)[vec_len ((V)) - 1] == 0))
1080
Chris Lukeb5850972016-05-03 16:34:59 -04001081/** \brief (If necessary) NULL terminate a vector containing a c-string.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001082
Dave Barachc3799992016-08-15 11:12:27 -04001083 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001084 @return V (value-result macro parameter)
1085*/
Damjan Marion299571a2022-03-19 00:07:52 +01001086#define vec_terminate_c_string(V) \
1087 do \
1088 { \
1089 if (!vec_c_string_is_terminated (V)) \
1090 vec_add1 (V, 0); \
1091 } \
1092 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001093
1094#endif /* included_vec_h */