vppinfra: add cmake option to grow vectors by 1
[vpp.git] / src / vppinfra / vec.c
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 #include <vppinfra/vec.h>
39 #include <vppinfra/mem.h>
40
41 /* Vector resize operator.  Called as needed by various macros such as
42    vec_add1() when we need to allocate memory. */
43 void *
44 vec_resize_allocate_memory (void *v,
45                             word length_increment,
46                             uword data_bytes,
47                             uword header_bytes, uword data_align,
48                             uword numa_id)
49 {
50   vec_header_t *vh = _vec_find (v);
51   uword old_alloc_bytes, new_alloc_bytes;
52   void *old, *new;
53   void *oldheap;
54
55   header_bytes = vec_header_bytes (header_bytes);
56
57   data_bytes += header_bytes;
58
59   if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
60     {
61       oldheap = clib_mem_get_per_cpu_heap ();
62       clib_mem_set_per_cpu_heap (clib_mem_get_per_numa_heap (numa_id));
63     }
64
65   if (!v)
66     {
67       new = clib_mem_alloc_aligned_at_offset (data_bytes, data_align, header_bytes, 1   /* yes, call os_out_of_memory */
68         );
69       new_alloc_bytes = clib_mem_size (new);
70       CLIB_MEM_UNPOISON (new + data_bytes, new_alloc_bytes - data_bytes);
71       clib_memset (new, 0, new_alloc_bytes);
72       CLIB_MEM_POISON (new + data_bytes, new_alloc_bytes - data_bytes);
73       v = new + header_bytes;
74       _vec_len (v) = length_increment;
75       _vec_numa (v) = numa_id;
76       if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
77         clib_mem_set_per_cpu_heap (oldheap);
78       return v;
79     }
80
81   vh->len += length_increment;
82   old = v - header_bytes;
83
84   /* Vector header must start heap object. */
85   ASSERT (clib_mem_is_heap_object (old));
86
87   old_alloc_bytes = clib_mem_size (old);
88
89   /* Need to resize? */
90   if (data_bytes <= old_alloc_bytes)
91     {
92       CLIB_MEM_UNPOISON (v, data_bytes);
93       if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
94         clib_mem_set_per_cpu_heap (oldheap);
95       return v;
96     }
97
98 #if CLIB_VECTOR_GROW_BY_ONE > 0
99   new_alloc_bytes = data_bytes;
100 #else
101   new_alloc_bytes = (old_alloc_bytes * 3) / 2;
102   if (new_alloc_bytes < data_bytes)
103     new_alloc_bytes = data_bytes;
104 #endif
105
106   new =
107     clib_mem_alloc_aligned_at_offset (new_alloc_bytes, data_align,
108                                       header_bytes,
109                                       1 /* yes, call os_out_of_memory */ );
110
111   /* FIXME fail gracefully. */
112   if (!new)
113     clib_panic
114       ("vec_resize fails, length increment %d, data bytes %d, alignment %d",
115        length_increment, data_bytes, data_align);
116
117   CLIB_MEM_UNPOISON (old, old_alloc_bytes);
118   clib_memcpy_fast (new, old, old_alloc_bytes);
119   clib_mem_free (old);
120
121   /* Allocator may give a bit of extra room. */
122   new_alloc_bytes = clib_mem_size (new);
123   v = new;
124
125   /* Zero new memory. */
126   CLIB_MEM_UNPOISON (new + data_bytes, new_alloc_bytes - data_bytes);
127   memset (v + old_alloc_bytes, 0, new_alloc_bytes - old_alloc_bytes);
128   CLIB_MEM_POISON (new + data_bytes, new_alloc_bytes - data_bytes);
129
130   _vec_numa ((v + header_bytes)) = numa_id;
131   if (PREDICT_FALSE (numa_id != VEC_NUMA_UNSPECIFIED))
132     clib_mem_set_per_cpu_heap (oldheap);
133
134   return v + header_bytes;
135 }
136
137 uword
138 clib_mem_is_vec_h (void *v, uword header_bytes)
139 {
140   return clib_mem_is_heap_object (vec_header (v, header_bytes));
141 }
142
143 /** \cond */
144
145 #ifdef TEST
146
147 #include <stdio.h>
148
149 void
150 main (int argc, char *argv[])
151 {
152   word n = atoi (argv[1]);
153   word i, *x = 0;
154
155   typedef struct
156   {
157     word x, y, z;
158   } FOO;
159
160   FOO *foos = vec_init (FOO, 10), *f;
161
162   vec_validate (foos, 100);
163   foos[100].x = 99;
164
165   _vec_len (foos) = 0;
166   for (i = 0; i < n; i++)
167     {
168       vec_add1 (x, i);
169       vec_add2 (foos, f, 1);
170       f->x = 2 * i;
171       f->y = 3 * i;
172       f->z = 4 * i;
173     }
174
175   {
176     word n = 2;
177     word m = 42;
178     vec_delete (foos, n, m);
179   }
180
181   {
182     word n = 2;
183     word m = 42;
184     vec_insert (foos, n, m);
185   }
186
187   vec_free (x);
188   vec_free (foos);
189   exit (0);
190 }
191 #endif
192 /** \endcond */
193
194 /*
195  * fd.io coding-style-patch-verification: ON
196  *
197  * Local Variables:
198  * eval: (c-set-style "gnu")
199  * End:
200  */