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