blob: 7e4cc0f8959c1983e3d1b3c3d6e5e4a02e71e702 [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~~~~~~~~
55 user header (aligned to uword boundary)
56 vector length: number of elements
57 user's pointer-> vector element #0
58 vector element #1
59 ...
60~~~~~~~~
61
Dave Barach2bc1eba2016-01-19 15:10:27 -050062 The user pointer contains the address of vector element # 0. Null
Dave Barachc3799992016-08-15 11:12:27 -040063 pointer vectors are valid and mean a zero length vector.
Dave Barach2bc1eba2016-01-19 15:10:27 -050064
65 You can reset the length of an allocated vector to zero via the
66 vec_reset_length(v) macro, or by setting the vector length field to
67 zero (e.g. _vec_len (v) = 0). Vec_reset_length(v) preferred: it
68 understands Null pointers.
Ed Warnickecb9cada2015-12-08 15:45:58 -070069
70 Typically, the header is not present. Headers allow for other
71 data structures to be built atop CLIB vectors.
72
Dave Wallace4659d0e2018-12-13 12:29:44 -050073 Users may specify the alignment for first data element of a vector
74 via the vec_*_aligned macros.
Ed Warnickecb9cada2015-12-08 15:45:58 -070075
Dave Wallace4659d0e2018-12-13 12:29:44 -050076 Vector elements can be any C type e.g. (int, double, struct bar).
Ed Warnickecb9cada2015-12-08 15:45:58 -070077 This is also true for data types built atop vectors (e.g. heap,
78 pool, etc.).
79
Dave Wallace4659d0e2018-12-13 12:29:44 -050080 Many macros have \_a variants supporting alignment of vector elements
81 and \_h variants supporting non-zero-length vector headers. The \_ha
82 variants support both. Additionally cacheline alignment within a
83 vector element structure can be specified using the
84 CLIB_CACHE_LINE_ALIGN_MARK() macro.
Ed Warnickecb9cada2015-12-08 15:45:58 -070085
Dave Barachc3799992016-08-15 11:12:27 -040086 Standard programming error: memorize a pointer to the ith element
Ed Warnickecb9cada2015-12-08 15:45:58 -070087 of a vector then expand it. Vectors expand by 3/2, so such code
88 may appear to work for a period of time. Memorize vector indices
Dave Barachc3799992016-08-15 11:12:27 -040089 which are invariant.
Ed Warnickecb9cada2015-12-08 15:45:58 -070090 */
91
92/** \brief Low-level resize allocation function, usually not called directly
93
94 @param v pointer to a vector
95 @param length_increment length increment in elements
96 @param data_bytes requested size in bytes
97 @param header_bytes header size in bytes (may be zero)
98 @param data_align alignment (may be zero)
Dave Baracha690fdb2020-01-21 12:34:55 -050099 @param numa_id numa id (may be zero)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700100 @return v_prime pointer to resized vector, may or may not equal v
101*/
Dave Barachc3799992016-08-15 11:12:27 -0400102void *vec_resize_allocate_memory (void *v,
103 word length_increment,
104 uword data_bytes,
Dave Baracha690fdb2020-01-21 12:34:55 -0500105 uword header_bytes, uword data_align,
106 uword numa_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700107
108/** \brief Low-level vector resize function, usually not called directly
109
110 @param v pointer to a vector
111 @param length_increment length increment in elements
112 @param data_bytes requested size in bytes
113 @param header_bytes header size in bytes (may be zero)
114 @param data_align alignment (may be zero)
Dave Baracha690fdb2020-01-21 12:34:55 -0500115 @param numa_id (may be ~0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700116 @return v_prime pointer to resized vector, may or may not equal v
117*/
118
Andreas Schultzc458c492020-03-26 14:18:52 +0000119#define _vec_resize_numa(V,L,DB,HB,A,S) \
120({ \
121 __typeof__ ((V)) _V; \
BenoƮt Ganned25147d2020-06-30 18:17:06 +0200122 _V = _vec_resize_inline((void *)V,L,DB,HB,clib_max((__alignof__((V)[0])),(A)),(S)); \
Andreas Schultzc458c492020-03-26 14:18:52 +0000123 _V; \
124})
Dave Baracha690fdb2020-01-21 12:34:55 -0500125
126#define _vec_resize(V,L,DB,HB,A) \
127 _vec_resize_numa(V,L,DB,HB,A,VEC_NUMA_UNSPECIFIED)
Damjan Marion2f25ef32018-05-04 20:45:41 +0200128
Ed Warnickecb9cada2015-12-08 15:45:58 -0700129always_inline void *
Damjan Marion2f25ef32018-05-04 20:45:41 +0200130_vec_resize_inline (void *v,
131 word length_increment,
Dave Baracha690fdb2020-01-21 12:34:55 -0500132 uword data_bytes, uword header_bytes, uword data_align,
133 uword numa_id)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700134{
Dave Barachc3799992016-08-15 11:12:27 -0400135 vec_header_t *vh = _vec_find (v);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700136 uword new_data_bytes, aligned_header_bytes;
Dave Baracha690fdb2020-01-21 12:34:55 -0500137 void *oldheap;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700138
139 aligned_header_bytes = vec_header_bytes (header_bytes);
140
141 new_data_bytes = data_bytes + aligned_header_bytes;
142
143 if (PREDICT_TRUE (v != 0))
144 {
Dave Barachc3799992016-08-15 11:12:27 -0400145 void *p = v - aligned_header_bytes;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700146
Dave Baracha690fdb2020-01-21 12:34:55 -0500147 if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
148 {
149 oldheap = clib_mem_get_per_cpu_heap ();
150 clib_mem_set_per_cpu_heap (clib_mem_get_per_numa_heap (numa_id));
151 }
152
Ed Warnickecb9cada2015-12-08 15:45:58 -0700153 /* Vector header must start heap object. */
154 ASSERT (clib_mem_is_heap_object (p));
155
156 /* Typically we'll not need to resize. */
157 if (new_data_bytes <= clib_mem_size (p))
158 {
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +0200159 CLIB_MEM_UNPOISON (v, data_bytes);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700160 vh->len += length_increment;
Dave Baracha690fdb2020-01-21 12:34:55 -0500161 if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
162 clib_mem_set_per_cpu_heap (oldheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700163 return v;
164 }
Dave Baracha690fdb2020-01-21 12:34:55 -0500165 if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
166 clib_mem_set_per_cpu_heap (oldheap);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700167 }
168
169 /* Slow path: call helper function. */
Dave Barachc3799992016-08-15 11:12:27 -0400170 return vec_resize_allocate_memory (v, length_increment, data_bytes,
171 header_bytes,
172 clib_max (sizeof (vec_header_t),
Dave Baracha690fdb2020-01-21 12:34:55 -0500173 data_align), numa_id);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700174}
175
Florin Corasef5d5aa2017-11-02 19:28:09 -0400176/** \brief Determine if vector will resize with next allocation
Dave Barach614ac5d2017-02-06 09:28:03 -0500177
178 @param v pointer to a vector
179 @param length_increment length increment in elements
180 @param data_bytes requested size in bytes
181 @param header_bytes header size in bytes (may be zero)
182 @param data_align alignment (may be zero)
Florin Corasef5d5aa2017-11-02 19:28:09 -0400183 @return 1 if vector will resize 0 otherwise
Dave Barach614ac5d2017-02-06 09:28:03 -0500184*/
185
186always_inline int
Damjan Marion66d4cb52022-03-17 18:59:46 +0100187_vec_resize_will_expand (void *v, uword n_elts, uword elt_size)
Dave Barach614ac5d2017-02-06 09:28:03 -0500188{
Dave Barach614ac5d2017-02-06 09:28:03 -0500189 if (PREDICT_TRUE (v != 0))
190 {
Dave Barach614ac5d2017-02-06 09:28:03 -0500191 /* Vector header must start heap object. */
Damjan Marion66d4cb52022-03-17 18:59:46 +0100192 ASSERT (clib_mem_is_heap_object (vec_header (v)));
Dave Barach614ac5d2017-02-06 09:28:03 -0500193
Damjan Marion66d4cb52022-03-17 18:59:46 +0100194 if (vec_mem_size (v) >= ((_vec_len (v) + n_elts)) * elt_size)
Florin Corasef5d5aa2017-11-02 19:28:09 -0400195 return 0;
Dave Barach614ac5d2017-02-06 09:28:03 -0500196 }
197 return 1;
198}
199
Miklos Tirpake700df82021-01-13 10:00:38 +0100200/** \brief Determine if vector will resize with next allocation
201
202 @param V pointer to a vector
203 @param N number of elements to add
204 @return 1 if vector will resize 0 otherwise
205*/
206
207#define vec_resize_will_expand(V, N) \
Damjan Marion66d4cb52022-03-17 18:59:46 +0100208 _vec_resize_will_expand (V, N, sizeof ((V)[0]))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700209
Dave Barachc3799992016-08-15 11:12:27 -0400210/** \brief Predicate function, says whether the supplied vector is a clib heap
Ed Warnickecb9cada2015-12-08 15:45:58 -0700211 object
212
213 @param v pointer to a vector
214 @return 0 or 1
Dave Barachc3799992016-08-15 11:12:27 -0400215*/
216always_inline uword
217clib_mem_is_vec (void *v)
218{
Damjan Marion66d4cb52022-03-17 18:59:46 +0100219 return clib_mem_is_heap_object (vec_header (v));
Dave Barachc3799992016-08-15 11:12:27 -0400220}
Ed Warnickecb9cada2015-12-08 15:45:58 -0700221
222/* Local variable naming macro (prevents collisions with other macro naming). */
223#define _v(var) _vec_##var
224
225/** \brief Resize a vector (general version).
226 Add N elements to end of given vector V, return pointer to start of vector.
227 Vector will have room for H header bytes and will have user's data aligned
228 at alignment A (rounded to next power of 2).
229
230 @param V pointer to a vector
231 @param N number of elements to add
232 @param H header size in bytes (may be zero)
233 @param A alignment (may be zero)
Dave Baracha690fdb2020-01-21 12:34:55 -0500234 @param S numa_id (may be zero)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700235 @return V (value-result macro parameter)
236*/
237
Dave Baracha690fdb2020-01-21 12:34:55 -0500238#define vec_resize_has(V,N,H,A,S) \
239do { \
240 word _v(n) = (N); \
241 word _v(l) = vec_len (V); \
242 V = _vec_resize_numa ((V), _v(n), \
243 (_v(l) + _v(n)) * sizeof ((V)[0]), \
244 (H), (A),(S)); \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700245} while (0)
246
Dave Baracha690fdb2020-01-21 12:34:55 -0500247/** \brief Resize a vector (less general version).
248 Add N elements to end of given vector V, return pointer to start of vector.
249 Vector will have room for H header bytes and will have user's data aligned
250 at alignment A (rounded to next power of 2).
251
252 @param V pointer to a vector
253 @param N number of elements to add
254 @param H header size in bytes (may be zero)
255 @param A alignment (may be zero)
256 @return V (value-result macro parameter)
257*/
258#define vec_resize_ha(V,N,H,A) vec_resize_has(V,N,H,A,VEC_NUMA_UNSPECIFIED)
259
Ed Warnickecb9cada2015-12-08 15:45:58 -0700260/** \brief Resize a vector (no header, unspecified alignment)
261 Add N elements to end of given vector V, return pointer to start of vector.
262 Vector will have room for H header bytes and will have user's data aligned
263 at alignment A (rounded to next power of 2).
264
265 @param V pointer to a vector
266 @param N number of elements to add
267 @return V (value-result macro parameter)
268*/
269#define vec_resize(V,N) vec_resize_ha(V,N,0,0)
270
271/** \brief Resize a vector (no header, alignment specified).
272 Add N elements to end of given vector V, return pointer to start of vector.
273 Vector will have room for H header bytes and will have user's data aligned
274 at alignment A (rounded to next power of 2).
275
276 @param V pointer to a vector
277 @param N number of elements to add
278 @param A alignment (may be zero)
279 @return V (value-result macro parameter)
280*/
281
282#define vec_resize_aligned(V,N,A) vec_resize_ha(V,N,0,A)
283
Dave Barachc3799992016-08-15 11:12:27 -0400284/** \brief Allocate space for N more elements
Ed Warnickecb9cada2015-12-08 15:45:58 -0700285
286 @param V pointer to a vector
287 @param N number of elements to add
288 @param H header size in bytes (may be zero)
289 @param A alignment (may be zero)
290 @return V (value-result macro parameter)
291*/
292
293#define vec_alloc_ha(V,N,H,A) \
294do { \
295 uword _v(l) = vec_len (V); \
296 vec_resize_ha (V, N, H, A); \
297 _vec_len (V) = _v(l); \
298} while (0)
299
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)
323 @return V new vector
324*/
Andreas Schultzc458c492020-03-26 14:18:52 +0000325#define vec_new_ha(T,N,H,A) \
326({ \
327 word _v(n) = (N); \
328 (T *)_vec_resize ((T *) 0, _v(n), _v(n) * sizeof (T), (H), (A)); \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700329})
330
Dave Barachc3799992016-08-15 11:12:27 -0400331/** \brief Create new vector of given type and length
Ed Warnickecb9cada2015-12-08 15:45:58 -0700332 (unspecified alignment, no header).
333
334 @param T type of elements in new vector
335 @param N number of elements to add
336 @return V new vector
337*/
338#define vec_new(T,N) vec_new_ha(T,N,0,0)
Dave Barachc3799992016-08-15 11:12:27 -0400339/** \brief Create new vector of given type and length
340 (alignment specified, no header).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700341
342 @param T type of elements in new vector
343 @param N number of elements to add
344 @param A alignment (may be zero)
345 @return V new vector
346*/
347#define vec_new_aligned(T,N,A) vec_new_ha(T,N,0,A)
348
Damjan Marion05563c92022-03-17 18:29:32 +0100349/** \brief Free vector's memory (no header).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350 @param V pointer to a vector
Ed Warnickecb9cada2015-12-08 15:45:58 -0700351 @return V (value-result parameter, V=0)
352*/
Damjan Marion05563c92022-03-17 18:29:32 +0100353#define vec_free(V) \
Damjan Mariona4a28f02022-03-17 15:46:25 +0100354 do \
355 { \
356 if (V) \
357 { \
358 clib_mem_free (vec_header ((V))); \
359 V = 0; \
360 } \
361 } \
362 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700363
Dave Barache09ae012020-08-19 06:59:53 -0400364void vec_free_not_inline (void *v);
365
Ed Warnickecb9cada2015-12-08 15:45:58 -0700366/**\brief Free vector user header (syntactic sugar)
367 @param h vector header
368 @void
369*/
370#define vec_free_header(h) clib_mem_free (h)
371
372/** \brief Return copy of vector (general version).
373
374 @param V pointer to a vector
375 @param H size of header in bytes
376 @param A alignment (may be zero)
Dave Baracha690fdb2020-01-21 12:34:55 -0500377 @param S numa (may be VEC_NUMA_UNSPECIFIED)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700378
379 @return Vdup copy of vector
380*/
381
Dave Baracha690fdb2020-01-21 12:34:55 -0500382#define vec_dup_ha_numa(V,H,A,S) \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700383({ \
384 __typeof__ ((V)[0]) * _v(v) = 0; \
385 uword _v(l) = vec_len (V); \
386 if (_v(l) > 0) \
387 { \
Dave Baracha690fdb2020-01-21 12:34:55 -0500388 vec_resize_has (_v(v), _v(l), (H), (A), (S)); \
Dave Barach178cf492018-11-13 16:34:13 -0500389 clib_memcpy_fast (_v(v), (V), _v(l) * sizeof ((V)[0]));\
Ed Warnickecb9cada2015-12-08 15:45:58 -0700390 } \
391 _v(v); \
392})
393
Dave Baracha690fdb2020-01-21 12:34:55 -0500394/** \brief Return copy of vector (VEC_NUMA_UNSPECIFIED).
395
396 @param V pointer to a vector
397 @param H size of header in bytes
398 @param A alignment (may be zero)
399
400 @return Vdup copy of vector
401*/
402#define vec_dup_ha(V,H,A) \
403 vec_dup_ha_numa(V,H,A,VEC_NUMA_UNSPECIFIED)
404
405
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*/
437#define vec_clone(NEW_V,OLD_V) \
438do { \
439 (NEW_V) = 0; \
440 (NEW_V) = _vec_resize ((NEW_V), vec_len (OLD_V), \
441 vec_len (OLD_V) * sizeof ((NEW_V)[0]), (0), (0)); \
442} while (0)
443
444/** \brief Make sure vector is long enough for given index (general version).
445
Dave Barachc3799992016-08-15 11:12:27 -0400446 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700447 @param I vector index which will be valid upon return
448 @param H header size in bytes (may be zero)
449 @param A alignment (may be zero)
Dave Baracha690fdb2020-01-21 12:34:55 -0500450 @param N numa_id (may be zero)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700451 @return V (value-result macro parameter)
452*/
453
Dave Baracha690fdb2020-01-21 12:34:55 -0500454#define vec_validate_han(V,I,H,A,N) \
455do { \
456 void *oldheap; \
457 STATIC_ASSERT(A==0 || ((A % sizeof(V[0]))==0) \
458 || ((sizeof(V[0]) % A) == 0), \
459 "vector validate aligned on incorrectly sized object"); \
460 word _v(i) = (I); \
461 word _v(l) = vec_len (V); \
462 if (_v(i) >= _v(l)) \
463 { \
464 /* switch to the per-numa heap if directed */ \
465 if (PREDICT_FALSE(N != VEC_NUMA_UNSPECIFIED)) \
466 { \
467 oldheap = clib_mem_get_per_cpu_heap(); \
468 clib_mem_set_per_cpu_heap (clib_mem_get_per_numa_heap(N)); \
469 } \
470 \
471 vec_resize_ha ((V), 1 + (_v(i) - _v(l)), (H), (A)); \
472 /* Must zero new space since user may have previously \
473 used e.g. _vec_len (v) -= 10 */ \
474 clib_memset ((V) + _v(l), 0, \
475 (1 + (_v(i) - _v(l))) * sizeof ((V)[0])); \
476 /* Switch back to the global heap */ \
477 if (PREDICT_FALSE (N != VEC_NUMA_UNSPECIFIED)) \
478 clib_mem_set_per_cpu_heap (oldheap); \
479 } \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700480} while (0)
481
Dave Baracha690fdb2020-01-21 12:34:55 -0500482#define vec_validate_ha(V,I,H,A) vec_validate_han(V,I,H,A,VEC_NUMA_UNSPECIFIED)
483
Dave Barachc3799992016-08-15 11:12:27 -0400484/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700485 (no header, unspecified alignment)
486
Dave Barachc3799992016-08-15 11:12:27 -0400487 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700488 @param I vector index which will be valid upon return
489 @return V (value-result macro parameter)
490*/
491#define vec_validate(V,I) vec_validate_ha(V,I,0,0)
492
Dave Barachc3799992016-08-15 11:12:27 -0400493/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700494 (no header, specified alignment)
495
Dave Barachc3799992016-08-15 11:12:27 -0400496 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700497 @param I vector index which will be valid upon return
498 @param A alignment (may be zero)
499 @return V (value-result macro parameter)
500*/
501
502#define vec_validate_aligned(V,I,A) vec_validate_ha(V,I,0,A)
503
Dave Barachc3799992016-08-15 11:12:27 -0400504/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700505 and initialize empty space (general version)
506
Dave Barachc3799992016-08-15 11:12:27 -0400507 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700508 @param I vector index which will be valid upon return
509 @param INIT initial value (can be a complex expression!)
510 @param H header size in bytes (may be zero)
511 @param A alignment (may be zero)
512 @return V (value-result macro parameter)
513*/
514#define vec_validate_init_empty_ha(V,I,INIT,H,A) \
515do { \
516 word _v(i) = (I); \
517 word _v(l) = vec_len (V); \
518 if (_v(i) >= _v(l)) \
519 { \
520 vec_resize_ha ((V), 1 + (_v(i) - _v(l)), (H), (A)); \
521 while (_v(l) <= _v(i)) \
522 { \
523 (V)[_v(l)] = (INIT); \
524 _v(l)++; \
525 } \
526 } \
527} while (0)
528
Dave Barachc3799992016-08-15 11:12:27 -0400529/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700530 and initialize empty space (no header, unspecified alignment)
531
Dave Barachc3799992016-08-15 11:12:27 -0400532 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700533 @param I vector index which will be valid upon return
534 @param INIT initial value (can be a complex expression!)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700535 @return V (value-result macro parameter)
536*/
537
538#define vec_validate_init_empty(V,I,INIT) \
539 vec_validate_init_empty_ha(V,I,INIT,0,0)
540
Dave Barachc3799992016-08-15 11:12:27 -0400541/** \brief Make sure vector is long enough for given index
Ed Warnickecb9cada2015-12-08 15:45:58 -0700542 and initialize empty space (no header, alignment alignment)
543
Dave Barachc3799992016-08-15 11:12:27 -0400544 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700545 @param I vector index which will be valid upon return
546 @param INIT initial value (can be a complex expression!)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700547 @param A alignment (may be zero)
548 @return V (value-result macro parameter)
549*/
Damjan Marion7d272182017-06-05 21:53:39 +0200550#define vec_validate_init_empty_aligned(V,I,INIT,A) \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700551 vec_validate_init_empty_ha(V,I,INIT,0,A)
552
Dave Barachc3799992016-08-15 11:12:27 -0400553/** \brief Add 1 element to end of vector (general version).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700554
555 @param V pointer to a vector
556 @param E element to add
557 @param H header size in bytes (may be zero)
558 @param A alignment (may be zero)
559 @return V (value-result macro parameter)
560*/
561#define vec_add1_ha(V,E,H,A) \
562do { \
563 word _v(l) = vec_len (V); \
564 V = _vec_resize ((V), 1, (_v(l) + 1) * sizeof ((V)[0]), (H), (A)); \
565 (V)[_v(l)] = (E); \
566} while (0)
567
Dave Barachc3799992016-08-15 11:12:27 -0400568/** \brief Add 1 element to end of vector (unspecified alignment).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700569
570 @param V pointer to a vector
571 @param E element to add
572 @return V (value-result macro parameter)
573*/
574#define vec_add1(V,E) vec_add1_ha(V,E,0,0)
575
Dave Barachc3799992016-08-15 11:12:27 -0400576/** \brief Add 1 element to end of vector (alignment specified).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700577
578 @param V pointer to a vector
579 @param E element to add
Ed Warnickecb9cada2015-12-08 15:45:58 -0700580 @param A alignment (may be zero)
581 @return V (value-result macro parameter)
582*/
583#define vec_add1_aligned(V,E,A) vec_add1_ha(V,E,0,A)
584
Dave Barachc3799992016-08-15 11:12:27 -0400585/** \brief Add N elements to end of vector V,
586 return pointer to new elements in P. (general version)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700587
588 @param V pointer to a vector
589 @param P pointer to new vector element(s)
590 @param N number of elements to add
591 @param H header size in bytes (may be zero)
592 @param A alignment (may be zero)
593 @return V and P (value-result macro parameters)
594*/
595#define vec_add2_ha(V,P,N,H,A) \
596do { \
597 word _v(n) = (N); \
598 word _v(l) = vec_len (V); \
599 V = _vec_resize ((V), _v(n), (_v(l) + _v(n)) * sizeof ((V)[0]), (H), (A)); \
600 P = (V) + _v(l); \
601} while (0)
602
Dave Barachc3799992016-08-15 11:12:27 -0400603/** \brief Add N elements to end of vector V,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700604 return pointer to new elements in P. (no header, unspecified alignment)
605
606 @param V pointer to a vector
607 @param P pointer to new vector element(s)
608 @param N number of elements to add
609 @return V and P (value-result macro parameters)
610*/
611
612#define vec_add2(V,P,N) vec_add2_ha(V,P,N,0,0)
613
Dave Barachc3799992016-08-15 11:12:27 -0400614/** \brief Add N elements to end of vector V,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700615 return pointer to new elements in P. (no header, alignment specified)
616
617 @param V pointer to a vector
618 @param P pointer to new vector element(s)
619 @param N number of elements to add
620 @param A alignment (may be zero)
621 @return V and P (value-result macro parameters)
622*/
623
624#define vec_add2_aligned(V,P,N,A) vec_add2_ha(V,P,N,0,A)
625
Dave Barachc3799992016-08-15 11:12:27 -0400626/** \brief Add N elements to end of vector V (general version)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700627
628 @param V pointer to a vector
629 @param E pointer to element(s) to add
630 @param N number of elements to add
631 @param H header size in bytes (may be zero)
632 @param A alignment (may be zero)
633 @return V (value-result macro parameter)
634*/
BenoƮt Ganne1a3e08a2021-02-11 19:46:43 +0100635#define vec_add_ha(V, E, N, H, A) \
636 do \
637 { \
638 word _v (n) = (N); \
639 if (PREDICT_TRUE (_v (n) > 0)) \
640 { \
641 word _v (l) = vec_len (V); \
642 V = _vec_resize ((V), _v (n), (_v (l) + _v (n)) * sizeof ((V)[0]), \
643 (H), (A)); \
644 clib_memcpy_fast ((V) + _v (l), (E), _v (n) * sizeof ((V)[0])); \
645 } \
646 } \
647 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700648
649/** \brief Add N elements to end of vector V (no header, unspecified alignment)
650
651 @param V pointer to a vector
652 @param E pointer to element(s) to add
653 @param N number of elements to add
654 @return V (value-result macro parameter)
655*/
656#define vec_add(V,E,N) vec_add_ha(V,E,N,0,0)
657
658/** \brief Add N elements to end of vector V (no header, specified alignment)
659
660 @param V pointer to a vector
661 @param E pointer to element(s) to add
662 @param N number of elements to add
663 @param A alignment (may be zero)
664 @return V (value-result macro parameter)
665*/
666#define vec_add_aligned(V,E,N,A) vec_add_ha(V,E,N,0,A)
667
Dave Barachc3799992016-08-15 11:12:27 -0400668/** \brief Returns last element of a vector and decrements its length
Ed Warnickecb9cada2015-12-08 15:45:58 -0700669
670 @param V pointer to a vector
671 @return E element removed from the end of the vector
672*/
673#define vec_pop(V) \
674({ \
675 uword _v(l) = vec_len (V); \
676 ASSERT (_v(l) > 0); \
677 _v(l) -= 1; \
678 _vec_len (V) = _v (l); \
679 (V)[_v(l)]; \
680})
681
Dave Barachc3799992016-08-15 11:12:27 -0400682/** \brief Set E to the last element of a vector, decrement vector length
Ed Warnickecb9cada2015-12-08 15:45:58 -0700683 @param V pointer to a vector
684 @param E pointer to the last vector element
Dave Barachc3799992016-08-15 11:12:27 -0400685 @return E element removed from the end of the vector
Ed Warnickecb9cada2015-12-08 15:45:58 -0700686 (value-result macro parameter
687*/
688
689#define vec_pop2(V,E) \
690({ \
691 uword _v(l) = vec_len (V); \
692 if (_v(l) > 0) (E) = vec_pop (V); \
693 _v(l) > 0; \
694})
695
Dave Barachc3799992016-08-15 11:12:27 -0400696/** \brief Insert N vector elements starting at element M,
697 initialize new elements (general version).
Ed Warnickecb9cada2015-12-08 15:45:58 -0700698
Dave Barachc3799992016-08-15 11:12:27 -0400699 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700700 @param N number of elements to insert
701 @param M insertion point
702 @param INIT initial value (can be a complex expression!)
703 @param H header size in bytes (may be zero)
704 @param A alignment (may be zero)
705 @return V (value-result macro parameter)
706*/
707#define vec_insert_init_empty_ha(V,N,M,INIT,H,A) \
708do { \
709 word _v(l) = vec_len (V); \
710 word _v(n) = (N); \
711 word _v(m) = (M); \
712 V = _vec_resize ((V), \
713 _v(n), \
714 (_v(l) + _v(n))*sizeof((V)[0]), \
715 (H), (A)); \
716 ASSERT (_v(m) <= _v(l)); \
717 memmove ((V) + _v(m) + _v(n), \
718 (V) + _v(m), \
719 (_v(l) - _v(m)) * sizeof ((V)[0])); \
Dave Barachb7b92992018-10-17 10:38:51 -0400720 clib_memset ((V) + _v(m), INIT, _v(n) * sizeof ((V)[0])); \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700721} while (0)
722
Dave Barachc3799992016-08-15 11:12:27 -0400723/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700724 initialize new elements to zero (general version)
725
Dave Barachc3799992016-08-15 11:12:27 -0400726 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700727 @param N number of elements to insert
728 @param M insertion point
729 @param H header size in bytes (may be zero)
730 @param A alignment (may be zero)
731 @return V (value-result macro parameter)
732*/
733#define vec_insert_ha(V,N,M,H,A) vec_insert_init_empty_ha(V,N,M,0,H,A)
734
Dave Barachc3799992016-08-15 11:12:27 -0400735/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700736 initialize new elements to zero (no header, unspecified alignment)
737
Dave Barachc3799992016-08-15 11:12:27 -0400738 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700739 @param N number of elements to insert
740 @param M insertion point
741 @return V (value-result macro parameter)
742*/
743#define vec_insert(V,N,M) vec_insert_ha(V,N,M,0,0)
744
Dave Barachc3799992016-08-15 11:12:27 -0400745/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700746 initialize new elements to zero (no header, alignment specified)
747
Dave Barachc3799992016-08-15 11:12:27 -0400748 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700749 @param N number of elements to insert
750 @param M insertion point
751 @param A alignment (may be zero)
752 @return V (value-result macro parameter)
753*/
754#define vec_insert_aligned(V,N,M,A) vec_insert_ha(V,N,M,0,A)
755
Dave Barachc3799992016-08-15 11:12:27 -0400756/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700757 initialize new elements (no header, unspecified alignment)
758
Dave Barachc3799992016-08-15 11:12:27 -0400759 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700760 @param N number of elements to insert
761 @param M insertion point
762 @param INIT initial value (can be a complex expression!)
763 @return V (value-result macro parameter)
764*/
765
766#define vec_insert_init_empty(V,N,M,INIT) \
767 vec_insert_init_empty_ha(V,N,M,INIT,0,0)
768/* Resize vector by N elements starting from element M, initialize new elements to INIT (alignment specified, no header). */
769
Dave Barachc3799992016-08-15 11:12:27 -0400770/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700771 initialize new elements (no header, specified alignment)
772
Dave Barachc3799992016-08-15 11:12:27 -0400773 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700774 @param N number of elements to insert
775 @param M insertion point
776 @param INIT initial value (can be a complex expression!)
777 @param A alignment (may be zero)
778 @return V (value-result macro parameter)
779*/
780#define vec_insert_init_empty_aligned(V,N,M,INIT,A) \
781 vec_insert_init_empty_ha(V,N,M,INIT,0,A)
782
Dave Barachc3799992016-08-15 11:12:27 -0400783/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700784 insert given elements (general version)
785
Dave Barachc3799992016-08-15 11:12:27 -0400786 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700787 @param E element(s) to insert
788 @param N number of elements to insert
789 @param M insertion point
790 @param H header size in bytes (may be zero)
791 @param A alignment (may be zero)
792 @return V (value-result macro parameter)
793*/
794
BenoƮt Ganne1a3e08a2021-02-11 19:46:43 +0100795#define vec_insert_elts_ha(V, E, N, M, H, A) \
796 do \
797 { \
798 word _v (n) = (N); \
799 if (PREDICT_TRUE (_v (n) > 0)) \
800 { \
801 word _v (l) = vec_len (V); \
802 word _v (m) = (M); \
803 V = _vec_resize ((V), _v (n), (_v (l) + _v (n)) * sizeof ((V)[0]), \
804 (H), (A)); \
805 ASSERT (_v (m) <= _v (l)); \
806 memmove ((V) + _v (m) + _v (n), (V) + _v (m), \
807 (_v (l) - _v (m)) * sizeof ((V)[0])); \
808 clib_memcpy_fast ((V) + _v (m), (E), _v (n) * sizeof ((V)[0])); \
809 } \
810 } \
811 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700812
Dave Barachc3799992016-08-15 11:12:27 -0400813/** \brief Insert N vector elements starting at element M,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700814 insert given elements (no header, unspecified alignment)
815
Dave Barachc3799992016-08-15 11:12:27 -0400816 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -0700817 @param E element(s) to insert
818 @param N number of elements to insert
819 @param M insertion point
820 @return V (value-result macro parameter)
821*/
822#define vec_insert_elts(V,E,N,M) vec_insert_elts_ha(V,E,N,M,0,0)
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 (no header, specified alignment)
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 A alignment (may be zero)
832 @return V (value-result macro parameter)
833*/
834#define vec_insert_elts_aligned(V,E,N,M,A) vec_insert_elts_ha(V,E,N,M,0,A)
835
Dave Barachc3799992016-08-15 11:12:27 -0400836/** \brief Delete N elements starting at element M
Ed Warnickecb9cada2015-12-08 15:45:58 -0700837
838 @param V pointer to a vector
839 @param N number of elements to delete
840 @param M first element to delete
841 @return V (value-result macro parameter)
842*/
843#define vec_delete(V,N,M) \
844do { \
845 word _v(l) = vec_len (V); \
846 word _v(n) = (N); \
847 word _v(m) = (M); \
848 /* Copy over deleted elements. */ \
849 if (_v(l) - _v(n) - _v(m) > 0) \
850 memmove ((V) + _v(m), (V) + _v(m) + _v(n), \
851 (_v(l) - _v(n) - _v(m)) * sizeof ((V)[0])); \
852 /* Zero empty space at end (for future re-allocation). */ \
853 if (_v(n) > 0) \
Dave Barachb7b92992018-10-17 10:38:51 -0400854 clib_memset ((V) + _v(l) - _v(n), 0, _v(n) * sizeof ((V)[0])); \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700855 _vec_len (V) -= _v(n); \
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +0200856 CLIB_MEM_POISON(vec_end(V), _v(n) * sizeof ((V)[0])); \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700857} while (0)
858
859/** \brief Delete the element at index I
860
861 @param V pointer to a vector
862 @param I index to delete
863*/
864#define vec_del1(v,i) \
865do { \
866 uword _vec_del_l = _vec_len (v) - 1; \
867 uword _vec_del_i = (i); \
868 if (_vec_del_i < _vec_del_l) \
869 (v)[_vec_del_i] = (v)[_vec_del_l]; \
870 _vec_len (v) = _vec_del_l; \
BenoƮt Ganne9fb6d402019-04-15 15:28:21 +0200871 CLIB_MEM_POISON(vec_end(v), sizeof ((v)[0])); \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700872} while (0)
873
874/** \brief Append v2 after v1. Result in v1.
875 @param V1 target vector
876 @param V2 vector to append
877*/
Dave Barachc3799992016-08-15 11:12:27 -0400878
BenoƮt Ganne1a3e08a2021-02-11 19:46:43 +0100879#define vec_append(v1, v2) \
880 do \
881 { \
882 uword _v (l1) = vec_len (v1); \
883 uword _v (l2) = vec_len (v2); \
884 \
885 if (PREDICT_TRUE (_v (l2) > 0)) \
886 { \
887 v1 = _vec_resize ((v1), _v (l2), \
888 (_v (l1) + _v (l2)) * sizeof ((v1)[0]), 0, 0); \
889 clib_memcpy_fast ((v1) + _v (l1), (v2), \
890 _v (l2) * sizeof ((v2)[0])); \
891 } \
892 } \
893 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700894
895/** \brief Append v2 after v1. Result in v1. Specified alignment.
896 @param V1 target vector
897 @param V2 vector to append
898 @param align required alignment
899*/
Dave Barachc3799992016-08-15 11:12:27 -0400900
BenoƮt Ganne1a3e08a2021-02-11 19:46:43 +0100901#define vec_append_aligned(v1, v2, align) \
902 do \
903 { \
904 uword _v (l1) = vec_len (v1); \
905 uword _v (l2) = vec_len (v2); \
906 \
907 if (PREDICT_TRUE (_v (l2) > 0)) \
908 { \
909 v1 = _vec_resize ( \
910 (v1), _v (l2), (_v (l1) + _v (l2)) * sizeof ((v1)[0]), 0, align); \
911 clib_memcpy_fast ((v1) + _v (l1), (v2), \
912 _v (l2) * sizeof ((v2)[0])); \
913 } \
914 } \
915 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700916
917/** \brief Prepend v2 before v1. Result in v1.
918 @param V1 target vector
919 @param V2 vector to prepend
920*/
921
BenoƮt Ganne1a3e08a2021-02-11 19:46:43 +0100922#define vec_prepend(v1, v2) \
923 do \
924 { \
925 uword _v (l1) = vec_len (v1); \
926 uword _v (l2) = vec_len (v2); \
927 \
928 if (PREDICT_TRUE (_v (l2) > 0)) \
929 { \
930 v1 = _vec_resize ((v1), _v (l2), \
931 (_v (l1) + _v (l2)) * sizeof ((v1)[0]), 0, 0); \
932 memmove ((v1) + _v (l2), (v1), _v (l1) * sizeof ((v1)[0])); \
933 clib_memcpy_fast ((v1), (v2), _v (l2) * sizeof ((v2)[0])); \
934 } \
935 } \
936 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700937
938/** \brief Prepend v2 before v1. Result in v1. Specified alignment
939 @param V1 target vector
940 @param V2 vector to prepend
941 @param align required alignment
942*/
943
BenoƮt Ganne1a3e08a2021-02-11 19:46:43 +0100944#define vec_prepend_aligned(v1, v2, align) \
945 do \
946 { \
947 uword _v (l1) = vec_len (v1); \
948 uword _v (l2) = vec_len (v2); \
949 \
950 if (PREDICT_TRUE (_v (l2) > 0)) \
951 { \
952 v1 = _vec_resize ( \
953 (v1), _v (l2), (_v (l1) + _v (l2)) * sizeof ((v1)[0]), 0, align); \
954 memmove ((v1) + _v (l2), (v1), _v (l1) * sizeof ((v1)[0])); \
955 clib_memcpy_fast ((v1), (v2), _v (l2) * sizeof ((v2)[0])); \
956 } \
957 } \
958 while (0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700959
960/** \brief Zero all vector elements. Null-pointer tolerant.
961 @param var Vector to zero
962*/
963#define vec_zero(var) \
964do { \
965 if (var) \
Dave Barachb7b92992018-10-17 10:38:51 -0400966 clib_memset ((var), 0, vec_len (var) * sizeof ((var)[0])); \
Ed Warnickecb9cada2015-12-08 15:45:58 -0700967} while (0)
968
969/** \brief Set all vector elements to given value. Null-pointer tolerant.
970 @param v vector to set
971 @param val value for each vector element
972*/
973#define vec_set(v,val) \
974do { \
975 word _v(i); \
976 __typeof__ ((v)[0]) _val = (val); \
977 for (_v(i) = 0; _v(i) < vec_len (v); _v(i)++) \
978 (v)[_v(i)] = _val; \
979} while (0)
980
981#ifdef CLIB_UNIX
982#include <stdlib.h> /* for qsort */
983#endif
984
985/** \brief Compare two vectors, not NULL-pointer tolerant
986
987 @param v1 Pointer to a vector
988 @param v2 Pointer to a vector
989 @return 1 if equal, 0 if unequal
990*/
991#define vec_is_equal(v1,v2) \
992 (vec_len (v1) == vec_len (v2) && ! memcmp ((v1), (v2), vec_len (v1) * sizeof ((v1)[0])))
993
994/** \brief Compare two vectors (only applicable to vectors of signed numbers).
Dave Barachc3799992016-08-15 11:12:27 -0400995 Used in qsort compare functions.
996
Ed Warnickecb9cada2015-12-08 15:45:58 -0700997 @param v1 Pointer to a vector
998 @param v2 Pointer to a vector
999 @return -1, 0, +1
1000*/
1001#define vec_cmp(v1,v2) \
1002({ \
1003 word _v(i), _v(cmp), _v(l); \
1004 _v(l) = clib_min (vec_len (v1), vec_len (v2)); \
1005 _v(cmp) = 0; \
1006 for (_v(i) = 0; _v(i) < _v(l); _v(i)++) { \
1007 _v(cmp) = (v1)[_v(i)] - (v2)[_v(i)]; \
1008 if (_v(cmp)) \
1009 break; \
1010 } \
1011 if (_v(cmp) == 0 && _v(l) > 0) \
1012 _v(cmp) = vec_len(v1) - vec_len(v2); \
1013 (_v(cmp) < 0 ? -1 : (_v(cmp) > 0 ? +1 : 0)); \
1014})
1015
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001016/** \brief Search a vector for the index of the entry that matches.
1017
Dave Wallace64b3cc22019-04-05 10:30:44 -04001018 @param v Pointer to a vector
1019 @param E Entry to match
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001020 @return index of match or ~0
1021*/
1022#define vec_search(v,E) \
1023({ \
1024 word _v(i) = 0; \
1025 while (_v(i) < vec_len(v)) \
1026 { \
Andrew Yourtchenkof908a032017-06-20 12:26:23 +02001027 if ((v)[_v(i)] == E) \
Neale Ranns0bfe5d82016-08-25 15:29:12 +01001028 break; \
1029 _v(i)++; \
1030 } \
1031 if (_v(i) == vec_len(v)) \
1032 _v(i) = ~0; \
1033 _v(i); \
1034})
1035
Neale Ranns947ea622018-06-07 23:48:20 -07001036/** \brief Search a vector for the index of the entry that matches.
1037
Dave Wallace64b3cc22019-04-05 10:30:44 -04001038 @param v Pointer to a vector
1039 @param E Pointer to entry to match
Neale Ranns947ea622018-06-07 23:48:20 -07001040 @param fn Comparison function !0 => match
1041 @return index of match or ~0
1042*/
1043#define vec_search_with_function(v,E,fn) \
1044({ \
1045 word _v(i) = 0; \
1046 while (_v(i) < vec_len(v)) \
1047 { \
1048 if (0 != fn(&(v)[_v(i)], (E))) \
1049 break; \
1050 _v(i)++; \
1051 } \
1052 if (_v(i) == vec_len(v)) \
1053 _v(i) = ~0; \
1054 _v(i); \
1055})
1056
Ed Warnickecb9cada2015-12-08 15:45:58 -07001057/** \brief Sort a vector using the supplied element comparison function
1058
Dave Barachf593b572020-04-24 16:07:37 -04001059 Does not depend on the underlying implementation to deal correctly
1060 with null, zero-long, or 1-long vectors
1061
Ed Warnickecb9cada2015-12-08 15:45:58 -07001062 @param vec vector to sort
1063 @param f comparison function
1064*/
Dave Barachf593b572020-04-24 16:07:37 -04001065#define vec_sort_with_function(vec,f) \
1066do { \
1067 if (vec_len (vec) > 1) \
1068 qsort (vec, vec_len (vec), sizeof (vec[0]), (void *) (f)); \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001069} while (0)
1070
1071/** \brief Make a vector containing a NULL terminated c-string.
1072
Dave Barachc3799992016-08-15 11:12:27 -04001073 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001074 @param S pointer to string buffer.
1075 @param L string length (NOT including the terminating NULL; a la strlen())
1076*/
1077#define vec_validate_init_c_string(V, S, L) \
1078 do { \
1079 vec_reset_length (V); \
1080 vec_validate ((V), (L)); \
1081 if ((S) && (L)) \
Dave Barach178cf492018-11-13 16:34:13 -05001082 clib_memcpy_fast ((V), (S), (L)); \
Ed Warnickecb9cada2015-12-08 15:45:58 -07001083 (V)[(L)] = 0; \
1084 } while (0)
1085
1086
Chris Lukeb5850972016-05-03 16:34:59 -04001087/** \brief Test whether a vector is a NULL terminated c-string.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001088
Dave Barachc3799992016-08-15 11:12:27 -04001089 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001090 @return BOOLEAN indicating if the vector c-string is null terminated.
1091*/
1092#define vec_c_string_is_terminated(V) \
1093 (((V) != 0) && (vec_len (V) != 0) && ((V)[vec_len ((V)) - 1] == 0))
1094
Chris Lukeb5850972016-05-03 16:34:59 -04001095/** \brief (If necessary) NULL terminate a vector containing a c-string.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001096
Dave Barachc3799992016-08-15 11:12:27 -04001097 @param V (possibly NULL) pointer to a vector.
Ed Warnickecb9cada2015-12-08 15:45:58 -07001098 @return V (value-result macro parameter)
1099*/
1100#define vec_terminate_c_string(V) \
1101 do { \
1102 u32 vl = vec_len ((V)); \
1103 if (!vec_c_string_is_terminated(V)) \
1104 { \
1105 vec_validate ((V), vl); \
1106 (V)[vl] = 0; \
1107 } \
1108 } while (0)
1109
1110#endif /* included_vec_h */
1111
Dave Barachc3799992016-08-15 11:12:27 -04001112
1113/*
1114 * fd.io coding-style-patch-verification: ON
1115 *
1116 * Local Variables:
1117 * eval: (c-set-style "gnu")
1118 * End:
1119 */