blob: bfb7b1b7fc68064f3298fb1b9e53562c47c1337e [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
Damjan Marion24738582022-03-31 15:12:20 +020057 heap pointer (optional, only if default_heap == 0)
Damjan Marion299571a2022-03-19 00:07:52 +010058 vector header: number of elements, header size
Ed Warnickecb9cada2015-12-08 15:45:58 -070059 user's pointer-> vector element #0
Damjan Marion299571a2022-03-19 00:07:52 +010060 vector element #1
61 ...
Ed Warnickecb9cada2015-12-08 15:45:58 -070062~~~~~~~~
63
Dave Barach2bc1eba2016-01-19 15:10:27 -050064 The user pointer contains the address of vector element # 0. Null
Dave Barachc3799992016-08-15 11:12:27 -040065 pointer vectors are valid and mean a zero length vector.
Dave Barach2bc1eba2016-01-19 15:10:27 -050066
67 You can reset the length of an allocated vector to zero via the
68 vec_reset_length(v) macro, or by setting the vector length field to
69 zero (e.g. _vec_len (v) = 0). Vec_reset_length(v) preferred: it
70 understands Null pointers.
Ed Warnickecb9cada2015-12-08 15:45:58 -070071
72 Typically, the header is not present. Headers allow for other
73 data structures to be built atop CLIB vectors.
74
Damjan Marion299571a2022-03-19 00:07:52 +010075 While users may specify the alignment for first data element of a vector
76 via the vec_*_aligned macros that is typically not needed as alignment
77 is set based on native alignment of the data structure used.
Ed Warnickecb9cada2015-12-08 15:45:58 -070078
Dave Wallace4659d0e2018-12-13 12:29:44 -050079 Vector elements can be any C type e.g. (int, double, struct bar).
Ed Warnickecb9cada2015-12-08 15:45:58 -070080 This is also true for data types built atop vectors (e.g. heap,
81 pool, etc.).
82
Dave Wallace4659d0e2018-12-13 12:29:44 -050083 Many macros have \_a variants supporting alignment of vector elements
84 and \_h variants supporting non-zero-length vector headers. The \_ha
85 variants support both. Additionally cacheline alignment within a
86 vector element structure can be specified using the
87 CLIB_CACHE_LINE_ALIGN_MARK() macro.
Ed Warnickecb9cada2015-12-08 15:45:58 -070088
Dave Barachc3799992016-08-15 11:12:27 -040089 Standard programming error: memorize a pointer to the ith element
Ed Warnickecb9cada2015-12-08 15:45:58 -070090 of a vector then expand it. Vectors expand by 3/2, so such code
91 may appear to work for a period of time. Memorize vector indices
Dave Barachc3799992016-08-15 11:12:27 -040092 which are invariant.
Ed Warnickecb9cada2015-12-08 15:45:58 -070093 */
94
Damjan Marion299571a2022-03-19 00:07:52 +010095/** \brief Low-level (re)allocation function, usually not called directly
Ed Warnickecb9cada2015-12-08 15:45:58 -070096
97 @param v pointer to a vector
Damjan Marion299571a2022-03-19 00:07:52 +010098 @param n_elts requested number of elements
99 @param elt_sz requested size of one element
100 @param hdr_sz header size in bytes (may be zero)
101 @param align alignment (may be zero)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700102 @return v_prime pointer to resized vector, may or may not equal v
103*/
Damjan Marion299571a2022-03-19 00:07:52 +0100104void *_vec_realloc (void *v, uword n_elts, uword elt_sz, uword hdr_sz,
105 uword align, void *heap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700106
Damjan Marion299571a2022-03-19 00:07:52 +0100107/* calculate minimum alignment out of data natural alignment and provided
108 * value, should not be < VEC_MIN_ALIGN */
109static_always_inline uword
110__vec_align (uword data_align, uword configuered_align)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700111{
Damjan Marion299571a2022-03-19 00:07:52 +0100112 data_align = clib_max (data_align, configuered_align);
113 ASSERT (count_set_bits (data_align) == 1);
114 return clib_max (VEC_MIN_ALIGN, data_align);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700115}
116
Damjan Marion299571a2022-03-19 00:07:52 +0100117/* function used t o catch cases where vec_* macros on used on void * */
118static_always_inline uword
119__vec_elt_sz (uword elt_sz, int is_void)
120{
121 /* vector macro operations on void * are not allowed */
122 ASSERT (is_void == 0);
123 return elt_sz;
124}
Dave Barach614ac5d2017-02-06 09:28:03 -0500125
Damjan Marion299571a2022-03-19 00:07:52 +0100126static_always_inline void
127_vec_update_pointer (void **vp, void *v)
128{
129 /* avoid store if not needed */
130 if (v != vp[0])
131 vp[0] = v;
132}
Dave Barach614ac5d2017-02-06 09:28:03 -0500133
Damjan Marion24738582022-03-31 15:12:20 +0200134static_always_inline void *
135vec_get_heap (void *v)
136{
137 if (v == 0 || _vec_find (v)->default_heap == 1)
138 return 0;
139 return _vec_heap (v);
140}
141
142static_always_inline void *
Damjan Marion299571a2022-03-19 00:07:52 +0100143_vec_realloc_inline (void *v, uword n_elts, uword elt_sz, uword hdr_sz,
144 uword align, void *heap)
Dave Barach614ac5d2017-02-06 09:28:03 -0500145{
Dave Barach614ac5d2017-02-06 09:28:03 -0500146 if (PREDICT_TRUE (v != 0))
147 {
Dave Barach614ac5d2017-02-06 09:28:03 -0500148 /* Vector header must start heap object. */
Damjan Marion24738582022-03-31 15:12:20 +0200149 ASSERT (clib_mem_heap_is_heap_object (vec_get_heap (v), vec_header (v)));
Dave Barach614ac5d2017-02-06 09:28:03 -0500150
Damjan Marion299571a2022-03-19 00:07:52 +0100151 /* Typically we'll not need to resize. */
152 if ((n_elts * elt_sz) <= vec_max_bytes (v))
153 {
154 _vec_set_len (v, n_elts, elt_sz);
155 return v;
156 }
Dave Barach614ac5d2017-02-06 09:28:03 -0500157 }
Damjan Marion299571a2022-03-19 00:07:52 +0100158
159 /* Slow path: call helper function. */
160 return _vec_realloc (v, n_elts, elt_sz, hdr_sz, align, heap);
161}
162
Damjan Marion24738582022-03-31 15:12:20 +0200163static_always_inline void
164_vec_prealloc (void **vp, uword n_elts, uword hdr_sz, uword align, void *heap,
165 uword elt_sz)
166{
167 void *v;
168
169 ASSERT (vp[0] == 0);
170
171 v = _vec_realloc (0, n_elts, elt_sz, hdr_sz, align, heap);
172 _vec_set_len (v, 0, elt_sz);
173 _vec_update_pointer (vp, v);
174}
175
176/** \brief Pre-allocate a vector (generic version)
177
178 @param V pointer to a vector
179 @param N number of elements to pre-allocate
180 @param H header size in bytes (may be zero)
181 @param A alignment (zero means default alignment of the data structure)
182 @param P heap (zero means default heap)
183 @return V (value-result macro parameter)
184*/
185
186#define vec_prealloc_hap(V, N, H, A, P) \
187 _vec_prealloc ((void **) &(V), N, H, _vec_align (V, A), P, _vec_elt_sz (V))
188
189/** \brief Pre-allocate a vector (simple version)
190
191 @param V pointer to a vector
192 @param N number of elements to pre-allocate
193 @return V (value-result macro parameter)
194*/
195#define vec_prealloc(V, N) vec_prealloc_hap (V, N, 0, 0, 0)
196
197/** \brief Pre-allocate a vector (heap version)
198
199 @param V pointer to a vector
200 @param N number of elements to pre-allocate
201 @param P heap (zero means default heap)
202 @return V (value-result macro parameter)
203*/
204#define vec_prealloc_heap(V, N, P) vec_prealloc_hap (V, N, 0, 0, P)
205
Damjan Marion299571a2022-03-19 00:07:52 +0100206always_inline int
207_vec_resize_will_expand (void *v, uword n_elts, uword elt_sz)
208{
209 if (v == 0)
210 return 1;
211
212 /* Vector header must start heap object. */
Damjan Marion24738582022-03-31 15:12:20 +0200213 ASSERT (clib_mem_heap_is_heap_object (vec_get_heap (v), vec_header (v)));
Damjan Marion299571a2022-03-19 00:07:52 +0100214
215 n_elts += _vec_len (v);
216 if ((n_elts * elt_sz) <= vec_max_bytes (v))
217 return 0;
218
Dave Barach614ac5d2017-02-06 09:28:03 -0500219 return 1;
220}
221
Miklos Tirpake700df82021-01-13 10:00:38 +0100222/** \brief Determine if vector will resize with next allocation
223
224 @param V pointer to a vector
225 @param N number of elements to add
226 @return 1 if vector will resize 0 otherwise
227*/
228
229#define vec_resize_will_expand(V, N) \
Damjan Marion299571a2022-03-19 00:07:52 +0100230 _vec_resize_will_expand (V, N, _vec_elt_sz (V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700231
Ed Warnickecb9cada2015-12-08 15:45:58 -0700232/* Local variable naming macro (prevents collisions with other macro naming). */
233#define _v(var) _vec_##var
234
235/** \brief Resize a vector (general version).
236 Add N elements to end of given vector V, return pointer to start of vector.
237 Vector will have room for H header bytes and will have user's data aligned
238 at alignment A (rounded to next power of 2).
239
240 @param V pointer to a vector
241 @param N number of elements to add
242 @param H header size in bytes (may be zero)
243 @param A alignment (may be zero)
244 @return V (value-result macro parameter)
245*/
246
Damjan Marion299571a2022-03-19 00:07:52 +0100247static_always_inline void
248_vec_resize (void **vp, uword n_add, uword hdr_sz, uword align, uword elt_sz)
249{
250 void *v = vp[0];
251 v = _vec_realloc_inline (v, vec_len (v) + n_add, elt_sz, hdr_sz, align, 0);
252 _vec_update_pointer (vp, v);
253}
254
Damjan Marion3cfd5292022-03-18 15:48:12 +0100255#define vec_resize_ha(V, N, H, A) \
Damjan Marion299571a2022-03-19 00:07:52 +0100256 _vec_resize ((void **) &(V), N, H, _vec_align (V, A), _vec_elt_sz (V))
Dave Baracha690fdb2020-01-21 12:34:55 -0500257
Ed Warnickecb9cada2015-12-08 15:45:58 -0700258/** \brief Resize a vector (no header, unspecified alignment)
259 Add N elements to end of given vector V, return pointer to start of vector.
260 Vector will have room for H header bytes and will have user's data aligned
261 at alignment A (rounded to next power of 2).
262
263 @param V pointer to a vector
264 @param N number of elements to add
265 @return V (value-result macro parameter)
266*/
267#define vec_resize(V,N) vec_resize_ha(V,N,0,0)
268
269/** \brief Resize a vector (no header, alignment specified).
270 Add N elements to end of given vector V, return pointer to start of vector.
271 Vector will have room for H header bytes and will have user's data aligned
272 at alignment A (rounded to next power of 2).
273
274 @param V pointer to a vector
275 @param N number of elements to add
276 @param A alignment (may be zero)
277 @return V (value-result macro parameter)
278*/
279
280#define vec_resize_aligned(V,N,A) vec_resize_ha(V,N,0,A)
281
Dave Barachc3799992016-08-15 11:12:27 -0400282/** \brief Allocate space for N more elements
Ed Warnickecb9cada2015-12-08 15:45:58 -0700283
284 @param V pointer to a vector
285 @param N number of elements to add
286 @param H header size in bytes (may be zero)
287 @param A alignment (may be zero)
288 @return V (value-result macro parameter)
289*/
290
Damjan Marion299571a2022-03-19 00:07:52 +0100291#define vec_alloc_ha(V, N, H, A) \
292 do \
293 { \
294 uword _v (l) = vec_len (V); \
295 vec_resize_ha (V, N, H, A); \
296 vec_set_len (V, _v (l)); \
297 } \
298 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700299
Dave Barachc3799992016-08-15 11:12:27 -0400300/** \brief Allocate space for N more elements
301 (no header, unspecified alignment)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700302
303 @param V pointer to a vector
304 @param N number of elements to add
305 @return V (value-result macro parameter)
306*/
307#define vec_alloc(V,N) vec_alloc_ha(V,N,0,0)
308
309/** \brief Allocate space for N more elements (no header, given alignment)
310 @param V pointer to a vector
311 @param N number of elements to add
312 @param A alignment (may be zero)
313 @return V (value-result macro parameter)
314*/
315
316#define vec_alloc_aligned(V,N,A) vec_alloc_ha(V,N,0,A)
317
318/** \brief Create new vector of given type and length (general version).
319 @param T type of elements in new vector
320 @param N number of elements to add
321 @param H header size in bytes (may be zero)
322 @param A alignment (may be zero)
Damjan Marion43daea82022-04-06 12:31:15 +0200323 @param P heap (may be zero)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700324 @return V new vector
325*/
Damjan Marion43daea82022-04-06 12:31:15 +0200326#define vec_new_generic(T, N, H, A, P) \
327 _vec_realloc (0, N, sizeof (T), H, _vec_align ((T *) 0, A), P)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700328
Dave Barachc3799992016-08-15 11:12:27 -0400329/** \brief Create new vector of given type and length
Ed Warnickecb9cada2015-12-08 15:45:58 -0700330 (unspecified alignment, no header).
331
332 @param T type of elements in new vector
333 @param N number of elements to add
334 @return V new vector
335*/
Damjan Marion43daea82022-04-06 12:31:15 +0200336#define vec_new(T, N) vec_new_generic (T, N, 0, 0, 0)
Dave Barachc3799992016-08-15 11:12:27 -0400337/** \brief Create new vector of given type and length
338 (alignment specified, no header).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700339
340 @param T type of elements in new vector
341 @param N number of elements to add
342 @param A alignment (may be zero)
343 @return V new vector
344*/
Damjan Marion43daea82022-04-06 12:31:15 +0200345#define vec_new_aligned(T, N, A) vec_new_generic (T, N, 0, A, 0)
346/** \brief Create new vector of given type and length
347 (heap specified, no header).
348
349 @param T type of elements in new vector
350 @param N number of elements to add
351 @param P heap (may be zero)
352 @return V new vector
353*/
354#define vec_new_heap(T, N, P) vec_new_generic (T, N, 0, 0, P)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700355
Damjan Marion05563c92022-03-17 18:29:32 +0100356/** \brief Free vector's memory (no header).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700357 @param V pointer to a vector
Ed Warnickecb9cada2015-12-08 15:45:58 -0700358 @return V (value-result parameter, V=0)
359*/
Damjan Marion299571a2022-03-19 00:07:52 +0100360
361static_always_inline void
362_vec_free (void **vp)
363{
364 if (vp[0] == 0)
365 return;
366 clib_mem_free (vec_header (vp[0]));
367 vp[0] = 0;
368}
369
370#define vec_free(V) _vec_free ((void **) &(V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700371
Dave Barache09ae012020-08-19 06:59:53 -0400372void vec_free_not_inline (void *v);
373
Ed Warnickecb9cada2015-12-08 15:45:58 -0700374/**\brief Free vector user header (syntactic sugar)
375 @param h vector header
376 @void
377*/
378#define vec_free_header(h) clib_mem_free (h)
379
380/** \brief Return copy of vector (general version).
381
382 @param V pointer to a vector
383 @param H size of header in bytes
384 @param A alignment (may be zero)
385
386 @return Vdup copy of vector
387*/
388
Damjan Marion299571a2022-03-19 00:07:52 +0100389static_always_inline void *
390_vec_dup (void *v, uword hdr_size, uword align, uword elt_sz)
391{
392 uword len = vec_len (v);
393 void *n = 0;
394
395 if (len)
396 {
397 n = _vec_realloc (0, len, elt_sz, hdr_size, align, 0);
398 clib_memcpy_fast (n, v, len * elt_sz);
399 }
400 return n;
401}
402
Damjan Marion3cfd5292022-03-18 15:48:12 +0100403#define vec_dup_ha(V, H, A) \
Damjan Marion299571a2022-03-19 00:07:52 +0100404 _vec_dup ((void *) (V), H, _vec_align (V, A), _vec_elt_sz (V))
Dave Baracha690fdb2020-01-21 12:34:55 -0500405
Ed Warnickecb9cada2015-12-08 15:45:58 -0700406/** \brief Return copy of vector (no header, no alignment)
407
408 @param V pointer to a vector
409 @return Vdup copy of vector
410*/
411#define vec_dup(V) vec_dup_ha(V,0,0)
412
413/** \brief Return copy of vector (no header, alignment specified).
414
415 @param V pointer to a vector
416 @param A alignment (may be zero)
417
418 @return Vdup copy of vector
419*/
420#define vec_dup_aligned(V,A) vec_dup_ha(V,0,A)
421
422/** \brief Copy a vector, memcpy wrapper. Assumes sizeof(SRC[0]) ==
423 sizeof(DST[0])
424
Dave Barachc3799992016-08-15 11:12:27 -0400425 @param DST destination
Ed Warnickecb9cada2015-12-08 15:45:58 -0700426 @param SRC source
427*/
Dave Barach178cf492018-11-13 16:34:13 -0500428#define vec_copy(DST,SRC) clib_memcpy_fast (DST, SRC, vec_len (DST) * \
Damjan Marionf1213b82016-03-13 02:22:06 +0100429 sizeof ((DST)[0]))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700430
Dave Barachc3799992016-08-15 11:12:27 -0400431/** \brief Clone a vector. Make a new vector with the
Ed Warnickecb9cada2015-12-08 15:45:58 -0700432 same size as a given vector but possibly with a different type.
433
434 @param NEW_V pointer to new vector
435 @param OLD_V pointer to old vector
436*/
Damjan Marion299571a2022-03-19 00:07:52 +0100437
438static_always_inline void
439_vec_clone (void **v1p, void *v2, uword align, uword elt_sz)
440{
441 v1p[0] = _vec_realloc (0, vec_len (v2), elt_sz, 0, align, 0);
442}
443#define vec_clone(NEW_V, OLD_V) \
444 _vec_clone ((void **) &(NEW_V), OLD_V, _vec_align (NEW_V, 0), \
445 _vec_elt_sz (NEW_V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700446
447/** \brief Make sure vector is long enough for given index (general version).
448
Dave Barachc3799992016-08-15 11:12:27 -0400449 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700450 @param I vector index which will be valid upon return
451 @param H header size in bytes (may be zero)
452 @param A alignment (may be zero)
453 @return V (value-result macro parameter)
454*/
455
Damjan Marion299571a2022-03-19 00:07:52 +0100456always_inline void
457_vec_zero_elts (void *v, uword first, uword count, uword elt_sz)
458{
459 clib_memset_u8 (v + (first * elt_sz), 0, count * elt_sz);
460}
461#define vec_zero_elts(V, F, C) _vec_zero_elts (V, F, C, sizeof ((V)[0]))
462
Damjan Marion24738582022-03-31 15:12:20 +0200463static_always_inline void
464_vec_validate (void **vp, uword index, uword header_size, uword align,
465 void *heap, uword elt_sz)
Damjan Marion299571a2022-03-19 00:07:52 +0100466{
Damjan Marion24738582022-03-31 15:12:20 +0200467 void *v = vp[0];
Damjan Marion299571a2022-03-19 00:07:52 +0100468 uword vl = vec_len (v);
469 if (index >= vl)
470 {
Damjan Marion24738582022-03-31 15:12:20 +0200471 v = _vec_realloc_inline (v, index + 1, elt_sz, header_size, align, heap);
Damjan Marion299571a2022-03-19 00:07:52 +0100472 _vec_zero_elts (v, vl, index - vl + 1, elt_sz);
Damjan Marion24738582022-03-31 15:12:20 +0200473 _vec_update_pointer (vp, v);
Damjan Marion299571a2022-03-19 00:07:52 +0100474 }
Damjan Marion299571a2022-03-19 00:07:52 +0100475}
476
Damjan Marion24738582022-03-31 15:12:20 +0200477#define vec_validate_hap(V, I, H, A, P) \
478 _vec_validate ((void **) &(V), I, H, _vec_align (V, A), 0, sizeof ((V)[0]))
Dave Baracha690fdb2020-01-21 12:34:55 -0500479
Dave Barachc3799992016-08-15 11:12:27 -0400480/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700481 (no header, unspecified alignment)
482
Dave Barachc3799992016-08-15 11:12:27 -0400483 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700484 @param I vector index which will be valid upon return
485 @return V (value-result macro parameter)
486*/
Damjan Marion24738582022-03-31 15:12:20 +0200487#define vec_validate(V, I) vec_validate_hap (V, I, 0, 0, 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488
Dave Barachc3799992016-08-15 11:12:27 -0400489/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700490 (no header, specified alignment)
491
Dave Barachc3799992016-08-15 11:12:27 -0400492 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700493 @param I vector index which will be valid upon return
494 @param A alignment (may be zero)
495 @return V (value-result macro parameter)
496*/
497
Damjan Marion24738582022-03-31 15:12:20 +0200498#define vec_validate_aligned(V, I, A) vec_validate_hap (V, I, 0, A, 0)
499
500/** \brief Make sure vector is long enough for given index
501 (no header, specified heap)
502
503 @param V (possibly NULL) pointer to a vector.
504 @param I vector index which will be valid upon return
505 @param H heap (may be zero)
506 @return V (value-result macro parameter)
507*/
508
509#define vec_validate_heap(V, I, P) vec_validate_hap (V, I, 0, 0, P)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700510
Dave Barachc3799992016-08-15 11:12:27 -0400511/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700512 and initialize empty space (general version)
513
Dave Barachc3799992016-08-15 11:12:27 -0400514 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700515 @param I vector index which will be valid upon return
516 @param INIT initial value (can be a complex expression!)
517 @param H header size in bytes (may be zero)
518 @param A alignment (may be zero)
519 @return V (value-result macro parameter)
520*/
Damjan Marion299571a2022-03-19 00:07:52 +0100521#define vec_validate_init_empty_ha(V, I, INIT, H, A) \
522 do \
523 { \
524 word _v (i) = (I); \
525 word _v (l) = vec_len (V); \
526 if (_v (i) >= _v (l)) \
527 { \
528 vec_resize_ha (V, 1 + (_v (i) - _v (l)), H, A); \
529 while (_v (l) <= _v (i)) \
530 { \
531 (V)[_v (l)] = (INIT); \
532 _v (l)++; \
533 } \
534 } \
535 } \
536 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700537
Dave Barachc3799992016-08-15 11:12:27 -0400538/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700539 and initialize empty space (no header, unspecified alignment)
540
Dave Barachc3799992016-08-15 11:12:27 -0400541 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700542 @param I vector index which will be valid upon return
543 @param INIT initial value (can be a complex expression!)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700544 @return V (value-result macro parameter)
545*/
546
547#define vec_validate_init_empty(V,I,INIT) \
548 vec_validate_init_empty_ha(V,I,INIT,0,0)
549
Dave Barachc3799992016-08-15 11:12:27 -0400550/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700551 and initialize empty space (no header, alignment alignment)
552
Dave Barachc3799992016-08-15 11:12:27 -0400553 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700554 @param I vector index which will be valid upon return
555 @param INIT initial value (can be a complex expression!)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700556 @param A alignment (may be zero)
557 @return V (value-result macro parameter)
558*/
Damjan Marion7d272182017-06-05 21:53:39 +0200559#define vec_validate_init_empty_aligned(V,I,INIT,A) \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700560 vec_validate_init_empty_ha(V,I,INIT,0,A)
561
Dave Barachc3799992016-08-15 11:12:27 -0400562/** \brief Add 1 element to end of vector (general version).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700563
564 @param V pointer to a vector
565 @param E element to add
566 @param H header size in bytes (may be zero)
567 @param A alignment (may be zero)
568 @return V (value-result macro parameter)
569*/
Damjan Marion299571a2022-03-19 00:07:52 +0100570
571static_always_inline void *
572_vec_add1 (void **vp, uword hdr_sz, uword align, uword elt_sz)
573{
574 void *v = vp[0];
575 uword len = vec_len (v);
576 v = _vec_realloc_inline (v, len + 1, elt_sz, hdr_sz, align, 0);
577
578 _vec_update_pointer (vp, v);
579
580 return v + len * elt_sz;
581}
582
583#define vec_add1_ha(V, E, H, A) \
584 ((__typeof__ ((V)[0]) *) _vec_add1 ((void **) &(V), H, _vec_align (V, A), \
585 _vec_elt_sz (V)))[0] = (E)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700586
Dave Barachc3799992016-08-15 11:12:27 -0400587/** \brief Add 1 element to end of vector (unspecified alignment).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700588
589 @param V pointer to a vector
590 @param E element to add
591 @return V (value-result macro parameter)
592*/
593#define vec_add1(V,E) vec_add1_ha(V,E,0,0)
594
Dave Barachc3799992016-08-15 11:12:27 -0400595/** \brief Add 1 element to end of vector (alignment specified).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700596
597 @param V pointer to a vector
598 @param E element to add
Ed Warnickecb9cada2015-12-08 15:45:58 -0700599 @param A alignment (may be zero)
600 @return V (value-result macro parameter)
601*/
602#define vec_add1_aligned(V,E,A) vec_add1_ha(V,E,0,A)
603
Dave Barachc3799992016-08-15 11:12:27 -0400604/** \brief Add N elements to end of vector V,
605 return pointer to new elements in P. (general version)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700606
607 @param V pointer to a vector
608 @param P pointer to new vector element(s)
609 @param N number of elements to add
610 @param H header size in bytes (may be zero)
611 @param A alignment (may be zero)
612 @return V and P (value-result macro parameters)
613*/
Damjan Marion299571a2022-03-19 00:07:52 +0100614
615static_always_inline void
616_vec_add2 (void **vp, void **pp, uword n_add, uword hdr_sz, uword align,
617 uword elt_sz)
618{
619 void *v = vp[0];
620 uword len = vec_len (vp[0]);
621 v = _vec_realloc_inline (v, len + n_add, elt_sz, hdr_sz, align, 0);
622 _vec_update_pointer (vp, v);
623 pp[0] = v + len * elt_sz;
624}
625
626#define vec_add2_ha(V, P, N, H, A) \
627 _vec_add2 ((void **) &(V), (void **) &(P), N, H, _vec_align (V, A), \
628 _vec_elt_sz (V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700629
Dave Barachc3799992016-08-15 11:12:27 -0400630/** \brief Add N elements to end of vector V,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700631 return pointer to new elements in P. (no header, unspecified alignment)
632
633 @param V pointer to a vector
634 @param P pointer to new vector element(s)
635 @param N number of elements to add
636 @return V and P (value-result macro parameters)
637*/
638
639#define vec_add2(V,P,N) vec_add2_ha(V,P,N,0,0)
640
Dave Barachc3799992016-08-15 11:12:27 -0400641/** \brief Add N elements to end of vector V,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700642 return pointer to new elements in P. (no header, alignment specified)
643
644 @param V pointer to a vector
645 @param P pointer to new vector element(s)
646 @param N number of elements to add
647 @param A alignment (may be zero)
648 @return V and P (value-result macro parameters)
649*/
650
651#define vec_add2_aligned(V,P,N,A) vec_add2_ha(V,P,N,0,A)
652
Dave Barachc3799992016-08-15 11:12:27 -0400653/** \brief Add N elements to end of vector V (general version)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700654
655 @param V pointer to a vector
656 @param E pointer to element(s) to add
657 @param N number of elements to add
658 @param H header size in bytes (may be zero)
659 @param A alignment (may be zero)
660 @return V (value-result macro parameter)
661*/
Damjan Marion299571a2022-03-19 00:07:52 +0100662static_always_inline void
663_vec_add (void **vp, void *e, word n_add, uword hdr_sz, uword align,
664 uword elt_sz)
665{
666 void *v = vp[0];
667 uword len = vec_len (v);
668
669 ASSERT (n_add >= 0);
670
671 if (n_add < 1)
672 return;
673
674 v = _vec_realloc_inline (v, len + n_add, elt_sz, hdr_sz, align, 0);
675 clib_memcpy_fast (v + len * elt_sz, e, n_add * elt_sz);
676 _vec_update_pointer (vp, v);
677}
678
Benoît Ganne1a3e08a2021-02-11 19:46:43 +0100679#define vec_add_ha(V, E, N, H, A) \
Damjan Marion299571a2022-03-19 00:07:52 +0100680 _vec_add ((void **) &(V), (void *) (E), N, H, _vec_align (V, A), \
681 _vec_elt_sz (V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700682
683/** \brief Add N elements to end of vector V (no header, unspecified alignment)
684
685 @param V pointer to a vector
686 @param E pointer to element(s) to add
687 @param N number of elements to add
688 @return V (value-result macro parameter)
689*/
690#define vec_add(V,E,N) vec_add_ha(V,E,N,0,0)
691
692/** \brief Add N elements to end of vector V (no header, specified alignment)
693
694 @param V pointer to a vector
695 @param E pointer to element(s) to add
696 @param N number of elements to add
697 @param A alignment (may be zero)
698 @return V (value-result macro parameter)
699*/
700#define vec_add_aligned(V,E,N,A) vec_add_ha(V,E,N,0,A)
701
Dave Barachc3799992016-08-15 11:12:27 -0400702/** \brief Returns last element of a vector and decrements its length
Ed Warnickecb9cada2015-12-08 15:45:58 -0700703
704 @param V pointer to a vector
705 @return E element removed from the end of the vector
706*/
Damjan Marion299571a2022-03-19 00:07:52 +0100707#define vec_pop(V) \
708 ({ \
709 uword _v (l) = vec_len (V); \
710 __typeof__ ((V)[0]) _v (rv); \
711 ASSERT (_v (l) > 0); \
712 _v (l) -= 1; \
713 _v (rv) = (V)[_v (l)]; \
714 vec_set_len (V, _v (l)); \
715 (_v (rv)); \
716 })
Ed Warnickecb9cada2015-12-08 15:45:58 -0700717
Dave Barachc3799992016-08-15 11:12:27 -0400718/** \brief Set E to the last element of a vector, decrement vector length
Ed Warnickecb9cada2015-12-08 15:45:58 -0700719 @param V pointer to a vector
720 @param E pointer to the last vector element
Dave Barachc3799992016-08-15 11:12:27 -0400721 @return E element removed from the end of the vector
Ed Warnickecb9cada2015-12-08 15:45:58 -0700722 (value-result macro parameter
723*/
724
725#define vec_pop2(V,E) \
726({ \
727 uword _v(l) = vec_len (V); \
728 if (_v(l) > 0) (E) = vec_pop (V); \
729 _v(l) > 0; \
730})
731
Dave Barachc3799992016-08-15 11:12:27 -0400732/** \brief Insert N vector elements starting at element M,
733 initialize new elements (general version).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700734
Dave Barachc3799992016-08-15 11:12:27 -0400735 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700736 @param N number of elements to insert
737 @param M insertion point
738 @param INIT initial value (can be a complex expression!)
739 @param H header size in bytes (may be zero)
740 @param A alignment (may be zero)
741 @return V (value-result macro parameter)
742*/
Damjan Marion299571a2022-03-19 00:07:52 +0100743
744static_always_inline void
745_vec_insert (void **vp, uword n_insert, uword ins_pt, u8 init, uword hdr_sz,
746 uword align, uword elt_sz)
747{
748 void *v = vp[0];
749 uword len = vec_len (v);
750
751 ASSERT (ins_pt <= len);
752
753 v = _vec_realloc_inline (v, len + n_insert, elt_sz, hdr_sz, align, 0);
754 clib_memmove (v + elt_sz * (ins_pt + n_insert), v + ins_pt * elt_sz,
755 (len - ins_pt) * elt_sz);
756 _vec_zero_elts (v, ins_pt, n_insert, elt_sz);
757 _vec_update_pointer (vp, v);
758}
759
760#define vec_insert_init_empty_ha(V, N, M, INIT, H, A) \
761 _vec_insert ((void **) &(V), N, M, INIT, H, _vec_align (V, A), \
762 _vec_elt_sz (V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700763
Dave Barachc3799992016-08-15 11:12:27 -0400764/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700765 initialize new elements to zero (general version)
766
Dave Barachc3799992016-08-15 11:12:27 -0400767 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700768 @param N number of elements to insert
769 @param M insertion point
770 @param H header size in bytes (may be zero)
771 @param A alignment (may be zero)
772 @return V (value-result macro parameter)
773*/
774#define vec_insert_ha(V,N,M,H,A) vec_insert_init_empty_ha(V,N,M,0,H,A)
775
Dave Barachc3799992016-08-15 11:12:27 -0400776/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700777 initialize new elements to zero (no header, unspecified alignment)
778
Dave Barachc3799992016-08-15 11:12:27 -0400779 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700780 @param N number of elements to insert
781 @param M insertion point
782 @return V (value-result macro parameter)
783*/
784#define vec_insert(V,N,M) vec_insert_ha(V,N,M,0,0)
785
Dave Barachc3799992016-08-15 11:12:27 -0400786/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700787 initialize new elements to zero (no header, alignment specified)
788
Dave Barachc3799992016-08-15 11:12:27 -0400789 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700790 @param N number of elements to insert
791 @param M insertion point
792 @param A alignment (may be zero)
793 @return V (value-result macro parameter)
794*/
795#define vec_insert_aligned(V,N,M,A) vec_insert_ha(V,N,M,0,A)
796
Dave Barachc3799992016-08-15 11:12:27 -0400797/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700798 initialize new elements (no header, unspecified alignment)
799
Dave Barachc3799992016-08-15 11:12:27 -0400800 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700801 @param N number of elements to insert
802 @param M insertion point
803 @param INIT initial value (can be a complex expression!)
804 @return V (value-result macro parameter)
805*/
806
807#define vec_insert_init_empty(V,N,M,INIT) \
808 vec_insert_init_empty_ha(V,N,M,INIT,0,0)
809/* Resize vector by N elements starting from element M, initialize new elements to INIT (alignment specified, no header). */
810
Dave Barachc3799992016-08-15 11:12:27 -0400811/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700812 initialize new elements (no header, specified alignment)
813
Dave Barachc3799992016-08-15 11:12:27 -0400814 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700815 @param N number of elements to insert
816 @param M insertion point
817 @param INIT initial value (can be a complex expression!)
818 @param A alignment (may be zero)
819 @return V (value-result macro parameter)
820*/
821#define vec_insert_init_empty_aligned(V,N,M,INIT,A) \
822 vec_insert_init_empty_ha(V,N,M,INIT,0,A)
823
Dave Barachc3799992016-08-15 11:12:27 -0400824/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700825 insert given elements (general version)
826
Dave Barachc3799992016-08-15 11:12:27 -0400827 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700828 @param E element(s) to insert
829 @param N number of elements to insert
830 @param M insertion point
831 @param H header size in bytes (may be zero)
832 @param A alignment (may be zero)
833 @return V (value-result macro parameter)
834*/
835
Damjan Marion299571a2022-03-19 00:07:52 +0100836static_always_inline void
837_vec_insert_elts (void **vp, void *e, uword n_insert, uword ins_pt,
838 uword hdr_sz, uword align, uword elt_sz)
839{
840 void *v = vp[0];
841 uword len = vec_len (v);
842
843 ASSERT (ins_pt <= len);
844
845 v = _vec_realloc_inline (v, len + n_insert, elt_sz, hdr_sz, align, 0);
846 clib_memmove (v + elt_sz * (ins_pt + n_insert), v + ins_pt * elt_sz,
847 (len - ins_pt) * elt_sz);
848 _vec_zero_elts (v, ins_pt, n_insert, elt_sz);
849 clib_memcpy_fast (v + ins_pt * elt_sz, e, n_insert * elt_sz);
850 _vec_update_pointer (vp, v);
851}
852
Benoît Ganne1a3e08a2021-02-11 19:46:43 +0100853#define vec_insert_elts_ha(V, E, N, M, H, A) \
Damjan Marion299571a2022-03-19 00:07:52 +0100854 _vec_insert_elts ((void **) &(V), E, N, M, H, _vec_align (V, A), \
855 _vec_elt_sz (V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700856
Dave Barachc3799992016-08-15 11:12:27 -0400857/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700858 insert given elements (no header, unspecified alignment)
859
Dave Barachc3799992016-08-15 11:12:27 -0400860 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700861 @param E element(s) to insert
862 @param N number of elements to insert
863 @param M insertion point
864 @return V (value-result macro parameter)
865*/
866#define vec_insert_elts(V,E,N,M) vec_insert_elts_ha(V,E,N,M,0,0)
867
Dave Barachc3799992016-08-15 11:12:27 -0400868/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700869 insert given elements (no header, specified alignment)
870
Dave Barachc3799992016-08-15 11:12:27 -0400871 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700872 @param E element(s) to insert
873 @param N number of elements to insert
874 @param M insertion point
875 @param A alignment (may be zero)
876 @return V (value-result macro parameter)
877*/
878#define vec_insert_elts_aligned(V,E,N,M,A) vec_insert_elts_ha(V,E,N,M,0,A)
879
Dave Barachc3799992016-08-15 11:12:27 -0400880/** \brief Delete N elements starting at element M
Ed Warnickecb9cada2015-12-08 15:45:58 -0700881
882 @param V pointer to a vector
883 @param N number of elements to delete
884 @param M first element to delete
885 @return V (value-result macro parameter)
886*/
Damjan Marion299571a2022-03-19 00:07:52 +0100887
888static_always_inline void
889_vec_delete (void *v, uword n_del, uword first, uword elt_sz)
890{
891 word n_bytes_del, n_bytes_to_move, len = vec_len (v);
892 u8 *dst;
893
894 if (n_del == 0)
895 return;
896
897 ASSERT (first + n_del <= len);
898
899 n_bytes_del = n_del * elt_sz;
900 n_bytes_to_move = (len - first - n_del) * elt_sz;
901 dst = v + first * elt_sz;
902
903 if (n_bytes_to_move > 0)
904 clib_memmove (dst, dst + n_bytes_del, n_bytes_to_move);
905 clib_memset (dst + n_bytes_to_move, 0, n_bytes_del);
906
907 _vec_set_len (v, _vec_len (v) - n_del, elt_sz);
908}
909
910#define vec_delete(V, N, M) _vec_delete ((void *) (V), N, M, _vec_elt_sz (V))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700911
912/** \brief Delete the element at index I
913
914 @param V pointer to a vector
915 @param I index to delete
916*/
Ed Warnickecb9cada2015-12-08 15:45:58 -0700917
Damjan Marion299571a2022-03-19 00:07:52 +0100918static_always_inline void
919_vec_del1 (void *v, uword index, uword elt_sz)
920{
921 uword len = _vec_len (v) - 1;
Dave Barachc3799992016-08-15 11:12:27 -0400922
Damjan Marion299571a2022-03-19 00:07:52 +0100923 if (index < len)
924 clib_memcpy_fast (v + index * elt_sz, v + len * elt_sz, elt_sz);
925
926 _vec_set_len (v, len, elt_sz);
927}
928
929#define vec_del1(v, i) _vec_del1 ((void *) (v), i, _vec_elt_sz (v))
930
931static_always_inline void
932_vec_append (void **v1p, void *v2, uword v1_elt_sz, uword v2_elt_sz,
933 uword align)
934{
935 void *v1 = v1p[0];
936 uword len1 = vec_len (v1);
937 uword len2 = vec_len (v2);
938
939 if (PREDICT_TRUE (len2 > 0))
940 {
941 v1 = _vec_realloc_inline (v1, len1 + len2, v2_elt_sz, 0, align, 0);
942 clib_memcpy_fast (v1 + len1 * v1_elt_sz, v2, len2 * v2_elt_sz);
943 _vec_update_pointer (v1p, v1);
944 }
945}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700946
947/** \brief Append v2 after v1. Result in v1. Specified alignment.
948 @param V1 target vector
949 @param V2 vector to append
950 @param align required alignment
951*/
Dave Barachc3799992016-08-15 11:12:27 -0400952
Benoît Ganne1a3e08a2021-02-11 19:46:43 +0100953#define vec_append_aligned(v1, v2, align) \
Damjan Marion299571a2022-03-19 00:07:52 +0100954 _vec_append ((void **) &(v1), (void *) (v2), _vec_elt_sz (v1), \
955 _vec_elt_sz (v2), _vec_align (v1, align))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700956
Damjan Marion299571a2022-03-19 00:07:52 +0100957/** \brief Append v2 after v1. Result in v1.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700958 @param V1 target vector
Damjan Marion299571a2022-03-19 00:07:52 +0100959 @param V2 vector to append
Ed Warnickecb9cada2015-12-08 15:45:58 -0700960*/
961
Damjan Marion299571a2022-03-19 00:07:52 +0100962#define vec_append(v1, v2) vec_append_aligned (v1, v2, 0)
963
964static_always_inline void
965_vec_prepend (void **v1p, void *v2, uword v1_elt_sz, uword v2_elt_sz,
966 uword align)
967{
968 void *v1 = v1p[0];
969 uword len1 = vec_len (v1);
970 uword len2 = vec_len (v2);
971
972 if (PREDICT_TRUE (len2 > 0))
973 {
974 v1 = _vec_realloc_inline (v1, len1 + len2, v2_elt_sz, 0, align, 0);
975 clib_memmove (v1 + len2 * v2_elt_sz, v1p[0], len1 * v1_elt_sz);
976 clib_memcpy_fast (v1, v2, len2 * v2_elt_sz);
977 _vec_update_pointer (v1p, v1);
978 }
979}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700980
981/** \brief Prepend v2 before v1. Result in v1. Specified alignment
982 @param V1 target vector
983 @param V2 vector to prepend
984 @param align required alignment
985*/
986
Benoît Ganne1a3e08a2021-02-11 19:46:43 +0100987#define vec_prepend_aligned(v1, v2, align) \
Damjan Marion299571a2022-03-19 00:07:52 +0100988 _vec_prepend ((void **) &(v1), (void *) (v2), _vec_elt_sz (v1), \
989 _vec_elt_sz (v2), _vec_align (v1, align))
990
991/** \brief Prepend v2 before v1. Result in v1.
992 @param V1 target vector
993 @param V2 vector to prepend
994*/
995
996#define vec_prepend(v1, v2) vec_prepend_aligned (v1, v2, 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700997
998/** \brief Zero all vector elements. Null-pointer tolerant.
999 @param var Vector to zero
1000*/
Damjan Marion299571a2022-03-19 00:07:52 +01001001static_always_inline void
1002_vec_zero (void *v, uword elt_sz)
1003{
1004 uword len = vec_len (v);
1005
1006 if (len)
1007 clib_memset_u8 (v, 0, len * elt_sz);
1008}
1009
1010#define vec_zero(var) _vec_zero ((void *) (var), _vec_elt_sz (var))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001011
1012/** \brief Set all vector elements to given value. Null-pointer tolerant.
1013 @param v vector to set
1014 @param val value for each vector element
1015*/
1016#define vec_set(v,val) \
1017do { \
1018 word _v(i); \
1019 __typeof__ ((v)[0]) _val = (val); \
1020 for (_v(i) = 0; _v(i) < vec_len (v); _v(i)++) \
1021 (v)[_v(i)] = _val; \
1022} while (0)
1023
1024#ifdef CLIB_UNIX
1025#include <stdlib.h> /* for qsort */
1026#endif
1027
1028/** \brief Compare two vectors, not NULL-pointer tolerant
1029
1030 @param v1 Pointer to a vector
1031 @param v2 Pointer to a vector
1032 @return 1 if equal, 0 if unequal
1033*/
Damjan Marion299571a2022-03-19 00:07:52 +01001034static_always_inline int
1035_vec_is_equal (void *v1, void *v2, uword v1_elt_sz, uword v2_elt_sz)
1036{
1037 uword vec_len_v1 = vec_len (v1);
1038
1039 if ((vec_len_v1 != vec_len (v2)) || (v1_elt_sz != v2_elt_sz))
1040 return 0;
1041
1042 if ((vec_len_v1 == 0) || (memcmp (v1, v2, vec_len_v1 * v1_elt_sz) == 0))
1043 return 1;
1044
1045 return 0;
1046}
1047
1048#define vec_is_equal(v1, v2) \
1049 _vec_is_equal ((void *) (v1), (void *) (v2), _vec_elt_sz (v1), \
1050 _vec_elt_sz (v2))
Ed Warnickecb9cada2015-12-08 15:45:58 -07001051
1052/** \brief Compare two vectors (only applicable to vectors of signed numbers).
Dave Barachc3799992016-08-15 11:12:27 -04001053 Used in qsort compare functions.
1054
Ed Warnickecb9cada2015-12-08 15:45:58 -07001055 @param v1 Pointer to a vector
1056 @param v2 Pointer to a vector
1057 @return -1, 0, +1
1058*/
1059#define vec_cmp(v1,v2) \
1060({ \
1061 word _v(i), _v(cmp), _v(l); \
1062 _v(l) = clib_min (vec_len (v1), vec_len (v2)); \
1063 _v(cmp) = 0; \
1064 for (_v(i) = 0; _v(i) < _v(l); _v(i)++) { \
1065 _v(cmp) = (v1)[_v(i)] - (v2)[_v(i)]; \
1066 if (_v(cmp)) \
1067 break; \
1068 } \
1069 if (_v(cmp) == 0 && _v(l) > 0) \
1070 _v(cmp) = vec_len(v1) - vec_len(v2); \
1071 (_v(cmp) < 0 ? -1 : (_v(cmp) > 0 ? +1 : 0)); \
1072})
1073
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001074/** \brief Search a vector for the index of the entry that matches.
1075
Dave Wallace64b3cc22019-04-05 10:30:44 -04001076 @param v Pointer to a vector
1077 @param E Entry to match
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001078 @return index of match or ~0
1079*/
1080#define vec_search(v,E) \
1081({ \
1082 word _v(i) = 0; \
1083 while (_v(i) < vec_len(v)) \
1084 { \
Andrew Yourtchenkof908a032017-06-20 12:26:23 +02001085 if ((v)[_v(i)] == E) \
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001086 break; \
1087 _v(i)++; \
1088 } \
1089 if (_v(i) == vec_len(v)) \
1090 _v(i) = ~0; \
1091 _v(i); \
1092})
1093
Neale Ranns947ea622018-06-07 23:48:20 -07001094/** \brief Search a vector for the index of the entry that matches.
1095
Dave Wallace64b3cc22019-04-05 10:30:44 -04001096 @param v Pointer to a vector
1097 @param E Pointer to entry to match
Neale Ranns947ea622018-06-07 23:48:20 -07001098 @param fn Comparison function !0 => match
1099 @return index of match or ~0
1100*/
1101#define vec_search_with_function(v,E,fn) \
1102({ \
1103 word _v(i) = 0; \
1104 while (_v(i) < vec_len(v)) \
1105 { \
1106 if (0 != fn(&(v)[_v(i)], (E))) \
1107 break; \
1108 _v(i)++; \
1109 } \
1110 if (_v(i) == vec_len(v)) \
1111 _v(i) = ~0; \
1112 _v(i); \
1113})
1114
Ed Warnickecb9cada2015-12-08 15:45:58 -07001115/** \brief Sort a vector using the supplied element comparison function
1116
Dave Barachf593b572020-04-24 16:07:37 -04001117 Does not depend on the underlying implementation to deal correctly
1118 with null, zero-long, or 1-long vectors
1119
Ed Warnickecb9cada2015-12-08 15:45:58 -07001120 @param vec vector to sort
1121 @param f comparison function
1122*/
Dave Barachf593b572020-04-24 16:07:37 -04001123#define vec_sort_with_function(vec,f) \
1124do { \
1125 if (vec_len (vec) > 1) \
1126 qsort (vec, vec_len (vec), sizeof (vec[0]), (void *) (f)); \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001127} while (0)
1128
1129/** \brief Make a vector containing a NULL terminated c-string.
1130
Dave Barachc3799992016-08-15 11:12:27 -04001131 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001132 @param S pointer to string buffer.
1133 @param L string length (NOT including the terminating NULL; a la strlen())
1134*/
Damjan Marion299571a2022-03-19 00:07:52 +01001135#define vec_validate_init_c_string(V, S, L) \
1136 do \
1137 { \
1138 vec_reset_length (V); \
1139 vec_validate (V, (L)); \
1140 if ((S) && (L)) \
1141 clib_memcpy_fast (V, (S), (L)); \
1142 (V)[(L)] = 0; \
1143 } \
1144 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001145
Chris Lukeb5850972016-05-03 16:34:59 -04001146/** \brief Test whether a vector is a NULL terminated c-string.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001147
Dave Barachc3799992016-08-15 11:12:27 -04001148 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001149 @return BOOLEAN indicating if the vector c-string is null terminated.
1150*/
1151#define vec_c_string_is_terminated(V) \
1152 (((V) != 0) && (vec_len (V) != 0) && ((V)[vec_len ((V)) - 1] == 0))
1153
Chris Lukeb5850972016-05-03 16:34:59 -04001154/** \brief (If necessary) NULL terminate a vector containing a c-string.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001155
Dave Barachc3799992016-08-15 11:12:27 -04001156 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001157 @return V (value-result macro parameter)
1158*/
Damjan Marion299571a2022-03-19 00:07:52 +01001159#define vec_terminate_c_string(V) \
1160 do \
1161 { \
1162 if (!vec_c_string_is_terminated (V)) \
1163 vec_add1 (V, 0); \
1164 } \
1165 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -07001166
1167#endif /* included_vec_h */