fe8c5722fd51dd7ca47fcb48806ea14d656ae15e
[protos/libecoli.git] / src / ecoli_vec.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
3  */
4
5 #include <sys/types.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <stdint.h>
9 #include <errno.h>
10 #include <assert.h>
11
12 #include <ecoli_assert.h>
13 #include <ecoli_malloc.h>
14 #include <ecoli_log.h>
15 #include <ecoli_test.h>
16 #include <ecoli_vec.h>
17
18 EC_LOG_TYPE_REGISTER(vec);
19
20 struct ec_vec {
21         size_t len;
22         size_t size;
23         size_t elt_size;
24         ec_vec_elt_copy_t copy;
25         ec_vec_elt_free_t free;
26         void *vec;
27 };
28
29 static void *get_obj(const struct ec_vec *vec, size_t idx)
30 {
31         assert(vec->elt_size != 0);
32         return (char *)vec->vec + (idx * vec->elt_size);
33 }
34
35 struct ec_vec *
36 ec_vec(size_t elt_size, size_t size, ec_vec_elt_copy_t copy,
37         ec_vec_elt_free_t free)
38 {
39         struct ec_vec *vec;
40
41         if (elt_size == 0) {
42                 errno = EINVAL;
43                 return NULL;
44         }
45
46         vec = ec_calloc(1, sizeof(*vec));
47         if (vec == NULL)
48                 return NULL;
49
50         vec->elt_size = elt_size;
51         vec->copy = copy;
52         vec->free = free;
53
54         if (size == 0)
55                 return vec;
56
57         vec->vec = ec_calloc(size, vec->elt_size);
58         if (vec->vec == NULL) {
59                 ec_free(vec);
60                 return NULL;
61         }
62
63         return vec;
64 }
65
66 int ec_vec_add_by_ref(struct ec_vec *vec, void *ptr)
67 {
68         void *new_vec;
69
70         if (vec->len + 1 > vec->size) {
71                 new_vec = ec_realloc(vec->vec, vec->elt_size * (vec->len + 1));
72                 if (new_vec == NULL)
73                         return -1;
74                 vec->size = vec->len + 1;
75                 vec->vec = new_vec;
76         }
77
78         memcpy(get_obj(vec, vec->len), ptr, vec->elt_size);
79         vec->len++;
80
81         return 0;
82 }
83
84 int ec_vec_add_ptr(struct ec_vec *vec, void *elt)
85 {
86         EC_CHECK_ARG(vec->elt_size == sizeof(elt), -1, EINVAL);
87
88         return ec_vec_add_by_ref(vec, &elt);
89 }
90
91 int ec_vec_add_u8(struct ec_vec *vec, uint8_t elt)
92 {
93         EC_CHECK_ARG(vec->elt_size == sizeof(elt), -1, EINVAL);
94
95         return ec_vec_add_by_ref(vec, &elt);
96 }
97
98 int ec_vec_add_u16(struct ec_vec *vec, uint16_t elt)
99 {
100         EC_CHECK_ARG(vec->elt_size == sizeof(elt), -1, EINVAL);
101
102         return ec_vec_add_by_ref(vec, &elt);
103 }
104
105 int ec_vec_add_u32(struct ec_vec *vec, uint32_t elt)
106 {
107         EC_CHECK_ARG(vec->elt_size == sizeof(elt), -1, EINVAL);
108
109         return ec_vec_add_by_ref(vec, &elt);
110 }
111
112 int ec_vec_add_u64(struct ec_vec *vec, uint64_t elt)
113 {
114         EC_CHECK_ARG(vec->elt_size == sizeof(elt), -1, EINVAL);
115
116         return ec_vec_add_by_ref(vec, &elt);
117 }
118
119 struct ec_vec *ec_vec_ndup(const struct ec_vec *vec, size_t off,
120         size_t len)
121 {
122         struct ec_vec *copy = NULL;
123         size_t i, veclen;
124
125         veclen = ec_vec_len(vec);
126         if (off + len > veclen)
127                 return NULL;
128
129         copy = ec_vec(vec->elt_size, len, vec->copy, vec->free);
130         if (copy == NULL)
131                 goto fail;
132
133         if (len == 0)
134                 return copy;
135
136         for (i = 0; i < len; i++) {
137                 if (vec->copy)
138                         vec->copy(get_obj(copy, i), get_obj(vec, i + off));
139                 else
140                         memcpy(get_obj(copy, i), get_obj(vec, i + off),
141                                 vec->elt_size);
142         }
143         copy->len = len;
144
145         return copy;
146
147 fail:
148         ec_vec_free(copy);
149         return NULL;
150 }
151
152 size_t ec_vec_len(const struct ec_vec *vec)
153 {
154         if (vec == NULL)
155                 return 0;
156
157         return vec->len;
158 }
159
160 struct ec_vec *ec_vec_dup(const struct ec_vec *vec)
161 {
162         return ec_vec_ndup(vec, 0, ec_vec_len(vec));
163 }
164
165 void ec_vec_free(struct ec_vec *vec)
166 {
167         size_t i;
168
169         if (vec == NULL)
170                 return;
171
172         for (i = 0; i < ec_vec_len(vec); i++) {
173                 if (vec->free)
174                         vec->free(get_obj(vec, i));
175         }
176
177         ec_free(vec->vec);
178         ec_free(vec);
179 }
180
181 int ec_vec_get(void *ptr, const struct ec_vec *vec, size_t idx)
182 {
183         if (vec == NULL || idx >= vec->len) {
184                 errno = EINVAL;
185                 return -1;
186         }
187
188         memcpy(ptr, get_obj(vec, idx), vec->elt_size);
189
190         return 0;
191 }
192
193 static void str_free(void *elt)
194 {
195         char **s = elt;
196
197         ec_free(*s);
198 }
199
200 #define GOTO_FAIL do {                                       \
201                 EC_LOG(EC_LOG_ERR, "%s:%d: test failed\n",   \
202                         __FILE__, __LINE__);                 \
203                 goto fail;                                   \
204         } while(0)
205
206 /* LCOV_EXCL_START */
207 static int ec_vec_testcase(void)
208 {
209         struct ec_vec *vec = NULL;
210         struct ec_vec *vec2 = NULL;
211         uint8_t val8;
212         uint16_t val16;
213         uint32_t val32;
214         uint64_t val64;
215         void *valp;
216         char *vals;
217
218         /* uint8_t vector */
219         vec = ec_vec(sizeof(val8), 0, NULL, NULL);
220         if (vec == NULL)
221                 GOTO_FAIL;
222
223         if (ec_vec_add_u8(vec, 0) < 0)
224                 GOTO_FAIL;
225         if (ec_vec_add_u8(vec, 1) < 0)
226                 GOTO_FAIL;
227         if (ec_vec_add_u8(vec, 2) < 0)
228                 GOTO_FAIL;
229         /* should fail */
230         if (ec_vec_add_u16(vec, 3) == 0)
231                 GOTO_FAIL;
232         if (ec_vec_add_u32(vec, 3) == 0)
233                 GOTO_FAIL;
234         if (ec_vec_add_u64(vec, 3) == 0)
235                 GOTO_FAIL;
236         if (ec_vec_add_ptr(vec, (void *)3) == 0)
237                 GOTO_FAIL;
238
239         if (ec_vec_get(&val8, vec, 0) < 0)
240                 GOTO_FAIL;
241         if (val8 != 0)
242                 GOTO_FAIL;
243         if (ec_vec_get(&val8, vec, 1) < 0)
244                 GOTO_FAIL;
245         if (val8 != 1)
246                 GOTO_FAIL;
247         if (ec_vec_get(&val8, vec, 2) < 0)
248                 GOTO_FAIL;
249         if (val8 != 2)
250                 GOTO_FAIL;
251
252         /* duplicate the vector */
253         vec2 = ec_vec_dup(vec);
254         if (vec2 == NULL)
255                 GOTO_FAIL;
256         if (ec_vec_get(&val8, vec2, 0) < 0)
257                 GOTO_FAIL;
258         if (val8 != 0)
259                 GOTO_FAIL;
260         if (ec_vec_get(&val8, vec2, 1) < 0)
261                 GOTO_FAIL;
262         if (val8 != 1)
263                 GOTO_FAIL;
264         if (ec_vec_get(&val8, vec2, 2) < 0)
265                 GOTO_FAIL;
266         if (val8 != 2)
267                 GOTO_FAIL;
268
269         ec_vec_free(vec2);
270         vec2 = NULL;
271
272         /* dup at offset 1 */
273         vec2 = ec_vec_ndup(vec, 1, 2);
274         if (vec2 == NULL)
275                 GOTO_FAIL;
276         if (ec_vec_get(&val8, vec2, 0) < 0)
277                 GOTO_FAIL;
278         if (val8 != 1)
279                 GOTO_FAIL;
280         if (ec_vec_get(&val8, vec2, 1) < 0)
281                 GOTO_FAIL;
282         if (val8 != 2)
283                 GOTO_FAIL;
284
285         ec_vec_free(vec2);
286         vec2 = NULL;
287
288         /* len = 0, duplicate is empty */
289         vec2 = ec_vec_ndup(vec, 2, 0);
290         if (vec2 == NULL)
291                 GOTO_FAIL;
292         if (ec_vec_get(&val8, vec2, 0) == 0)
293                 GOTO_FAIL;
294
295         ec_vec_free(vec2);
296         vec2 = NULL;
297
298         /* bad dup args */
299         vec2 = ec_vec_ndup(vec, 10, 1);
300         if (vec2 != NULL)
301                 GOTO_FAIL;
302
303         ec_vec_free(vec);
304         vec = NULL;
305
306         /* uint16_t vector */
307         vec = ec_vec(sizeof(val16), 0, NULL, NULL);
308         if (vec == NULL)
309                 GOTO_FAIL;
310
311         if (ec_vec_add_u16(vec, 0) < 0)
312                 GOTO_FAIL;
313         if (ec_vec_add_u16(vec, 1) < 0)
314                 GOTO_FAIL;
315         if (ec_vec_add_u16(vec, 2) < 0)
316                 GOTO_FAIL;
317         /* should fail */
318         if (ec_vec_add_u8(vec, 3) == 0)
319                 GOTO_FAIL;
320
321         if (ec_vec_get(&val16, vec, 0) < 0)
322                 GOTO_FAIL;
323         if (val16 != 0)
324                 GOTO_FAIL;
325         if (ec_vec_get(&val16, vec, 1) < 0)
326                 GOTO_FAIL;
327         if (val16 != 1)
328                 GOTO_FAIL;
329         if (ec_vec_get(&val16, vec, 2) < 0)
330                 GOTO_FAIL;
331         if (val16 != 2)
332                 GOTO_FAIL;
333
334         ec_vec_free(vec);
335         vec = NULL;
336
337         /* uint32_t vector */
338         vec = ec_vec(sizeof(val32), 0, NULL, NULL);
339         if (vec == NULL)
340                 GOTO_FAIL;
341
342         if (ec_vec_add_u32(vec, 0) < 0)
343                 GOTO_FAIL;
344         if (ec_vec_add_u32(vec, 1) < 0)
345                 GOTO_FAIL;
346         if (ec_vec_add_u32(vec, 2) < 0)
347                 GOTO_FAIL;
348
349         if (ec_vec_get(&val32, vec, 0) < 0)
350                 GOTO_FAIL;
351         if (val32 != 0)
352                 GOTO_FAIL;
353         if (ec_vec_get(&val32, vec, 1) < 0)
354                 GOTO_FAIL;
355         if (val32 != 1)
356                 GOTO_FAIL;
357         if (ec_vec_get(&val32, vec, 2) < 0)
358                 GOTO_FAIL;
359         if (val32 != 2)
360                 GOTO_FAIL;
361
362         ec_vec_free(vec);
363         vec = NULL;
364
365         /* uint64_t vector */
366         vec = ec_vec(sizeof(val64), 0, NULL, NULL);
367         if (vec == NULL)
368                 GOTO_FAIL;
369
370         if (ec_vec_add_u64(vec, 0) < 0)
371                 GOTO_FAIL;
372         if (ec_vec_add_u64(vec, 1) < 0)
373                 GOTO_FAIL;
374         if (ec_vec_add_u64(vec, 2) < 0)
375                 GOTO_FAIL;
376
377         if (ec_vec_get(&val64, vec, 0) < 0)
378                 GOTO_FAIL;
379         if (val64 != 0)
380                 GOTO_FAIL;
381         if (ec_vec_get(&val64, vec, 1) < 0)
382                 GOTO_FAIL;
383         if (val64 != 1)
384                 GOTO_FAIL;
385         if (ec_vec_get(&val64, vec, 2) < 0)
386                 GOTO_FAIL;
387         if (val64 != 2)
388                 GOTO_FAIL;
389
390         ec_vec_free(vec);
391         vec = NULL;
392
393         /* ptr vector */
394         vec = ec_vec(sizeof(valp), 0, NULL, NULL);
395         if (vec == NULL)
396                 GOTO_FAIL;
397
398         if (ec_vec_add_ptr(vec, (void *)0) < 0)
399                 GOTO_FAIL;
400         if (ec_vec_add_ptr(vec, (void *)1) < 0)
401                 GOTO_FAIL;
402         if (ec_vec_add_ptr(vec, (void *)2) < 0)
403                 GOTO_FAIL;
404
405         if (ec_vec_get(&valp, vec, 0) < 0)
406                 GOTO_FAIL;
407         if (valp != (void *)0)
408                 GOTO_FAIL;
409         if (ec_vec_get(&valp, vec, 1) < 0)
410                 GOTO_FAIL;
411         if (valp != (void *)1)
412                 GOTO_FAIL;
413         if (ec_vec_get(&valp, vec, 2) < 0)
414                 GOTO_FAIL;
415         if (valp != (void *)2)
416                 GOTO_FAIL;
417
418         ec_vec_free(vec);
419         vec = NULL;
420
421         /* string vector */
422         vec = ec_vec(sizeof(valp), 0, NULL, str_free);
423         if (vec == NULL)
424                 GOTO_FAIL;
425
426         if (ec_vec_add_ptr(vec, ec_strdup("0")) < 0)
427                 GOTO_FAIL;
428         if (ec_vec_add_ptr(vec, ec_strdup("1")) < 0)
429                 GOTO_FAIL;
430         if (ec_vec_add_ptr(vec, ec_strdup("2")) < 0)
431                 GOTO_FAIL;
432
433         if (ec_vec_get(&vals, vec, 0) < 0)
434                 GOTO_FAIL;
435         if (vals == NULL || strcmp(vals, "0"))
436                 GOTO_FAIL;
437         if (ec_vec_get(&vals, vec, 1) < 0)
438                 GOTO_FAIL;
439         if (vals == NULL || strcmp(vals, "1"))
440                 GOTO_FAIL;
441         if (ec_vec_get(&vals, vec, 2) < 0)
442                 GOTO_FAIL;
443         if (vals == NULL || strcmp(vals, "2"))
444                 GOTO_FAIL;
445
446         ec_vec_free(vec);
447         vec = NULL;
448
449         /* invalid args */
450         vec = ec_vec(0, 0, NULL, NULL);
451         if (vec != NULL)
452                 GOTO_FAIL;
453
454         return 0;
455
456 fail:
457         ec_vec_free(vec);
458         ec_vec_free(vec2);
459         return -1;
460 }
461 /* LCOV_EXCL_STOP */
462
463 static struct ec_test ec_vec_test = {
464         .name = "vec",
465         .test = ec_vec_testcase,
466 };
467
468 EC_TEST_REGISTER(ec_vec_test);