dynamic log types
[protos/libecoli.git] / lib / ecoli_vec.c
1 /*
2  * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <sys/types.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <stdint.h>
32 #include <errno.h>
33 #include <assert.h>
34
35 #include <ecoli_malloc.h>
36 #include <ecoli_log.h>
37 #include <ecoli_test.h>
38 #include <ecoli_vec.h>
39
40 EC_LOG_TYPE_REGISTER(vec);
41
42 struct ec_vec {
43         size_t len;
44         size_t size;
45         size_t elt_size;
46         ec_vec_elt_copy_t copy;
47         ec_vec_elt_free_t free;
48         void *vec;
49 };
50
51 static void *get_obj(const struct ec_vec *vec, size_t idx)
52 {
53         assert(vec->elt_size != 0);
54         return (char *)vec->vec + (idx * vec->elt_size);
55 }
56
57 struct ec_vec *
58 ec_vec(size_t elt_size, size_t size, ec_vec_elt_copy_t copy,
59         ec_vec_elt_free_t free)
60 {
61         struct ec_vec *vec;
62
63         if (elt_size == 0) {
64                 errno = -EINVAL;
65                 return NULL;
66         }
67
68         vec = ec_calloc(1, sizeof(*vec));
69         if (vec == NULL)
70                 return NULL;
71
72         vec->elt_size = elt_size;
73         vec->copy = copy;
74         vec->free = free;
75
76         if (size == 0)
77                 return vec;
78
79         vec->vec = ec_calloc(size, vec->elt_size);
80         if (vec->vec == NULL) {
81                 ec_free(vec);
82                 return NULL;
83         }
84
85         return vec;
86 }
87
88 int ec_vec_add_by_ref(struct ec_vec *vec, void *ptr)
89 {
90         void *new_vec;
91
92         if (vec->len + 1 > vec->size) {
93                 new_vec = ec_realloc(vec->vec, vec->elt_size * (vec->len + 1));
94                 if (new_vec == NULL)
95                         return -ENOMEM;
96         }
97
98         vec->vec = new_vec;
99         if (vec->copy)
100                 vec->copy(get_obj(vec, vec->len), ptr);
101         else
102                 memcpy(get_obj(vec, vec->len), ptr, vec->elt_size);
103         vec->len++;
104
105         return 0;
106 }
107
108 int ec_vec_add_ptr(struct ec_vec *vec, void *elt)
109 {
110         if (vec->elt_size != sizeof(elt))
111                 return -EINVAL;
112
113         return ec_vec_add_by_ref(vec, &elt);
114 }
115
116 int ec_vec_add_u8(struct ec_vec *vec, uint8_t elt)
117 {
118         if (vec->elt_size != sizeof(elt))
119                 return -EINVAL;
120
121         return ec_vec_add_by_ref(vec, &elt);
122 }
123
124 int ec_vec_add_u16(struct ec_vec *vec, uint16_t elt)
125 {
126         if (vec->elt_size != sizeof(elt))
127                 return -EINVAL;
128
129         return ec_vec_add_by_ref(vec, &elt);
130 }
131
132 int ec_vec_add_u32(struct ec_vec *vec, uint32_t elt)
133 {
134         if (vec->elt_size != sizeof(elt))
135                 return -EINVAL;
136
137         return ec_vec_add_by_ref(vec, &elt);
138 }
139
140 int ec_vec_add_u64(struct ec_vec *vec, uint64_t elt)
141 {
142         if (vec->elt_size != sizeof(elt))
143                 return -EINVAL;
144
145         return ec_vec_add_by_ref(vec, &elt);
146 }
147
148 struct ec_vec *ec_vec_ndup(const struct ec_vec *vec, size_t off,
149         size_t len)
150 {
151         struct ec_vec *copy = NULL;
152         size_t i, veclen;
153
154         veclen = ec_vec_len(vec);
155         if (off + len > veclen)
156                 return NULL;
157
158         copy = ec_vec(vec->elt_size, len, vec->copy, vec->free);
159         if (copy == NULL)
160                 goto fail;
161
162         if (len == 0)
163                 return copy;
164
165         for (i = 0; i < len; i++) {
166                 if (vec->copy)
167                         vec->copy(get_obj(copy, i), get_obj(vec, i + off));
168                 else
169                         memcpy(get_obj(copy, i), get_obj(vec, i + off),
170                                 vec->elt_size);
171         }
172         copy->len = len;
173
174         return copy;
175
176 fail:
177         ec_vec_free(copy);
178         return NULL;
179 }
180
181 size_t ec_vec_len(const struct ec_vec *vec)
182 {
183         return vec->len;
184 }
185
186 struct ec_vec *ec_vec_dup(const struct ec_vec *vec)
187 {
188         return ec_vec_ndup(vec, 0, ec_vec_len(vec));
189 }
190
191 void ec_vec_free(struct ec_vec *vec)
192 {
193         size_t i;
194
195         if (vec == NULL)
196                 return;
197
198         for (i = 0; i < ec_vec_len(vec); i++) {
199                 if (vec->free)
200                         vec->free(get_obj(vec, i));
201         }
202
203         ec_free(vec->vec);
204         ec_free(vec);
205 }
206
207 int ec_vec_get(void *ptr, const struct ec_vec *vec, size_t idx)
208 {
209         if (vec == NULL || idx >= vec->len)
210                 return -EINVAL;
211
212         if (vec->copy)
213                 vec->copy(ptr, get_obj(vec, idx));
214         else
215                 memcpy(ptr, get_obj(vec, idx), vec->elt_size);
216
217         return 0;
218 }
219
220 static void str_free(void *elt)
221 {
222         char **s = elt;
223
224         ec_free(*s);
225 }
226
227 #define GOTO_FAIL do {                                       \
228                 EC_LOG(EC_LOG_ERR, "%s:%d: test failed\n",   \
229                         __FILE__, __LINE__);                 \
230                 goto fail;                                   \
231         } while(0)
232
233 /* LCOV_EXCL_START */
234 static int ec_vec_testcase(void)
235 {
236         struct ec_vec *vec = NULL;
237         struct ec_vec *vec2 = NULL;
238         uint8_t val8;
239         uint16_t val16;
240         uint32_t val32;
241         uint64_t val64;
242         void *valp;
243         char *vals;
244
245         /* uint8_t vector */
246         vec = ec_vec(sizeof(val8), 0, NULL, NULL);
247         if (vec == NULL)
248                 GOTO_FAIL;
249
250         if (ec_vec_add_u8(vec, 0) < 0)
251                 GOTO_FAIL;
252         if (ec_vec_add_u8(vec, 1) < 0)
253                 GOTO_FAIL;
254         if (ec_vec_add_u8(vec, 2) < 0)
255                 GOTO_FAIL;
256         /* should fail */
257         if (ec_vec_add_u16(vec, 3) == 0)
258                 GOTO_FAIL;
259         if (ec_vec_add_u32(vec, 3) == 0)
260                 GOTO_FAIL;
261         if (ec_vec_add_u64(vec, 3) == 0)
262                 GOTO_FAIL;
263         if (ec_vec_add_ptr(vec, (void *)3) == 0)
264                 GOTO_FAIL;
265
266         if (ec_vec_get(&val8, vec, 0) < 0)
267                 GOTO_FAIL;
268         if (val8 != 0)
269                 GOTO_FAIL;
270         if (ec_vec_get(&val8, vec, 1) < 0)
271                 GOTO_FAIL;
272         if (val8 != 1)
273                 GOTO_FAIL;
274         if (ec_vec_get(&val8, vec, 2) < 0)
275                 GOTO_FAIL;
276         if (val8 != 2)
277                 GOTO_FAIL;
278
279         /* duplicate the vector */
280         vec2 = ec_vec_dup(vec);
281         if (vec2 == NULL)
282                 GOTO_FAIL;
283         if (ec_vec_get(&val8, vec2, 0) < 0)
284                 GOTO_FAIL;
285         if (val8 != 0)
286                 GOTO_FAIL;
287         if (ec_vec_get(&val8, vec2, 1) < 0)
288                 GOTO_FAIL;
289         if (val8 != 1)
290                 GOTO_FAIL;
291         if (ec_vec_get(&val8, vec2, 2) < 0)
292                 GOTO_FAIL;
293         if (val8 != 2)
294                 GOTO_FAIL;
295
296         ec_vec_free(vec2);
297         vec2 = NULL;
298
299         /* dup at offset 1 */
300         vec2 = ec_vec_ndup(vec, 1, 2);
301         if (vec2 == NULL)
302                 GOTO_FAIL;
303         if (ec_vec_get(&val8, vec2, 0) < 0)
304                 GOTO_FAIL;
305         if (val8 != 1)
306                 GOTO_FAIL;
307         if (ec_vec_get(&val8, vec2, 1) < 0)
308                 GOTO_FAIL;
309         if (val8 != 2)
310                 GOTO_FAIL;
311
312         ec_vec_free(vec2);
313         vec2 = NULL;
314
315         /* len = 0, duplicate is empty */
316         vec2 = ec_vec_ndup(vec, 2, 0);
317         if (vec2 == NULL)
318                 GOTO_FAIL;
319         if (ec_vec_get(&val8, vec2, 0) == 0)
320                 GOTO_FAIL;
321
322         ec_vec_free(vec2);
323         vec2 = NULL;
324
325         /* bad dup args */
326         vec2 = ec_vec_ndup(vec, 10, 1);
327         if (vec2 != NULL)
328                 GOTO_FAIL;
329
330         ec_vec_free(vec);
331         vec = NULL;
332
333         /* uint16_t vector */
334         vec = ec_vec(sizeof(val16), 0, NULL, NULL);
335         if (vec == NULL)
336                 GOTO_FAIL;
337
338         if (ec_vec_add_u16(vec, 0) < 0)
339                 GOTO_FAIL;
340         if (ec_vec_add_u16(vec, 1) < 0)
341                 GOTO_FAIL;
342         if (ec_vec_add_u16(vec, 2) < 0)
343                 GOTO_FAIL;
344         /* should fail */
345         if (ec_vec_add_u8(vec, 3) == 0)
346                 GOTO_FAIL;
347
348         if (ec_vec_get(&val16, vec, 0) < 0)
349                 GOTO_FAIL;
350         if (val16 != 0)
351                 GOTO_FAIL;
352         if (ec_vec_get(&val16, vec, 1) < 0)
353                 GOTO_FAIL;
354         if (val16 != 1)
355                 GOTO_FAIL;
356         if (ec_vec_get(&val16, vec, 2) < 0)
357                 GOTO_FAIL;
358         if (val16 != 2)
359                 GOTO_FAIL;
360
361         ec_vec_free(vec);
362         vec = NULL;
363
364         /* uint32_t vector */
365         vec = ec_vec(sizeof(val32), 0, NULL, NULL);
366         if (vec == NULL)
367                 GOTO_FAIL;
368
369         if (ec_vec_add_u32(vec, 0) < 0)
370                 GOTO_FAIL;
371         if (ec_vec_add_u32(vec, 1) < 0)
372                 GOTO_FAIL;
373         if (ec_vec_add_u32(vec, 2) < 0)
374                 GOTO_FAIL;
375
376         if (ec_vec_get(&val32, vec, 0) < 0)
377                 GOTO_FAIL;
378         if (val32 != 0)
379                 GOTO_FAIL;
380         if (ec_vec_get(&val32, vec, 1) < 0)
381                 GOTO_FAIL;
382         if (val32 != 1)
383                 GOTO_FAIL;
384         if (ec_vec_get(&val32, vec, 2) < 0)
385                 GOTO_FAIL;
386         if (val32 != 2)
387                 GOTO_FAIL;
388
389         ec_vec_free(vec);
390         vec = NULL;
391
392         /* uint64_t vector */
393         vec = ec_vec(sizeof(val64), 0, NULL, NULL);
394         if (vec == NULL)
395                 GOTO_FAIL;
396
397         if (ec_vec_add_u64(vec, 0) < 0)
398                 GOTO_FAIL;
399         if (ec_vec_add_u64(vec, 1) < 0)
400                 GOTO_FAIL;
401         if (ec_vec_add_u64(vec, 2) < 0)
402                 GOTO_FAIL;
403
404         if (ec_vec_get(&val64, vec, 0) < 0)
405                 GOTO_FAIL;
406         if (val64 != 0)
407                 GOTO_FAIL;
408         if (ec_vec_get(&val64, vec, 1) < 0)
409                 GOTO_FAIL;
410         if (val64 != 1)
411                 GOTO_FAIL;
412         if (ec_vec_get(&val64, vec, 2) < 0)
413                 GOTO_FAIL;
414         if (val64 != 2)
415                 GOTO_FAIL;
416
417         ec_vec_free(vec);
418         vec = NULL;
419
420         /* ptr vector */
421         vec = ec_vec(sizeof(valp), 0, NULL, NULL);
422         if (vec == NULL)
423                 GOTO_FAIL;
424
425         if (ec_vec_add_ptr(vec, (void *)0) < 0)
426                 GOTO_FAIL;
427         if (ec_vec_add_ptr(vec, (void *)1) < 0)
428                 GOTO_FAIL;
429         if (ec_vec_add_ptr(vec, (void *)2) < 0)
430                 GOTO_FAIL;
431
432         if (ec_vec_get(&valp, vec, 0) < 0)
433                 GOTO_FAIL;
434         if (valp != (void *)0)
435                 GOTO_FAIL;
436         if (ec_vec_get(&valp, vec, 1) < 0)
437                 GOTO_FAIL;
438         if (valp != (void *)1)
439                 GOTO_FAIL;
440         if (ec_vec_get(&valp, vec, 2) < 0)
441                 GOTO_FAIL;
442         if (valp != (void *)2)
443                 GOTO_FAIL;
444
445         ec_vec_free(vec);
446         vec = NULL;
447
448         /* string vector */
449         vec = ec_vec(sizeof(valp), 0, NULL, str_free);
450         if (vec == NULL)
451                 GOTO_FAIL;
452
453         if (ec_vec_add_ptr(vec, ec_strdup("0")) < 0)
454                 GOTO_FAIL;
455         if (ec_vec_add_ptr(vec, ec_strdup("1")) < 0)
456                 GOTO_FAIL;
457         if (ec_vec_add_ptr(vec, ec_strdup("2")) < 0)
458                 GOTO_FAIL;
459
460         if (ec_vec_get(&vals, vec, 0) < 0)
461                 GOTO_FAIL;
462         if (strcmp(vals, "0"))
463                 GOTO_FAIL;
464         if (ec_vec_get(&vals, vec, 1) < 0)
465                 GOTO_FAIL;
466         if (strcmp(vals, "1"))
467                 GOTO_FAIL;
468         if (ec_vec_get(&vals, vec, 2) < 0)
469                 GOTO_FAIL;
470         if (strcmp(vals, "2"))
471                 GOTO_FAIL;
472
473         ec_vec_free(vec);
474         vec = NULL;
475
476         /* invalid args */
477         vec = ec_vec(0, 0, NULL, NULL);
478         if (vec != NULL)
479                 GOTO_FAIL;
480
481         return 0;
482
483 fail:
484         ec_vec_free(vec);
485         ec_vec_free(vec2);
486         return -1;
487 }
488 /* LCOV_EXCL_STOP */
489
490 static struct ec_test ec_vec_test = {
491         .name = "vec",
492         .test = ec_vec_testcase,
493 };
494
495 EC_TEST_REGISTER(ec_vec_test);