vppinfra: deprecate vec_free_h()
[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,
188                          word length_increment,
189                          uword data_bytes, uword header_bytes,
190                          uword data_align)
191 {
192   uword new_data_bytes, aligned_header_bytes;
193
194   aligned_header_bytes = vec_header_bytes (header_bytes);
195
196   new_data_bytes = data_bytes + aligned_header_bytes;
197
198   if (PREDICT_TRUE (v != 0))
199     {
200       void *p = v - aligned_header_bytes;
201
202       /* Vector header must start heap object. */
203       ASSERT (clib_mem_is_heap_object (p));
204
205       /* Typically we'll not need to resize. */
206       if (new_data_bytes <= clib_mem_size (p))
207         return 0;
208     }
209   return 1;
210 }
211
212 /** \brief Determine if vector will resize with next allocation
213
214     @param V pointer to a vector
215     @param N number of elements to add
216     @return 1 if vector will resize 0 otherwise
217 */
218
219 #define vec_resize_will_expand(V, N)                                          \
220   ({                                                                          \
221     word _v (n) = (N);                                                        \
222     word _v (l) = vec_len (V);                                                \
223     _vec_resize_will_expand ((V), _v (n),                                     \
224                              (_v (l) + _v (n)) * sizeof ((V)[0]), 0, 0);      \
225   })
226
227 /** \brief Predicate function, says whether the supplied vector is a clib heap
228     object (general version).
229
230     @param v pointer to a vector
231     @param header_bytes vector header size in bytes (may be zero)
232     @return 0 or 1
233 */
234 uword clib_mem_is_vec_h (void *v, uword header_bytes);
235
236
237 /** \brief Predicate function, says whether the supplied vector is a clib heap
238     object
239
240     @param v pointer to a vector
241     @return 0 or 1
242 */
243 always_inline uword
244 clib_mem_is_vec (void *v)
245 {
246   return clib_mem_is_vec_h (v, 0);
247 }
248
249 /* Local variable naming macro (prevents collisions with other macro naming). */
250 #define _v(var) _vec_##var
251
252 /** \brief Resize a vector (general version).
253    Add N elements to end of given vector V, return pointer to start of vector.
254    Vector will have room for H header bytes and will have user's data aligned
255    at alignment A (rounded to next power of 2).
256
257     @param V pointer to a vector
258     @param N number of elements to add
259     @param H header size in bytes (may be zero)
260     @param A alignment (may be zero)
261     @param S numa_id (may be zero)
262     @return V (value-result macro parameter)
263 */
264
265 #define vec_resize_has(V,N,H,A,S)                               \
266 do {                                                            \
267   word _v(n) = (N);                                             \
268   word _v(l) = vec_len (V);                                     \
269   V = _vec_resize_numa ((V), _v(n),                           \
270                           (_v(l) + _v(n)) * sizeof ((V)[0]),    \
271                           (H), (A),(S));                        \
272 } while (0)
273
274 /** \brief Resize a vector (less general version).
275    Add N elements to end of given vector V, return pointer to start of vector.
276    Vector will have room for H header bytes and will have user's data aligned
277    at alignment A (rounded to next power of 2).
278
279     @param V pointer to a vector
280     @param N number of elements to add
281     @param H header size in bytes (may be zero)
282     @param A alignment (may be zero)
283     @return V (value-result macro parameter)
284 */
285 #define vec_resize_ha(V,N,H,A) vec_resize_has(V,N,H,A,VEC_NUMA_UNSPECIFIED)
286
287 /** \brief Resize a vector (no header, unspecified alignment)
288    Add N elements to end of given vector V, return pointer to start of vector.
289    Vector will have room for H header bytes and will have user's data aligned
290    at alignment A (rounded to next power of 2).
291
292     @param V pointer to a vector
293     @param N number of elements to add
294     @return V (value-result macro parameter)
295 */
296 #define vec_resize(V,N)     vec_resize_ha(V,N,0,0)
297
298 /** \brief Resize a vector (no header, alignment specified).
299    Add N elements to end of given vector V, return pointer to start of vector.
300    Vector will have room for H header bytes and will have user's data aligned
301    at alignment A (rounded to next power of 2).
302
303     @param V pointer to a vector
304     @param N number of elements to add
305     @param A alignment (may be zero)
306     @return V (value-result macro parameter)
307 */
308
309 #define vec_resize_aligned(V,N,A) vec_resize_ha(V,N,0,A)
310
311 /** \brief Allocate space for N more elements
312
313     @param V pointer to a vector
314     @param N number of elements to add
315     @param H header size in bytes (may be zero)
316     @param A alignment (may be zero)
317     @return V (value-result macro parameter)
318 */
319
320 #define vec_alloc_ha(V,N,H,A)                   \
321 do {                                            \
322     uword _v(l) = vec_len (V);                  \
323     vec_resize_ha (V, N, H, A);                 \
324     _vec_len (V) = _v(l);                       \
325 } while (0)
326
327 /** \brief Allocate space for N more elements
328     (no header, unspecified alignment)
329
330     @param V pointer to a vector
331     @param N number of elements to add
332     @return V (value-result macro parameter)
333 */
334 #define vec_alloc(V,N) vec_alloc_ha(V,N,0,0)
335
336 /** \brief Allocate space for N more elements (no header, given alignment)
337     @param V pointer to a vector
338     @param N number of elements to add
339     @param A alignment (may be zero)
340     @return V (value-result macro parameter)
341 */
342
343 #define vec_alloc_aligned(V,N,A) vec_alloc_ha(V,N,0,A)
344
345 /** \brief Create new vector of given type and length (general version).
346     @param T type of elements in new vector
347     @param N number of elements to add
348     @param H header size in bytes (may be zero)
349     @param A alignment (may be zero)
350     @return V new vector
351 */
352 #define vec_new_ha(T,N,H,A)                                             \
353 ({                                                                      \
354   word _v(n) = (N);                                                     \
355   (T *)_vec_resize ((T *) 0, _v(n), _v(n) * sizeof (T), (H), (A));      \
356 })
357
358 /** \brief Create new vector of given type and length
359     (unspecified alignment, no header).
360
361     @param T type of elements in new vector
362     @param N number of elements to add
363     @return V new vector
364 */
365 #define vec_new(T,N)           vec_new_ha(T,N,0,0)
366 /** \brief Create new vector of given type and length
367     (alignment specified, no header).
368
369     @param T type of elements in new vector
370     @param N number of elements to add
371     @param A alignment (may be zero)
372     @return V new vector
373 */
374 #define vec_new_aligned(T,N,A) vec_new_ha(T,N,0,A)
375
376 /** \brief Free vector's memory (no header).
377     @param V pointer to a vector
378     @return V (value-result parameter, V=0)
379 */
380 #define vec_free(V)                                                           \
381   do                                                                          \
382     {                                                                         \
383       if (V)                                                                  \
384         {                                                                     \
385           clib_mem_free (vec_header ((V)));                                   \
386           V = 0;                                                              \
387         }                                                                     \
388     }                                                                         \
389   while (0)
390
391 void vec_free_not_inline (void *v);
392
393 /**\brief Free vector user header (syntactic sugar)
394    @param h vector header
395    @void
396 */
397 #define vec_free_header(h) clib_mem_free (h)
398
399 /** \brief Return copy of vector (general version).
400
401     @param V pointer to a vector
402     @param H size of header in bytes
403     @param A alignment (may be zero)
404     @param S numa (may be VEC_NUMA_UNSPECIFIED)
405
406     @return Vdup copy of vector
407 */
408
409 #define vec_dup_ha_numa(V,H,A,S)                      \
410 ({                                                      \
411   __typeof__ ((V)[0]) * _v(v) = 0;                      \
412   uword _v(l) = vec_len (V);                            \
413   if (_v(l) > 0)                                        \
414     {                                                   \
415       vec_resize_has (_v(v), _v(l), (H), (A), (S));     \
416       clib_memcpy_fast (_v(v), (V), _v(l) * sizeof ((V)[0]));\
417     }                                                   \
418   _v(v);                                                \
419 })
420
421 /** \brief Return copy of vector (VEC_NUMA_UNSPECIFIED).
422
423     @param V pointer to a vector
424     @param H size of header in bytes
425     @param A alignment (may be zero)
426
427     @return Vdup copy of vector
428 */
429 #define vec_dup_ha(V,H,A) \
430   vec_dup_ha_numa(V,H,A,VEC_NUMA_UNSPECIFIED)
431
432
433 /** \brief Return copy of vector (no header, no alignment)
434
435     @param V pointer to a vector
436     @return Vdup copy of vector
437 */
438 #define vec_dup(V) vec_dup_ha(V,0,0)
439
440 /** \brief Return copy of vector (no header, alignment specified).
441
442     @param V pointer to a vector
443     @param A alignment (may be zero)
444
445     @return Vdup copy of vector
446 */
447 #define vec_dup_aligned(V,A) vec_dup_ha(V,0,A)
448
449 /** \brief Copy a vector, memcpy wrapper. Assumes sizeof(SRC[0]) ==
450     sizeof(DST[0])
451
452     @param DST destination
453     @param SRC source
454 */
455 #define vec_copy(DST,SRC) clib_memcpy_fast (DST, SRC, vec_len (DST) * \
456                                        sizeof ((DST)[0]))
457
458 /** \brief Clone a vector. Make a new vector with the
459     same size as a given vector but possibly with a different type.
460
461     @param NEW_V pointer to new vector
462     @param OLD_V pointer to old vector
463 */
464 #define vec_clone(NEW_V,OLD_V)                                                  \
465 do {                                                                            \
466   (NEW_V) = 0;                                                                  \
467   (NEW_V) = _vec_resize ((NEW_V), vec_len (OLD_V),                              \
468                          vec_len (OLD_V) * sizeof ((NEW_V)[0]), (0), (0));      \
469 } while (0)
470
471 /** \brief Make sure vector is long enough for given index (general version).
472
473     @param V (possibly NULL) pointer to a vector.
474     @param I vector index which will be valid upon return
475     @param H header size in bytes (may be zero)
476     @param A alignment (may be zero)
477     @param N numa_id (may be zero)
478     @return V (value-result macro parameter)
479 */
480
481 #define vec_validate_han(V,I,H,A,N)                                     \
482 do {                                                                    \
483   void *oldheap;                                                        \
484   STATIC_ASSERT(A==0 || ((A % sizeof(V[0]))==0)                         \
485         || ((sizeof(V[0]) % A) == 0),                                   \
486     "vector validate aligned on incorrectly sized object");             \
487   word _v(i) = (I);                                                     \
488   word _v(l) = vec_len (V);                                             \
489   if (_v(i) >= _v(l))                                                   \
490     {                                                                   \
491       /* switch to the per-numa heap if directed */                   \
492       if (PREDICT_FALSE(N != VEC_NUMA_UNSPECIFIED))                   \
493         {                                                               \
494            oldheap = clib_mem_get_per_cpu_heap();                       \
495            clib_mem_set_per_cpu_heap (clib_mem_get_per_numa_heap(N)); \
496         }                                                               \
497                                                                         \
498       vec_resize_ha ((V), 1 + (_v(i) - _v(l)), (H), (A));               \
499       /* Must zero new space since user may have previously             \
500          used e.g. _vec_len (v) -= 10 */                                \
501       clib_memset ((V) + _v(l), 0,                                      \
502                    (1 + (_v(i) - _v(l))) * sizeof ((V)[0]));            \
503       /* Switch back to the global heap */                              \
504       if (PREDICT_FALSE (N != VEC_NUMA_UNSPECIFIED))                  \
505         clib_mem_set_per_cpu_heap (oldheap);                            \
506     }                                                                   \
507 } while (0)
508
509 #define vec_validate_ha(V,I,H,A) vec_validate_han(V,I,H,A,VEC_NUMA_UNSPECIFIED)
510
511 /** \brief Make sure vector is long enough for given index
512     (no header, unspecified alignment)
513
514     @param V (possibly NULL) pointer to a vector.
515     @param I vector index which will be valid upon return
516     @return V (value-result macro parameter)
517 */
518 #define vec_validate(V,I)           vec_validate_ha(V,I,0,0)
519
520 /** \brief Make sure vector is long enough for given index
521     (no header, specified alignment)
522
523     @param V (possibly NULL) pointer to a vector.
524     @param I vector index which will be valid upon return
525     @param A alignment (may be zero)
526     @return V (value-result macro parameter)
527 */
528
529 #define vec_validate_aligned(V,I,A) vec_validate_ha(V,I,0,A)
530
531 /** \brief Make sure vector is long enough for given index
532     and initialize empty space (general version)
533
534     @param V (possibly NULL) pointer to a vector.
535     @param I vector index which will be valid upon return
536     @param INIT initial value (can be a complex expression!)
537     @param H header size in bytes (may be zero)
538     @param A alignment (may be zero)
539     @return V (value-result macro parameter)
540 */
541 #define vec_validate_init_empty_ha(V,I,INIT,H,A)                \
542 do {                                                            \
543   word _v(i) = (I);                                             \
544   word _v(l) = vec_len (V);                                     \
545   if (_v(i) >= _v(l))                                           \
546     {                                                           \
547       vec_resize_ha ((V), 1 + (_v(i) - _v(l)), (H), (A));       \
548       while (_v(l) <= _v(i))                                    \
549         {                                                       \
550           (V)[_v(l)] = (INIT);                                  \
551           _v(l)++;                                              \
552         }                                                       \
553     }                                                           \
554 } while (0)
555
556 /** \brief Make sure vector is long enough for given index
557     and initialize empty space (no header, unspecified alignment)
558
559     @param V (possibly NULL) pointer to a vector.
560     @param I vector index which will be valid upon return
561     @param INIT initial value (can be a complex expression!)
562     @return V (value-result macro parameter)
563 */
564
565 #define vec_validate_init_empty(V,I,INIT) \
566   vec_validate_init_empty_ha(V,I,INIT,0,0)
567
568 /** \brief Make sure vector is long enough for given index
569     and initialize empty space (no header, alignment alignment)
570
571     @param V (possibly NULL) pointer to a vector.
572     @param I vector index which will be valid upon return
573     @param INIT initial value (can be a complex expression!)
574     @param A alignment (may be zero)
575     @return V (value-result macro parameter)
576 */
577 #define vec_validate_init_empty_aligned(V,I,INIT,A) \
578   vec_validate_init_empty_ha(V,I,INIT,0,A)
579
580 /** \brief Add 1 element to end of vector (general version).
581
582     @param V pointer to a vector
583     @param E element to add
584     @param H header size in bytes (may be zero)
585     @param A alignment (may be zero)
586     @return V (value-result macro parameter)
587 */
588 #define vec_add1_ha(V,E,H,A)                                            \
589 do {                                                                    \
590   word _v(l) = vec_len (V);                                             \
591   V = _vec_resize ((V), 1, (_v(l) + 1) * sizeof ((V)[0]), (H), (A));    \
592   (V)[_v(l)] = (E);                                                     \
593 } while (0)
594
595 /** \brief Add 1 element to end of vector (unspecified alignment).
596
597     @param V pointer to a vector
598     @param E element to add
599     @return V (value-result macro parameter)
600 */
601 #define vec_add1(V,E)           vec_add1_ha(V,E,0,0)
602
603 /** \brief Add 1 element to end of vector (alignment specified).
604
605     @param V pointer to a vector
606     @param E element to add
607     @param A alignment (may be zero)
608     @return V (value-result macro parameter)
609 */
610 #define vec_add1_aligned(V,E,A) vec_add1_ha(V,E,0,A)
611
612 /** \brief Add N elements to end of vector V,
613     return pointer to new elements in P. (general version)
614
615     @param V pointer to a vector
616     @param P pointer to new vector element(s)
617     @param N number of elements to add
618     @param H header size in bytes (may be zero)
619     @param A alignment (may be zero)
620     @return V and P (value-result macro parameters)
621 */
622 #define vec_add2_ha(V,P,N,H,A)                                                  \
623 do {                                                                            \
624   word _v(n) = (N);                                                             \
625   word _v(l) = vec_len (V);                                                     \
626   V = _vec_resize ((V), _v(n), (_v(l) + _v(n)) * sizeof ((V)[0]), (H), (A));    \
627   P = (V) + _v(l);                                                              \
628 } while (0)
629
630 /** \brief Add N elements to end of vector V,
631     return pointer to new elements in P. (no header, unspecified alignment)
632
633     @param V pointer to a vector
634     @param P pointer to new vector element(s)
635     @param N number of elements to add
636     @return V and P (value-result macro parameters)
637 */
638
639 #define vec_add2(V,P,N)           vec_add2_ha(V,P,N,0,0)
640
641 /** \brief Add N elements to end of vector V,
642     return pointer to new elements in P. (no header, alignment specified)
643
644     @param V pointer to a vector
645     @param P pointer to new vector element(s)
646     @param N number of elements to add
647     @param A alignment (may be zero)
648     @return V and P (value-result macro parameters)
649 */
650
651 #define vec_add2_aligned(V,P,N,A) vec_add2_ha(V,P,N,0,A)
652
653 /** \brief Add N elements to end of vector V (general version)
654
655     @param V pointer to a vector
656     @param E pointer to element(s) to add
657     @param N number of elements to add
658     @param H header size in bytes (may be zero)
659     @param A alignment (may be zero)
660     @return V (value-result macro parameter)
661 */
662 #define vec_add_ha(V, E, N, H, A)                                             \
663   do                                                                          \
664     {                                                                         \
665       word _v (n) = (N);                                                      \
666       if (PREDICT_TRUE (_v (n) > 0))                                          \
667         {                                                                     \
668           word _v (l) = vec_len (V);                                          \
669           V = _vec_resize ((V), _v (n), (_v (l) + _v (n)) * sizeof ((V)[0]),  \
670                            (H), (A));                                         \
671           clib_memcpy_fast ((V) + _v (l), (E), _v (n) * sizeof ((V)[0]));     \
672         }                                                                     \
673     }                                                                         \
674   while (0)
675
676 /** \brief Add N elements to end of vector V (no header, unspecified alignment)
677
678     @param V pointer to a vector
679     @param E pointer to element(s) to add
680     @param N number of elements to add
681     @return V (value-result macro parameter)
682 */
683 #define vec_add(V,E,N)           vec_add_ha(V,E,N,0,0)
684
685 /** \brief Add N elements to end of vector V (no header, specified alignment)
686
687     @param V pointer to a vector
688     @param E pointer to element(s) to add
689     @param N number of elements to add
690     @param A alignment (may be zero)
691     @return V (value-result macro parameter)
692 */
693 #define vec_add_aligned(V,E,N,A) vec_add_ha(V,E,N,0,A)
694
695 /** \brief Returns last element of a vector and decrements its length
696
697     @param V pointer to a vector
698     @return E element removed from the end of the vector
699 */
700 #define vec_pop(V)                              \
701 ({                                              \
702   uword _v(l) = vec_len (V);                    \
703   ASSERT (_v(l) > 0);                           \
704   _v(l) -= 1;                                   \
705   _vec_len (V) = _v (l);                        \
706   (V)[_v(l)];                                   \
707 })
708
709 /** \brief Set E to the last element of a vector, decrement vector length
710     @param V pointer to a vector
711     @param E pointer to the last vector element
712     @return E element removed from the end of the vector
713     (value-result macro parameter
714 */
715
716 #define vec_pop2(V,E)                           \
717 ({                                              \
718   uword _v(l) = vec_len (V);                    \
719   if (_v(l) > 0) (E) = vec_pop (V);             \
720   _v(l) > 0;                                    \
721 })
722
723 /** \brief Insert N vector elements starting at element M,
724     initialize new elements (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 INIT initial value (can be a complex expression!)
730     @param H header size in bytes (may be zero)
731     @param A alignment (may be zero)
732     @return V (value-result macro parameter)
733 */
734 #define vec_insert_init_empty_ha(V,N,M,INIT,H,A)        \
735 do {                                                    \
736   word _v(l) = vec_len (V);                             \
737   word _v(n) = (N);                                     \
738   word _v(m) = (M);                                     \
739   V = _vec_resize ((V),                                 \
740                    _v(n),                               \
741                    (_v(l) + _v(n))*sizeof((V)[0]),      \
742                    (H), (A));                           \
743   ASSERT (_v(m) <= _v(l));                              \
744   memmove ((V) + _v(m) + _v(n),                         \
745            (V) + _v(m),                                 \
746            (_v(l) - _v(m)) * sizeof ((V)[0]));          \
747   clib_memset  ((V) + _v(m), INIT, _v(n) * sizeof ((V)[0]));    \
748 } while (0)
749
750 /** \brief Insert N vector elements starting at element M,
751     initialize new elements to zero (general version)
752
753     @param V (possibly NULL) pointer to a vector.
754     @param N number of elements to insert
755     @param M insertion point
756     @param H header size in bytes (may be zero)
757     @param A alignment (may be zero)
758     @return V (value-result macro parameter)
759 */
760 #define vec_insert_ha(V,N,M,H,A)    vec_insert_init_empty_ha(V,N,M,0,H,A)
761
762 /** \brief Insert N vector elements starting at element M,
763     initialize new elements to zero (no header, unspecified alignment)
764
765     @param V (possibly NULL) pointer to a vector.
766     @param N number of elements to insert
767     @param M insertion point
768     @return V (value-result macro parameter)
769 */
770 #define vec_insert(V,N,M)           vec_insert_ha(V,N,M,0,0)
771
772 /** \brief Insert N vector elements starting at element M,
773     initialize new elements to zero (no header, alignment specified)
774
775     @param V (possibly NULL) pointer to a vector.
776     @param N number of elements to insert
777     @param M insertion point
778     @param A alignment (may be zero)
779     @return V (value-result macro parameter)
780 */
781 #define vec_insert_aligned(V,N,M,A) vec_insert_ha(V,N,M,0,A)
782
783 /** \brief Insert N vector elements starting at element M,
784     initialize new elements (no header, unspecified alignment)
785
786     @param V (possibly NULL) pointer to a vector.
787     @param N number of elements to insert
788     @param M insertion point
789     @param INIT initial value (can be a complex expression!)
790     @return V (value-result macro parameter)
791 */
792
793 #define vec_insert_init_empty(V,N,M,INIT) \
794   vec_insert_init_empty_ha(V,N,M,INIT,0,0)
795 /* Resize vector by N elements starting from element M, initialize new elements to INIT (alignment specified, no header). */
796
797 /** \brief Insert N vector elements starting at element M,
798     initialize new elements (no header, specified alignment)
799
800     @param V (possibly NULL) pointer to a vector.
801     @param N number of elements to insert
802     @param M insertion point
803     @param INIT initial value (can be a complex expression!)
804     @param A alignment (may be zero)
805     @return V (value-result macro parameter)
806 */
807 #define vec_insert_init_empty_aligned(V,N,M,INIT,A) \
808   vec_insert_init_empty_ha(V,N,M,INIT,0,A)
809
810 /** \brief Insert N vector elements starting at element M,
811     insert given elements (general version)
812
813     @param V (possibly NULL) pointer to a vector.
814     @param E element(s) to insert
815     @param N number of elements to insert
816     @param M insertion point
817     @param H header size in bytes (may be zero)
818     @param A alignment (may be zero)
819     @return V (value-result macro parameter)
820 */
821
822 #define vec_insert_elts_ha(V, E, N, M, H, A)                                  \
823   do                                                                          \
824     {                                                                         \
825       word _v (n) = (N);                                                      \
826       if (PREDICT_TRUE (_v (n) > 0))                                          \
827         {                                                                     \
828           word _v (l) = vec_len (V);                                          \
829           word _v (m) = (M);                                                  \
830           V = _vec_resize ((V), _v (n), (_v (l) + _v (n)) * sizeof ((V)[0]),  \
831                            (H), (A));                                         \
832           ASSERT (_v (m) <= _v (l));                                          \
833           memmove ((V) + _v (m) + _v (n), (V) + _v (m),                       \
834                    (_v (l) - _v (m)) * sizeof ((V)[0]));                      \
835           clib_memcpy_fast ((V) + _v (m), (E), _v (n) * sizeof ((V)[0]));     \
836         }                                                                     \
837     }                                                                         \
838   while (0)
839
840 /** \brief Insert N vector elements starting at element M,
841     insert given elements (no header, unspecified alignment)
842
843     @param V (possibly NULL) pointer to a vector.
844     @param E element(s) to insert
845     @param N number of elements to insert
846     @param M insertion point
847     @return V (value-result macro parameter)
848 */
849 #define vec_insert_elts(V,E,N,M)           vec_insert_elts_ha(V,E,N,M,0,0)
850
851 /** \brief Insert N vector elements starting at element M,
852     insert given elements (no header, specified alignment)
853
854     @param V (possibly NULL) pointer to a vector.
855     @param E element(s) to insert
856     @param N number of elements to insert
857     @param M insertion point
858     @param A alignment (may be zero)
859     @return V (value-result macro parameter)
860 */
861 #define vec_insert_elts_aligned(V,E,N,M,A) vec_insert_elts_ha(V,E,N,M,0,A)
862
863 /** \brief Delete N elements starting at element M
864
865     @param V pointer to a vector
866     @param N number of elements to delete
867     @param M first element to delete
868     @return V (value-result macro parameter)
869 */
870 #define vec_delete(V,N,M)                                       \
871 do {                                                            \
872   word _v(l) = vec_len (V);                                     \
873   word _v(n) = (N);                                             \
874   word _v(m) = (M);                                             \
875   /* Copy over deleted elements. */                             \
876   if (_v(l) - _v(n) - _v(m) > 0)                                \
877     memmove ((V) + _v(m), (V) + _v(m) + _v(n),                  \
878              (_v(l) - _v(n) - _v(m)) * sizeof ((V)[0]));        \
879   /* Zero empty space at end (for future re-allocation). */     \
880   if (_v(n) > 0)                                                \
881     clib_memset ((V) + _v(l) - _v(n), 0, _v(n) * sizeof ((V)[0]));      \
882   _vec_len (V) -= _v(n);                                        \
883   CLIB_MEM_POISON(vec_end(V), _v(n) * sizeof ((V)[0]));         \
884 } while (0)
885
886 /** \brief Delete the element at index I
887
888     @param V pointer to a vector
889     @param I index to delete
890 */
891 #define vec_del1(v,i)                           \
892 do {                                            \
893   uword _vec_del_l = _vec_len (v) - 1;          \
894   uword _vec_del_i = (i);                       \
895   if (_vec_del_i < _vec_del_l)                  \
896     (v)[_vec_del_i] = (v)[_vec_del_l];          \
897   _vec_len (v) = _vec_del_l;                    \
898   CLIB_MEM_POISON(vec_end(v), sizeof ((v)[0])); \
899 } while (0)
900
901 /** \brief Append v2 after v1. Result in v1.
902     @param V1 target vector
903     @param V2 vector to append
904 */
905
906 #define vec_append(v1, v2)                                                    \
907   do                                                                          \
908     {                                                                         \
909       uword _v (l1) = vec_len (v1);                                           \
910       uword _v (l2) = vec_len (v2);                                           \
911                                                                               \
912       if (PREDICT_TRUE (_v (l2) > 0))                                         \
913         {                                                                     \
914           v1 = _vec_resize ((v1), _v (l2),                                    \
915                             (_v (l1) + _v (l2)) * sizeof ((v1)[0]), 0, 0);    \
916           clib_memcpy_fast ((v1) + _v (l1), (v2),                             \
917                             _v (l2) * sizeof ((v2)[0]));                      \
918         }                                                                     \
919     }                                                                         \
920   while (0)
921
922 /** \brief Append v2 after v1. Result in v1. Specified alignment.
923     @param V1 target vector
924     @param V2 vector to append
925     @param align required alignment
926 */
927
928 #define vec_append_aligned(v1, v2, align)                                     \
929   do                                                                          \
930     {                                                                         \
931       uword _v (l1) = vec_len (v1);                                           \
932       uword _v (l2) = vec_len (v2);                                           \
933                                                                               \
934       if (PREDICT_TRUE (_v (l2) > 0))                                         \
935         {                                                                     \
936           v1 = _vec_resize (                                                  \
937             (v1), _v (l2), (_v (l1) + _v (l2)) * sizeof ((v1)[0]), 0, align); \
938           clib_memcpy_fast ((v1) + _v (l1), (v2),                             \
939                             _v (l2) * sizeof ((v2)[0]));                      \
940         }                                                                     \
941     }                                                                         \
942   while (0)
943
944 /** \brief Prepend v2 before v1. Result in v1.
945     @param V1 target vector
946     @param V2 vector to prepend
947 */
948
949 #define vec_prepend(v1, v2)                                                   \
950   do                                                                          \
951     {                                                                         \
952       uword _v (l1) = vec_len (v1);                                           \
953       uword _v (l2) = vec_len (v2);                                           \
954                                                                               \
955       if (PREDICT_TRUE (_v (l2) > 0))                                         \
956         {                                                                     \
957           v1 = _vec_resize ((v1), _v (l2),                                    \
958                             (_v (l1) + _v (l2)) * sizeof ((v1)[0]), 0, 0);    \
959           memmove ((v1) + _v (l2), (v1), _v (l1) * sizeof ((v1)[0]));         \
960           clib_memcpy_fast ((v1), (v2), _v (l2) * sizeof ((v2)[0]));          \
961         }                                                                     \
962     }                                                                         \
963   while (0)
964
965 /** \brief Prepend v2 before v1. Result in v1. Specified alignment
966     @param V1 target vector
967     @param V2 vector to prepend
968     @param align required alignment
969 */
970
971 #define vec_prepend_aligned(v1, v2, align)                                    \
972   do                                                                          \
973     {                                                                         \
974       uword _v (l1) = vec_len (v1);                                           \
975       uword _v (l2) = vec_len (v2);                                           \
976                                                                               \
977       if (PREDICT_TRUE (_v (l2) > 0))                                         \
978         {                                                                     \
979           v1 = _vec_resize (                                                  \
980             (v1), _v (l2), (_v (l1) + _v (l2)) * sizeof ((v1)[0]), 0, align); \
981           memmove ((v1) + _v (l2), (v1), _v (l1) * sizeof ((v1)[0]));         \
982           clib_memcpy_fast ((v1), (v2), _v (l2) * sizeof ((v2)[0]));          \
983         }                                                                     \
984     }                                                                         \
985   while (0)
986
987 /** \brief Zero all vector elements. Null-pointer tolerant.
988     @param var Vector to zero
989 */
990 #define vec_zero(var)                                           \
991 do {                                                            \
992   if (var)                                                      \
993     clib_memset ((var), 0, vec_len (var) * sizeof ((var)[0]));  \
994 } while (0)
995
996 /** \brief Set all vector elements to given value. Null-pointer tolerant.
997     @param v vector to set
998     @param val value for each vector element
999 */
1000 #define vec_set(v,val)                          \
1001 do {                                            \
1002   word _v(i);                                   \
1003   __typeof__ ((v)[0]) _val = (val);             \
1004   for (_v(i) = 0; _v(i) < vec_len (v); _v(i)++) \
1005     (v)[_v(i)] = _val;                          \
1006 } while (0)
1007
1008 #ifdef CLIB_UNIX
1009 #include <stdlib.h>             /* for qsort */
1010 #endif
1011
1012 /** \brief Compare two vectors, not NULL-pointer tolerant
1013
1014     @param v1 Pointer to a vector
1015     @param v2 Pointer to a vector
1016     @return 1 if equal, 0 if unequal
1017 */
1018 #define vec_is_equal(v1,v2) \
1019   (vec_len (v1) == vec_len (v2) && ! memcmp ((v1), (v2), vec_len (v1) * sizeof ((v1)[0])))
1020
1021 /** \brief Compare two vectors (only applicable to vectors of signed numbers).
1022    Used in qsort compare functions.
1023
1024     @param v1 Pointer to a vector
1025     @param v2 Pointer to a vector
1026     @return -1, 0, +1
1027 */
1028 #define vec_cmp(v1,v2)                                  \
1029 ({                                                      \
1030   word _v(i), _v(cmp), _v(l);                           \
1031   _v(l) = clib_min (vec_len (v1), vec_len (v2));        \
1032   _v(cmp) = 0;                                          \
1033   for (_v(i) = 0; _v(i) < _v(l); _v(i)++) {             \
1034     _v(cmp) = (v1)[_v(i)] - (v2)[_v(i)];                \
1035     if (_v(cmp))                                        \
1036       break;                                            \
1037   }                                                     \
1038   if (_v(cmp) == 0 && _v(l) > 0)                        \
1039     _v(cmp) = vec_len(v1) - vec_len(v2);                \
1040   (_v(cmp) < 0 ? -1 : (_v(cmp) > 0 ? +1 : 0));          \
1041 })
1042
1043 /** \brief Search a vector for the index of the entry that matches.
1044
1045     @param v Pointer to a vector
1046     @param E Entry to match
1047     @return index of match or ~0
1048 */
1049 #define vec_search(v,E)                                 \
1050 ({                                                      \
1051   word _v(i) = 0;                                       \
1052   while (_v(i) < vec_len(v))                            \
1053   {                                                     \
1054     if ((v)[_v(i)] == E)                                        \
1055       break;                                            \
1056     _v(i)++;                                            \
1057   }                                                     \
1058   if (_v(i) == vec_len(v))                              \
1059     _v(i) = ~0;                                         \
1060   _v(i);                                                \
1061 })
1062
1063 /** \brief Search a vector for the index of the entry that matches.
1064
1065     @param v Pointer to a vector
1066     @param E Pointer to entry to match
1067     @param fn Comparison function !0 => match
1068     @return index of match or ~0
1069 */
1070 #define vec_search_with_function(v,E,fn)                \
1071 ({                                                      \
1072   word _v(i) = 0;                                       \
1073   while (_v(i) < vec_len(v))                            \
1074   {                                                     \
1075     if (0 != fn(&(v)[_v(i)], (E)))                      \
1076       break;                                            \
1077     _v(i)++;                                            \
1078   }                                                     \
1079   if (_v(i) == vec_len(v))                              \
1080     _v(i) = ~0;                                         \
1081   _v(i);                                                \
1082 })
1083
1084 /** \brief Sort a vector using the supplied element comparison function
1085
1086     Does not depend on the underlying implementation to deal correctly
1087     with null, zero-long, or 1-long vectors
1088
1089     @param vec vector to sort
1090     @param f comparison function
1091 */
1092 #define vec_sort_with_function(vec,f)                           \
1093 do {                                                            \
1094   if (vec_len (vec) > 1)                                        \
1095     qsort (vec, vec_len (vec), sizeof (vec[0]), (void *) (f));  \
1096 } while (0)
1097
1098 /** \brief Make a vector containing a NULL terminated c-string.
1099
1100     @param V (possibly NULL) pointer to a vector.
1101     @param S pointer to string buffer.
1102     @param L string length (NOT including the terminating NULL; a la strlen())
1103 */
1104 #define vec_validate_init_c_string(V, S, L)     \
1105   do {                                          \
1106     vec_reset_length (V);                       \
1107     vec_validate ((V), (L));                    \
1108     if ((S) && (L))                             \
1109         clib_memcpy_fast ((V), (S), (L));            \
1110     (V)[(L)] = 0;                               \
1111   } while (0)
1112
1113
1114 /** \brief Test whether a vector is a NULL terminated c-string.
1115
1116     @param V (possibly NULL) pointer to a vector.
1117     @return BOOLEAN indicating if the vector c-string is null terminated.
1118 */
1119 #define vec_c_string_is_terminated(V)                   \
1120   (((V) != 0) && (vec_len (V) != 0) && ((V)[vec_len ((V)) - 1] == 0))
1121
1122 /** \brief (If necessary) NULL terminate a vector containing a c-string.
1123
1124     @param V (possibly NULL) pointer to a vector.
1125     @return V (value-result macro parameter)
1126 */
1127 #define vec_terminate_c_string(V)               \
1128   do {                                          \
1129     u32 vl = vec_len ((V));                     \
1130     if (!vec_c_string_is_terminated(V))         \
1131       {                                         \
1132         vec_validate ((V), vl);                 \
1133         (V)[vl] = 0;                            \
1134       }                                         \
1135   } while (0)
1136
1137 #endif /* included_vec_h */
1138
1139
1140 /*
1141  * fd.io coding-style-patch-verification: ON
1142  *
1143  * Local Variables:
1144  * eval: (c-set-style "gnu")
1145  * End:
1146  */