tests: fix the RND_SEED parsing
[vpp.git] / src / vppinfra / vec.h
1 /*
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
41 #include <vppinfra/clib.h>      /* word, etc */
42 #include <vppinfra/mem.h>       /* clib_mem_free */
43 #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
62    The user pointer contains the address of vector element # 0.  Null
63    pointer vectors are valid and mean a zero length vector.
64
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.
69
70    Typically, the header is not present.  Headers allow for other
71    data structures to be built atop CLIB vectors.
72
73    Users may specify the alignment for first data element of a vector
74    via the vec_*_aligned macros.
75
76    Vector elements can be any C type e.g. (int, double, struct bar).
77    This is also true for data types built atop vectors (e.g. heap,
78    pool, etc.).
79
80    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.
85
86    Standard programming error: memorize a pointer to the ith element
87    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
89    which are invariant.
90  */
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)
99     @param numa_id numa id (may be zero)
100     @return v_prime pointer to resized vector, may or may not equal v
101 */
102 void *vec_resize_allocate_memory (void *v,
103                                   word length_increment,
104                                   uword data_bytes,
105                                   uword header_bytes, uword data_align,
106                                   uword numa_id);
107
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)
115     @param numa_id (may be ~0)
116     @return v_prime pointer to resized vector, may or may not equal v
117 */
118
119 #define _vec_resize_numa(V,L,DB,HB,A,S)                                 \
120 ({                                                                      \
121   __typeof__ ((V)) _V;                                                  \
122   _V = _vec_resize_inline((void *)V,L,DB,HB,clib_max((__alignof__((V)[0])),(A)),(S)); \
123   _V;                                                                   \
124 })
125
126 #define _vec_resize(V,L,DB,HB,A)  \
127   _vec_resize_numa(V,L,DB,HB,A,VEC_NUMA_UNSPECIFIED)
128
129 always_inline void *
130 _vec_resize_inline (void *v,
131                     word length_increment,
132                     uword data_bytes, uword header_bytes, uword data_align,
133                     uword numa_id)
134 {
135   vec_header_t *vh = _vec_find (v);
136   uword new_data_bytes, aligned_header_bytes;
137   void *oldheap;
138
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     {
145       void *p = v - aligned_header_bytes;
146
147       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
153       /* 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         {
159           CLIB_MEM_UNPOISON (v, data_bytes);
160           vh->len += length_increment;
161           if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
162             clib_mem_set_per_cpu_heap (oldheap);
163           return v;
164         }
165       if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
166         clib_mem_set_per_cpu_heap (oldheap);
167     }
168
169   /* Slow path: call helper function. */
170   return vec_resize_allocate_memory (v, length_increment, data_bytes,
171                                      header_bytes,
172                                      clib_max (sizeof (vec_header_t),
173                                                data_align), numa_id);
174 }
175
176 /** \brief Determine if vector will resize with next allocation
177
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)
183     @return 1 if vector will resize 0 otherwise
184 */
185
186 always_inline int
187 _vec_resize_will_expand (void *v, uword n_elts, uword elt_size)
188 {
189   if (PREDICT_TRUE (v != 0))
190     {
191       /* Vector header must start heap object. */
192       ASSERT (clib_mem_is_heap_object (vec_header (v)));
193
194       if (vec_mem_size (v) >= ((_vec_len (v) + n_elts)) * elt_size)
195         return 0;
196     }
197   return 1;
198 }
199
200 /** \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)                                          \
208   _vec_resize_will_expand (V, N, sizeof ((V)[0]))
209
210 /** \brief Predicate function, says whether the supplied vector is a clib heap
211     object
212
213     @param v pointer to a vector
214     @return 0 or 1
215 */
216 always_inline uword
217 clib_mem_is_vec (void *v)
218 {
219   return clib_mem_is_heap_object (vec_header (v));
220 }
221
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)
234     @param S numa_id (may be zero)
235     @return V (value-result macro parameter)
236 */
237
238 #define vec_resize_has(V,N,H,A,S)                               \
239 do {                                                            \
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));                        \
245 } while (0)
246
247 /** \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
260 /** \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
284 /** \brief Allocate space for N more elements
285
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)                   \
294 do {                                            \
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
300 /** \brief Allocate space for N more elements
301     (no header, unspecified alignment)
302
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 */
325 #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));      \
329 })
330
331 /** \brief Create new vector of given type and length
332     (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)
339 /** \brief Create new vector of given type and length
340     (alignment specified, no header).
341
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
349 /** \brief Free vector's memory (no header).
350     @param V pointer to a vector
351     @return V (value-result parameter, V=0)
352 */
353 #define vec_free(V)                                                           \
354   do                                                                          \
355     {                                                                         \
356       if (V)                                                                  \
357         {                                                                     \
358           clib_mem_free (vec_header ((V)));                                   \
359           V = 0;                                                              \
360         }                                                                     \
361     }                                                                         \
362   while (0)
363
364 void vec_free_not_inline (void *v);
365
366 /**\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)
377     @param S numa (may be VEC_NUMA_UNSPECIFIED)
378
379     @return Vdup copy of vector
380 */
381
382 #define vec_dup_ha_numa(V,H,A,S)                      \
383 ({                                                      \
384   __typeof__ ((V)[0]) * _v(v) = 0;                      \
385   uword _v(l) = vec_len (V);                            \
386   if (_v(l) > 0)                                        \
387     {                                                   \
388       vec_resize_has (_v(v), _v(l), (H), (A), (S));     \
389       clib_memcpy_fast (_v(v), (V), _v(l) * sizeof ((V)[0]));\
390     }                                                   \
391   _v(v);                                                \
392 })
393
394 /** \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
406 /** \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
425     @param DST destination
426     @param SRC source
427 */
428 #define vec_copy(DST,SRC) clib_memcpy_fast (DST, SRC, vec_len (DST) * \
429                                        sizeof ((DST)[0]))
430
431 /** \brief Clone a vector. Make a new vector with the
432     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)                                                  \
438 do {                                                                            \
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
446     @param V (possibly NULL) pointer to a vector.
447     @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)
450     @param N numa_id (may be zero)
451     @return V (value-result macro parameter)
452 */
453
454 #define vec_validate_han(V,I,H,A,N)                                     \
455 do {                                                                    \
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     }                                                                   \
480 } while (0)
481
482 #define vec_validate_ha(V,I,H,A) vec_validate_han(V,I,H,A,VEC_NUMA_UNSPECIFIED)
483
484 /** \brief Make sure vector is long enough for given index
485     (no header, unspecified alignment)
486
487     @param V (possibly NULL) pointer to a vector.
488     @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
493 /** \brief Make sure vector is long enough for given index
494     (no header, specified alignment)
495
496     @param V (possibly NULL) pointer to a vector.
497     @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
504 /** \brief Make sure vector is long enough for given index
505     and initialize empty space (general version)
506
507     @param V (possibly NULL) pointer to a vector.
508     @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)                \
515 do {                                                            \
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
529 /** \brief Make sure vector is long enough for given index
530     and initialize empty space (no header, unspecified alignment)
531
532     @param V (possibly NULL) pointer to a vector.
533     @param I vector index which will be valid upon return
534     @param INIT initial value (can be a complex expression!)
535     @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
541 /** \brief Make sure vector is long enough for given index
542     and initialize empty space (no header, alignment alignment)
543
544     @param V (possibly NULL) pointer to a vector.
545     @param I vector index which will be valid upon return
546     @param INIT initial value (can be a complex expression!)
547     @param A alignment (may be zero)
548     @return V (value-result macro parameter)
549 */
550 #define vec_validate_init_empty_aligned(V,I,INIT,A) \
551   vec_validate_init_empty_ha(V,I,INIT,0,A)
552
553 /** \brief Add 1 element to end of vector (general version).
554
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)                                            \
562 do {                                                                    \
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
568 /** \brief Add 1 element to end of vector (unspecified alignment).
569
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
576 /** \brief Add 1 element to end of vector (alignment specified).
577
578     @param V pointer to a vector
579     @param E element to add
580     @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
585 /** \brief Add N elements to end of vector V,
586     return pointer to new elements in P. (general version)
587
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)                                                  \
596 do {                                                                            \
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
603 /** \brief Add N elements to end of vector V,
604     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
614 /** \brief Add N elements to end of vector V,
615     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
626 /** \brief Add N elements to end of vector V (general version)
627
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 */
635 #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)
648
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
668 /** \brief Returns last element of a vector and decrements its length
669
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
682 /** \brief Set E to the last element of a vector, decrement vector length
683     @param V pointer to a vector
684     @param E pointer to the last vector element
685     @return E element removed from the end of the vector
686     (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
696 /** \brief Insert N vector elements starting at element M,
697     initialize new elements (general version).
698
699     @param V (possibly NULL) pointer to a vector.
700     @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)        \
708 do {                                                    \
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]));          \
720   clib_memset  ((V) + _v(m), INIT, _v(n) * sizeof ((V)[0]));    \
721 } while (0)
722
723 /** \brief Insert N vector elements starting at element M,
724     initialize new elements to zero (general version)
725
726     @param V (possibly NULL) pointer to a vector.
727     @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
735 /** \brief Insert N vector elements starting at element M,
736     initialize new elements to zero (no header, unspecified alignment)
737
738     @param V (possibly NULL) pointer to a vector.
739     @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
745 /** \brief Insert N vector elements starting at element M,
746     initialize new elements to zero (no header, alignment specified)
747
748     @param V (possibly NULL) pointer to a vector.
749     @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
756 /** \brief Insert N vector elements starting at element M,
757     initialize new elements (no header, unspecified alignment)
758
759     @param V (possibly NULL) pointer to a vector.
760     @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
770 /** \brief Insert N vector elements starting at element M,
771     initialize new elements (no header, specified alignment)
772
773     @param V (possibly NULL) pointer to a vector.
774     @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
783 /** \brief Insert N vector elements starting at element M,
784     insert given elements (general version)
785
786     @param V (possibly NULL) pointer to a vector.
787     @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
795 #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)
812
813 /** \brief Insert N vector elements starting at element M,
814     insert given elements (no header, unspecified alignment)
815
816     @param V (possibly NULL) pointer to a vector.
817     @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
824 /** \brief Insert N vector elements starting at element M,
825     insert given elements (no header, specified alignment)
826
827     @param V (possibly NULL) pointer to a vector.
828     @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
836 /** \brief Delete N elements starting at element M
837
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)                                       \
844 do {                                                            \
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)                                                \
854     clib_memset ((V) + _v(l) - _v(n), 0, _v(n) * sizeof ((V)[0]));      \
855   _vec_len (V) -= _v(n);                                        \
856   CLIB_MEM_POISON(vec_end(V), _v(n) * sizeof ((V)[0]));         \
857 } 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)                           \
865 do {                                            \
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;                    \
871   CLIB_MEM_POISON(vec_end(v), sizeof ((v)[0])); \
872 } while (0)
873
874 /** \brief Append v2 after v1. Result in v1.
875     @param V1 target vector
876     @param V2 vector to append
877 */
878
879 #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)
894
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 */
900
901 #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)
916
917 /** \brief Prepend v2 before v1. Result in v1.
918     @param V1 target vector
919     @param V2 vector to prepend
920 */
921
922 #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)
937
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
944 #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)
959
960 /** \brief Zero all vector elements. Null-pointer tolerant.
961     @param var Vector to zero
962 */
963 #define vec_zero(var)                                           \
964 do {                                                            \
965   if (var)                                                      \
966     clib_memset ((var), 0, vec_len (var) * sizeof ((var)[0]));  \
967 } 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)                          \
974 do {                                            \
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).
995    Used in qsort compare functions.
996
997     @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
1016 /** \brief Search a vector for the index of the entry that matches.
1017
1018     @param v Pointer to a vector
1019     @param E Entry to match
1020     @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   {                                                     \
1027     if ((v)[_v(i)] == E)                                        \
1028       break;                                            \
1029     _v(i)++;                                            \
1030   }                                                     \
1031   if (_v(i) == vec_len(v))                              \
1032     _v(i) = ~0;                                         \
1033   _v(i);                                                \
1034 })
1035
1036 /** \brief Search a vector for the index of the entry that matches.
1037
1038     @param v Pointer to a vector
1039     @param E Pointer to entry to match
1040     @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
1057 /** \brief Sort a vector using the supplied element comparison function
1058
1059     Does not depend on the underlying implementation to deal correctly
1060     with null, zero-long, or 1-long vectors
1061
1062     @param vec vector to sort
1063     @param f comparison function
1064 */
1065 #define vec_sort_with_function(vec,f)                           \
1066 do {                                                            \
1067   if (vec_len (vec) > 1)                                        \
1068     qsort (vec, vec_len (vec), sizeof (vec[0]), (void *) (f));  \
1069 } while (0)
1070
1071 /** \brief Make a vector containing a NULL terminated c-string.
1072
1073     @param V (possibly NULL) pointer to a vector.
1074     @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))                             \
1082         clib_memcpy_fast ((V), (S), (L));            \
1083     (V)[(L)] = 0;                               \
1084   } while (0)
1085
1086
1087 /** \brief Test whether a vector is a NULL terminated c-string.
1088
1089     @param V (possibly NULL) pointer to a vector.
1090     @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
1095 /** \brief (If necessary) NULL terminate a vector containing a c-string.
1096
1097     @param V (possibly NULL) pointer to a vector.
1098     @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
1112
1113 /*
1114  * fd.io coding-style-patch-verification: ON
1115  *
1116  * Local Variables:
1117  * eval: (c-set-style "gnu")
1118  * End:
1119  */