From d6d6ef90d5fe1050feb0de33b318fd346096672e Mon Sep 17 00:00:00 2001 From: Olivier Matz Date: Fri, 11 Aug 2017 21:17:34 +0200 Subject: [PATCH] vec --- lib/ecoli_vec.c | 493 ++++++++++++++++++++++++++++++++++++++++++++++++ lib/ecoli_vec.h | 60 ++++++ 2 files changed, 553 insertions(+) create mode 100644 lib/ecoli_vec.c create mode 100644 lib/ecoli_vec.h diff --git a/lib/ecoli_vec.c b/lib/ecoli_vec.c new file mode 100644 index 0000000..8038b31 --- /dev/null +++ b/lib/ecoli_vec.c @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2016, Olivier MATZ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +struct ec_vec { + size_t len; + size_t size; + size_t elt_size; + ec_vec_elt_copy_t copy; + ec_vec_elt_free_t free; + void *vec; +}; + +static void *get_obj(const struct ec_vec *vec, size_t idx) +{ + assert(vec->elt_size != 0); + return (char *)vec->vec + (idx * vec->elt_size); +} + +struct ec_vec * +ec_vec(size_t elt_size, size_t size, ec_vec_elt_copy_t copy, + ec_vec_elt_free_t free) +{ + struct ec_vec *vec; + + if (elt_size == 0) { + errno = -EINVAL; + return NULL; + } + + vec = ec_calloc(1, sizeof(*vec)); + if (vec == NULL) + return NULL; + + vec->elt_size = elt_size; + vec->copy = copy; + vec->free = free; + + if (size == 0) + return vec; + + vec->vec = ec_calloc(size, vec->elt_size); + if (vec->vec == NULL) { + ec_free(vec); + return NULL; + } + + return vec; +} + +int ec_vec_add_by_ref(struct ec_vec *vec, void *ptr) +{ + void *new_vec; + + if (vec->len + 1 > vec->size) { + new_vec = ec_realloc(vec->vec, vec->elt_size * (vec->len + 1)); + if (new_vec == NULL) + return -ENOMEM; + } + + vec->vec = new_vec; + if (vec->copy) + vec->copy(get_obj(vec, vec->len), ptr); + else + memcpy(get_obj(vec, vec->len), ptr, vec->elt_size); + vec->len++; + + return 0; +} + +int ec_vec_add_ptr(struct ec_vec *vec, void *elt) +{ + if (vec->elt_size != sizeof(elt)) + return -EINVAL; + + return ec_vec_add_by_ref(vec, &elt); +} + +int ec_vec_add_u8(struct ec_vec *vec, uint8_t elt) +{ + if (vec->elt_size != sizeof(elt)) + return -EINVAL; + + return ec_vec_add_by_ref(vec, &elt); +} + +int ec_vec_add_u16(struct ec_vec *vec, uint16_t elt) +{ + if (vec->elt_size != sizeof(elt)) + return -EINVAL; + + return ec_vec_add_by_ref(vec, &elt); +} + +int ec_vec_add_u32(struct ec_vec *vec, uint32_t elt) +{ + if (vec->elt_size != sizeof(elt)) + return -EINVAL; + + return ec_vec_add_by_ref(vec, &elt); +} + +int ec_vec_add_u64(struct ec_vec *vec, uint64_t elt) +{ + if (vec->elt_size != sizeof(elt)) + return -EINVAL; + + return ec_vec_add_by_ref(vec, &elt); +} + +struct ec_vec *ec_vec_ndup(const struct ec_vec *vec, size_t off, + size_t len) +{ + struct ec_vec *copy = NULL; + size_t i, veclen; + + veclen = ec_vec_len(vec); + if (off + len > veclen) + return NULL; + + copy = ec_vec(vec->elt_size, len, vec->copy, vec->free); + if (copy == NULL) + goto fail; + + if (len == 0) + return copy; + + for (i = 0; i < len; i++) { + if (vec->copy) + vec->copy(get_obj(copy, i), get_obj(vec, i + off)); + else + memcpy(get_obj(copy, i), get_obj(vec, i + off), + vec->elt_size); + } + copy->len = len; + + return copy; + +fail: + ec_vec_free(copy); + return NULL; +} + +size_t ec_vec_len(const struct ec_vec *vec) +{ + return vec->len; +} + +struct ec_vec *ec_vec_dup(const struct ec_vec *vec) +{ + return ec_vec_ndup(vec, 0, ec_vec_len(vec)); +} + +void ec_vec_free(struct ec_vec *vec) +{ + size_t i; + + if (vec == NULL) + return; + + for (i = 0; i < ec_vec_len(vec); i++) { + if (vec->free) + vec->free(get_obj(vec, i)); + } + + ec_free(vec->vec); + ec_free(vec); +} + +int ec_vec_get(void *ptr, const struct ec_vec *vec, size_t idx) +{ + if (vec == NULL || idx >= vec->len) + return -EINVAL; + + if (vec->copy) + vec->copy(ptr, get_obj(vec, idx)); + else + memcpy(ptr, get_obj(vec, idx), vec->elt_size); + + return 0; +} + +static void str_free(void *elt) +{ + char **s = elt; + + ec_free(*s); +} + +#define GOTO_FAIL do { \ + ec_log(EC_LOG_ERR, "%s:%d: test failed\n", \ + __FILE__, __LINE__); \ + goto fail; \ + } while(0) + +/* LCOV_EXCL_START */ +static int ec_vec_testcase(void) +{ + struct ec_vec *vec = NULL; + struct ec_vec *vec2 = NULL; + uint8_t val8; + uint16_t val16; + uint32_t val32; + uint64_t val64; + void *valp; + char *vals; + + /* uint8_t vector */ + vec = ec_vec(sizeof(val8), 0, NULL, NULL); + if (vec == NULL) + GOTO_FAIL; + + if (ec_vec_add_u8(vec, 0) < 0) + GOTO_FAIL; + if (ec_vec_add_u8(vec, 1) < 0) + GOTO_FAIL; + if (ec_vec_add_u8(vec, 2) < 0) + GOTO_FAIL; + /* should fail */ + if (ec_vec_add_u16(vec, 3) == 0) + GOTO_FAIL; + if (ec_vec_add_u32(vec, 3) == 0) + GOTO_FAIL; + if (ec_vec_add_u64(vec, 3) == 0) + GOTO_FAIL; + if (ec_vec_add_ptr(vec, (void *)3) == 0) + GOTO_FAIL; + + if (ec_vec_get(&val8, vec, 0) < 0) + GOTO_FAIL; + if (val8 != 0) + GOTO_FAIL; + if (ec_vec_get(&val8, vec, 1) < 0) + GOTO_FAIL; + if (val8 != 1) + GOTO_FAIL; + if (ec_vec_get(&val8, vec, 2) < 0) + GOTO_FAIL; + if (val8 != 2) + GOTO_FAIL; + + /* duplicate the vector */ + vec2 = ec_vec_dup(vec); + if (vec2 == NULL) + GOTO_FAIL; + if (ec_vec_get(&val8, vec2, 0) < 0) + GOTO_FAIL; + if (val8 != 0) + GOTO_FAIL; + if (ec_vec_get(&val8, vec2, 1) < 0) + GOTO_FAIL; + if (val8 != 1) + GOTO_FAIL; + if (ec_vec_get(&val8, vec2, 2) < 0) + GOTO_FAIL; + if (val8 != 2) + GOTO_FAIL; + + ec_vec_free(vec2); + vec2 = NULL; + + /* dup at offset 1 */ + vec2 = ec_vec_ndup(vec, 1, 2); + if (vec2 == NULL) + GOTO_FAIL; + if (ec_vec_get(&val8, vec2, 0) < 0) + GOTO_FAIL; + if (val8 != 1) + GOTO_FAIL; + if (ec_vec_get(&val8, vec2, 1) < 0) + GOTO_FAIL; + if (val8 != 2) + GOTO_FAIL; + + ec_vec_free(vec2); + vec2 = NULL; + + /* len = 0, duplicate is empty */ + vec2 = ec_vec_ndup(vec, 2, 0); + if (vec2 == NULL) + GOTO_FAIL; + if (ec_vec_get(&val8, vec2, 0) == 0) + GOTO_FAIL; + + ec_vec_free(vec2); + vec2 = NULL; + + /* bad dup args */ + vec2 = ec_vec_ndup(vec, 10, 1); + if (vec2 != NULL) + GOTO_FAIL; + + ec_vec_free(vec); + vec = NULL; + + /* uint16_t vector */ + vec = ec_vec(sizeof(val16), 0, NULL, NULL); + if (vec == NULL) + GOTO_FAIL; + + if (ec_vec_add_u16(vec, 0) < 0) + GOTO_FAIL; + if (ec_vec_add_u16(vec, 1) < 0) + GOTO_FAIL; + if (ec_vec_add_u16(vec, 2) < 0) + GOTO_FAIL; + /* should fail */ + if (ec_vec_add_u8(vec, 3) == 0) + GOTO_FAIL; + + if (ec_vec_get(&val16, vec, 0) < 0) + GOTO_FAIL; + if (val16 != 0) + GOTO_FAIL; + if (ec_vec_get(&val16, vec, 1) < 0) + GOTO_FAIL; + if (val16 != 1) + GOTO_FAIL; + if (ec_vec_get(&val16, vec, 2) < 0) + GOTO_FAIL; + if (val16 != 2) + GOTO_FAIL; + + ec_vec_free(vec); + vec = NULL; + + /* uint32_t vector */ + vec = ec_vec(sizeof(val32), 0, NULL, NULL); + if (vec == NULL) + GOTO_FAIL; + + if (ec_vec_add_u32(vec, 0) < 0) + GOTO_FAIL; + if (ec_vec_add_u32(vec, 1) < 0) + GOTO_FAIL; + if (ec_vec_add_u32(vec, 2) < 0) + GOTO_FAIL; + + if (ec_vec_get(&val32, vec, 0) < 0) + GOTO_FAIL; + if (val32 != 0) + GOTO_FAIL; + if (ec_vec_get(&val32, vec, 1) < 0) + GOTO_FAIL; + if (val32 != 1) + GOTO_FAIL; + if (ec_vec_get(&val32, vec, 2) < 0) + GOTO_FAIL; + if (val32 != 2) + GOTO_FAIL; + + ec_vec_free(vec); + vec = NULL; + + /* uint64_t vector */ + vec = ec_vec(sizeof(val64), 0, NULL, NULL); + if (vec == NULL) + GOTO_FAIL; + + if (ec_vec_add_u64(vec, 0) < 0) + GOTO_FAIL; + if (ec_vec_add_u64(vec, 1) < 0) + GOTO_FAIL; + if (ec_vec_add_u64(vec, 2) < 0) + GOTO_FAIL; + + if (ec_vec_get(&val64, vec, 0) < 0) + GOTO_FAIL; + if (val64 != 0) + GOTO_FAIL; + if (ec_vec_get(&val64, vec, 1) < 0) + GOTO_FAIL; + if (val64 != 1) + GOTO_FAIL; + if (ec_vec_get(&val64, vec, 2) < 0) + GOTO_FAIL; + if (val64 != 2) + GOTO_FAIL; + + ec_vec_free(vec); + vec = NULL; + + /* ptr vector */ + vec = ec_vec(sizeof(valp), 0, NULL, NULL); + if (vec == NULL) + GOTO_FAIL; + + if (ec_vec_add_ptr(vec, (void *)0) < 0) + GOTO_FAIL; + if (ec_vec_add_ptr(vec, (void *)1) < 0) + GOTO_FAIL; + if (ec_vec_add_ptr(vec, (void *)2) < 0) + GOTO_FAIL; + + if (ec_vec_get(&valp, vec, 0) < 0) + GOTO_FAIL; + if (valp != (void *)0) + GOTO_FAIL; + if (ec_vec_get(&valp, vec, 1) < 0) + GOTO_FAIL; + if (valp != (void *)1) + GOTO_FAIL; + if (ec_vec_get(&valp, vec, 2) < 0) + GOTO_FAIL; + if (valp != (void *)2) + GOTO_FAIL; + + ec_vec_free(vec); + vec = NULL; + + /* string vector */ + vec = ec_vec(sizeof(valp), 0, NULL, str_free); + if (vec == NULL) + GOTO_FAIL; + + if (ec_vec_add_ptr(vec, ec_strdup("0")) < 0) + GOTO_FAIL; + if (ec_vec_add_ptr(vec, ec_strdup("1")) < 0) + GOTO_FAIL; + if (ec_vec_add_ptr(vec, ec_strdup("2")) < 0) + GOTO_FAIL; + + if (ec_vec_get(&vals, vec, 0) < 0) + GOTO_FAIL; + if (strcmp(vals, "0")) + GOTO_FAIL; + if (ec_vec_get(&vals, vec, 1) < 0) + GOTO_FAIL; + if (strcmp(vals, "1")) + GOTO_FAIL; + if (ec_vec_get(&vals, vec, 2) < 0) + GOTO_FAIL; + if (strcmp(vals, "2")) + GOTO_FAIL; + + ec_vec_free(vec); + vec = NULL; + + /* invalid args */ + vec = ec_vec(0, 0, NULL, NULL); + if (vec != NULL) + GOTO_FAIL; + + return 0; + +fail: + ec_vec_free(vec); + ec_vec_free(vec2); + return -1; +} +/* LCOV_EXCL_STOP */ + +static struct ec_test ec_vec_test = { + .name = "vec", + .test = ec_vec_testcase, +}; + +EC_TEST_REGISTER(ec_vec_test); diff --git a/lib/ecoli_vec.h b/lib/ecoli_vec.h new file mode 100644 index 0000000..782ed70 --- /dev/null +++ b/lib/ecoli_vec.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2016, Olivier MATZ + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the University of California, Berkeley nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef ECOLI_VEC_ +#define ECOLI_VEC_ + +#include +#include +#include + +/* if NULL, default does nothing */ +typedef void (*ec_vec_elt_free_t)(void *ptr); +/* if NULL, default is: + * memcpy(dst, src, vec->elt_size) + */ +typedef void (*ec_vec_elt_copy_t)(void *dst, void *src); + +struct ec_vec *ec_vec(size_t elt_size, size_t size, + ec_vec_elt_copy_t copy, ec_vec_elt_free_t free); +int ec_vec_add_by_ref(struct ec_vec *vec, void *ptr); + +int ec_vec_add_ptr(struct ec_vec *vec, void *elt); +int ec_vec_add_u8(struct ec_vec *vec, uint8_t elt); +int ec_vec_add_u16(struct ec_vec *vec, uint16_t elt); +int ec_vec_add_u32(struct ec_vec *vec, uint32_t elt); +int ec_vec_add_u64(struct ec_vec *vec, uint64_t elt); + +int ec_vec_get(void *ptr, const struct ec_vec *vec, size_t idx); + +struct ec_vec *ec_vec_dup(const struct ec_vec *vec); +struct ec_vec *ec_vec_ndup(const struct ec_vec *vec, + size_t off, size_t len); +void ec_vec_free(struct ec_vec *vec); +size_t ec_vec_len(const struct ec_vec *vec); + +#endif -- 2.39.5