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