vec
authorOlivier Matz <zer0@droids-corp.org>
Fri, 11 Aug 2017 19:17:34 +0000 (21:17 +0200)
committerOlivier Matz <zer0@droids-corp.org>
Fri, 18 Aug 2017 20:50:04 +0000 (22:50 +0200)
lib/ecoli_vec.c [new file with mode: 0644]
lib/ecoli_vec.h [new file with mode: 0644]

diff --git a/lib/ecoli_vec.c b/lib/ecoli_vec.c
new file mode 100644 (file)
index 0000000..8038b31
--- /dev/null
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * 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 <sys/types.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <assert.h>
+
+#include <ecoli_malloc.h>
+#include <ecoli_log.h>
+#include <ecoli_test.h>
+#include <ecoli_vec.h>
+
+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 (file)
index 0000000..782ed70
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
+ *
+ * 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 <sys/types.h>
+#include <stdint.h>
+#include <stdio.h>
+
+/* 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