rework keyval
authorOlivier Matz <zer0@droids-corp.org>
Thu, 21 Mar 2019 19:10:20 +0000 (20:10 +0100)
committerOlivier Matz <zer0@droids-corp.org>
Thu, 21 Mar 2019 19:10:20 +0000 (20:10 +0100)
include/ecoli_keyval.h
src/ecoli_config.c
src/ecoli_keyval.c

index a3e9400..38b0d40 100644 (file)
@@ -18,7 +18,7 @@
 typedef void (*ec_keyval_elt_free_t)(void *);
 
 struct ec_keyval;
-struct ec_keyval_iter;
+struct ec_keyval_elt_ref;
 
 /**
  * Create a hash table.
@@ -133,20 +133,19 @@ void ec_keyval_dump(FILE *out, const struct ec_keyval *keyval);
  *
  *     // dump elements
  *     for (iter = ec_keyval_iter(keyval);
- *          ec_keyval_iter_valid(iter);
- *          ec_keyval_iter_next(iter)) {
+ *          iter != NULL;
+ *          iter = ec_keyval_iter_next(iter)) {
  *             printf("  %s: %p\n",
  *                     ec_keyval_iter_get_key(iter),
  *                     ec_keyval_iter_get_val(iter));
  *     }
- *     ec_keyval_iter_free(iter);
  *
  * @param keyval
  *   The hash table.
  * @return
- *   An iterator, or NULL on error (errno is set).
+ *   An iterator element, or NULL if the dict is empty.
  */
-struct ec_keyval_iter *
+struct ec_keyval_elt_ref *
 ec_keyval_iter(const struct ec_keyval *keyval);
 
 /**
@@ -154,27 +153,11 @@ ec_keyval_iter(const struct ec_keyval *keyval);
  *
  * @param iter
  *   The hash table iterator.
- */
-void ec_keyval_iter_next(struct ec_keyval_iter *iter);
-
-/**
- * Free the iterator.
- *
- * @param iter
- *   The hash table iterator.
- */
-void ec_keyval_iter_free(struct ec_keyval_iter *iter);
-
-/**
- * Check if the iterator points to a valid element.
- *
- * @param iter
- *   The hash table iterator.
  * @return
- *   true if the element is valid, else false.
+ *   An iterator element, or NULL there is no more element.
  */
-bool
-ec_keyval_iter_valid(const struct ec_keyval_iter *iter);
+struct ec_keyval_elt_ref *
+ec_keyval_iter_next(struct ec_keyval_elt_ref *iter);
 
 /**
  * Get the key of the current element.
@@ -186,7 +169,7 @@ ec_keyval_iter_valid(const struct ec_keyval_iter *iter);
  *   invalid element.
  */
 const char *
-ec_keyval_iter_get_key(const struct ec_keyval_iter *iter);
+ec_keyval_iter_get_key(const struct ec_keyval_elt_ref *iter);
 
 /**
  * Get the value of the current element.
@@ -198,7 +181,7 @@ ec_keyval_iter_get_key(const struct ec_keyval_iter *iter);
  *   invalid element.
  */
 void *
-ec_keyval_iter_get_val(const struct ec_keyval_iter *iter);
+ec_keyval_iter_get_val(const struct ec_keyval_elt_ref *iter);
 
 
 #endif
index 66d9232..3a98843 100644 (file)
@@ -461,15 +461,15 @@ ec_config_dict_cmp(const struct ec_keyval *d1,
                const struct ec_keyval *d2)
 {
        const struct ec_config *v1, *v2;
-       struct ec_keyval_iter *iter = NULL;
+       struct ec_keyval_elt_ref *iter = NULL;
        const char *key;
 
        if (ec_keyval_len(d1) != ec_keyval_len(d2))
                return -1;
 
        for (iter = ec_keyval_iter(d1);
-            ec_keyval_iter_valid(iter);
-            ec_keyval_iter_next(iter)) {
+            iter != NULL;
+            iter = ec_keyval_iter_next(iter)) {
                key = ec_keyval_iter_get_key(iter);
                v1 = ec_keyval_iter_get_val(iter);
                v2 = ec_keyval_get(d2, key);
@@ -478,11 +478,9 @@ ec_config_dict_cmp(const struct ec_keyval *d1,
                        goto fail;
        }
 
-       ec_keyval_iter_free(iter);
        return 0;
 
 fail:
-       ec_keyval_iter_free(iter);
        return -1;
 }
 
@@ -556,13 +554,13 @@ ec_config_dict_validate(const struct ec_keyval *dict,
                        const struct ec_config_schema *schema)
 {
        const struct ec_config *value;
-       struct ec_keyval_iter *iter = NULL;
+       struct ec_keyval_elt_ref *iter = NULL;
        const struct ec_config_schema *sch;
        const char *key;
 
        for (iter = ec_keyval_iter(dict);
-            ec_keyval_iter_valid(iter);
-            ec_keyval_iter_next(iter)) {
+            iter != NULL;
+            iter = ec_keyval_iter_next(iter)) {
 
                key = ec_keyval_iter_get_key(iter);
                value = ec_keyval_iter_get_val(iter);
@@ -582,11 +580,9 @@ ec_config_dict_validate(const struct ec_keyval *dict,
                }
        }
 
-       ec_keyval_iter_free(iter);
        return 0;
 
 fail:
-       ec_keyval_iter_free(iter);
        return -1;
 }
 
@@ -738,7 +734,7 @@ static struct ec_config *
 ec_config_dict_dup(const struct ec_keyval *dict)
 {
        struct ec_config *dup = NULL, *value;
-       struct ec_keyval_iter *iter = NULL;
+       struct ec_keyval_elt_ref *iter = NULL;
        const char *key;
 
        dup = ec_config_dict();
@@ -746,8 +742,8 @@ ec_config_dict_dup(const struct ec_keyval *dict)
                goto fail;
 
        for (iter = ec_keyval_iter(dict);
-            ec_keyval_iter_valid(iter);
-            ec_keyval_iter_next(iter)) {
+            iter != NULL;
+            iter = ec_keyval_iter_next(iter)) {
                key = ec_keyval_iter_get_key(iter);
                value = ec_config_dup(ec_keyval_iter_get_val(iter));
                if (value == NULL)
@@ -755,13 +751,11 @@ ec_config_dict_dup(const struct ec_keyval *dict)
                if (ec_config_dict_set(dup, key, value) < 0)
                        goto fail;
        }
-       ec_keyval_iter_free(iter);
 
        return dup;
 
 fail:
        ec_config_free(dup);
-       ec_keyval_iter_free(iter);
        return NULL;
 }
 
@@ -820,7 +814,7 @@ ec_config_dict_dump(FILE *out, const char *key, const struct ec_keyval *dict,
                size_t indent)
 {
        const struct ec_config *value;
-       struct ec_keyval_iter *iter;
+       struct ec_keyval_elt_ref *iter;
        const char *k;
 
        fprintf(out, "%*s" "%s%s%stype=dict\n", (int)indent * 4, "",
@@ -829,18 +823,16 @@ ec_config_dict_dump(FILE *out, const char *key, const struct ec_keyval *dict,
                key ? " ": "");
 
        for (iter = ec_keyval_iter(dict);
-            ec_keyval_iter_valid(iter);
-            ec_keyval_iter_next(iter)) {
+            iter != NULL;
+            iter = ec_keyval_iter_next(iter)) {
                k = ec_keyval_iter_get_key(iter);
                value = ec_keyval_iter_get_val(iter);
                if (__ec_config_dump(out, k, value, indent + 1) < 0)
                        goto fail;
        }
-       ec_keyval_iter_free(iter);
        return 0;
 
 fail:
-       ec_keyval_iter_free(iter);
        return -1;
 }
 
index 12fe66b..a99aaf0 100644 (file)
@@ -34,24 +34,20 @@ struct ec_keyval_elt {
 };
 
 struct ec_keyval_elt_ref {
-       LIST_ENTRY(ec_keyval_elt_ref) next;
+       TAILQ_ENTRY(ec_keyval_elt_ref) next;
+       TAILQ_ENTRY(ec_keyval_elt_ref) hnext;
        struct ec_keyval_elt *elt;
 };
 
-LIST_HEAD(ec_keyval_elt_ref_list, ec_keyval_elt_ref);
+TAILQ_HEAD(ec_keyval_elt_ref_list, ec_keyval_elt_ref);
 
 struct ec_keyval {
        size_t len;
        size_t table_size;
+       struct ec_keyval_elt_ref_list list;
        struct ec_keyval_elt_ref_list *table;
 };
 
-struct ec_keyval_iter {
-       const struct ec_keyval *keyval;
-       size_t cur_idx;
-       const struct ec_keyval_elt_ref *cur_ref;
-};
-
 struct ec_keyval *ec_keyval(void)
 {
        struct ec_keyval *keyval;
@@ -59,6 +55,7 @@ struct ec_keyval *ec_keyval(void)
        keyval = ec_calloc(1, sizeof(*keyval));
        if (keyval == NULL)
                return NULL;
+       TAILQ_INIT(&keyval->list);
 
        return keyval;
 }
@@ -79,7 +76,7 @@ ec_keyval_lookup(const struct ec_keyval *keyval, const char *key)
        }
 
        h = ec_murmurhash3(key, strlen(key), ec_keyval_seed);
-       LIST_FOREACH(ref, &keyval->table[h & mask], next) {
+       TAILQ_FOREACH(ref, &keyval->table[h & mask], hnext) {
                if (strcmp(ref->elt->key, key) == 0)
                        return ref;
        }
@@ -124,6 +121,7 @@ void *ec_keyval_get(const struct ec_keyval *keyval, const char *key)
 int ec_keyval_del(struct ec_keyval *keyval, const char *key)
 {
        struct ec_keyval_elt_ref *ref;
+       size_t idx;
 
        ref = ec_keyval_lookup(keyval, key);
        if (ref == NULL)
@@ -131,7 +129,9 @@ int ec_keyval_del(struct ec_keyval *keyval, const char *key)
 
        /* we could resize table here */
 
-       LIST_REMOVE(ref, next);
+       TAILQ_REMOVE(&keyval->list, ref, next);
+       idx = ref->elt->hash & (keyval->table_size - 1);
+       TAILQ_REMOVE(&keyval->table[idx], ref, hnext);
        ec_keyval_elt_ref_free(ref);
        keyval->len--;
 
@@ -152,15 +152,14 @@ static int ec_keyval_table_resize(struct ec_keyval *keyval, size_t new_size)
        new_table = ec_calloc(new_size, sizeof(*keyval->table));
        if (new_table == NULL)
                return -1;
-
-       for (i = 0; i < keyval->table_size; i++) {
-               while (!LIST_EMPTY(&keyval->table[i])) {
-                       ref = LIST_FIRST(&keyval->table[i]);
-                       LIST_REMOVE(ref, next);
-                       LIST_INSERT_HEAD(
-                               &new_table[ref->elt->hash & (new_size - 1)],
-                               ref, next);
-               }
+       for (i = 0; i < new_size; i++)
+               TAILQ_INIT(&new_table[i]);
+
+       TAILQ_FOREACH(ref, &keyval->list, next) {
+               i = ref->elt->hash & (keyval->table_size - 1);
+               TAILQ_REMOVE(&keyval->table[i], ref, hnext);
+               i = ref->elt->hash & (new_size - 1);
+               TAILQ_INSERT_TAIL(&new_table[i], ref, hnext);
        }
 
        ec_free(keyval->table);
@@ -191,7 +190,8 @@ __ec_keyval_set(struct ec_keyval *keyval, struct ec_keyval_elt_ref *ref)
        }
 
        mask = keyval->table_size - 1;
-       LIST_INSERT_HEAD(&keyval->table[ref->elt->hash & mask], ref, next);
+       TAILQ_INSERT_TAIL(&keyval->table[ref->elt->hash & mask], ref, hnext);
+       TAILQ_INSERT_TAIL(&keyval->list, ref, next);
        keyval->len++;
 
        return 0;
@@ -243,17 +243,17 @@ fail:
 void ec_keyval_free(struct ec_keyval *keyval)
 {
        struct ec_keyval_elt_ref *ref;
-       size_t i;
+       size_t idx;
 
        if (keyval == NULL)
                return;
 
-       for (i = 0; i < keyval->table_size; i++) {
-               while (!LIST_EMPTY(&keyval->table[i])) {
-                       ref = LIST_FIRST(&keyval->table[i]);
-                       LIST_REMOVE(ref, next);
-                       ec_keyval_elt_ref_free(ref);
-               }
+       while (!TAILQ_EMPTY(&keyval->list)) {
+               ref = TAILQ_FIRST(&keyval->list);
+               TAILQ_REMOVE(&keyval->list, ref, next);
+               idx = ref->elt->hash & (keyval->table_size - 1);
+               TAILQ_REMOVE(&keyval->table[idx], ref, hnext);
+               ec_keyval_elt_ref_free(ref);
        }
        ec_free(keyval->table);
        ec_free(keyval);
@@ -264,91 +264,45 @@ size_t ec_keyval_len(const struct ec_keyval *keyval)
        return keyval->len;
 }
 
-void
-ec_keyval_iter_free(struct ec_keyval_iter *iter)
-{
-       ec_free(iter);
-}
-
-struct ec_keyval_iter *
+struct ec_keyval_elt_ref *
 ec_keyval_iter(const struct ec_keyval *keyval)
 {
-       struct ec_keyval_iter *iter = NULL;
-
-       iter = ec_calloc(1, sizeof(*iter));
-       if (iter == NULL)
+       if (keyval == NULL)
                return NULL;
 
-       iter->keyval = keyval;
-       iter->cur_idx = 0;
-       iter->cur_ref = NULL;
-
-       ec_keyval_iter_next(iter);
-
-       return iter;
-}
-
-void
-ec_keyval_iter_next(struct ec_keyval_iter *iter)
-{
-       const struct ec_keyval_elt_ref *ref;
-       size_t i;
-
-       i = iter->cur_idx;
-       if (i == iter->keyval->table_size)
-               return; /* no more element */
-
-       if (iter->cur_ref != NULL) {
-               ref = LIST_NEXT(iter->cur_ref, next);
-               if (ref != NULL) {
-                       iter->cur_ref = ref;
-                       return;
-               }
-               i++;
-       }
-
-       for (; i < iter->keyval->table_size; i++) {
-               LIST_FOREACH(ref, &iter->keyval->table[i], next) {
-                       iter->cur_idx = i;
-                       iter->cur_ref = LIST_FIRST(&iter->keyval->table[i]);
-                       return;
-               }
-       }
-
-       iter->cur_idx = iter->keyval->table_size;
-       iter->cur_ref = NULL;
+       return TAILQ_FIRST(&keyval->list);
 }
 
-bool
-ec_keyval_iter_valid(const struct ec_keyval_iter *iter)
+struct ec_keyval_elt_ref *
+ec_keyval_iter_next(struct ec_keyval_elt_ref *iter)
 {
-       if (iter == NULL || iter->cur_ref == NULL)
-               return false;
+       if (iter == NULL)
+               return NULL;
 
-       return true;
+       return TAILQ_NEXT(iter, next);
 }
 
 const char *
-ec_keyval_iter_get_key(const struct ec_keyval_iter *iter)
+ec_keyval_iter_get_key(const struct ec_keyval_elt_ref *iter)
 {
-       if (iter == NULL || iter->cur_ref == NULL)
+       if (iter == NULL)
                return NULL;
 
-       return iter->cur_ref->elt->key;
+       return iter->elt->key;
 }
 
 void *
-ec_keyval_iter_get_val(const struct ec_keyval_iter *iter)
+ec_keyval_iter_get_val(const struct ec_keyval_elt_ref *iter)
 {
-       if (iter == NULL || iter->cur_ref == NULL)
+       if (iter == NULL)
                return NULL;
 
-       return iter->cur_ref->elt->val;
+       return iter->elt->val;
 }
 
 void ec_keyval_dump(FILE *out, const struct ec_keyval *keyval)
 {
-       struct ec_keyval_iter *iter;
+       struct ec_keyval_elt_ref *iter;
 
        if (keyval == NULL) {
                fprintf(out, "empty keyval\n");
@@ -357,36 +311,32 @@ void ec_keyval_dump(FILE *out, const struct ec_keyval *keyval)
 
        fprintf(out, "keyval:\n");
        for (iter = ec_keyval_iter(keyval);
-            ec_keyval_iter_valid(iter);
-            ec_keyval_iter_next(iter)) {
+            iter != NULL;
+            iter = ec_keyval_iter_next(iter)) {
                fprintf(out, "  %s: %p\n",
                        ec_keyval_iter_get_key(iter),
                        ec_keyval_iter_get_val(iter));
        }
-       ec_keyval_iter_free(iter);
 }
 
 struct ec_keyval *ec_keyval_dup(const struct ec_keyval *keyval)
 {
        struct ec_keyval *dup = NULL;
        struct ec_keyval_elt_ref *ref, *dup_ref = NULL;
-       size_t i;
 
        dup = ec_keyval();
        if (dup == NULL)
                return NULL;
 
-       for (i = 0; i < keyval->table_size; i++) {
-               LIST_FOREACH(ref, &keyval->table[i], next) {
-                       dup_ref = ec_calloc(1, sizeof(*ref));
-                       if (dup_ref == NULL)
-                               goto fail;
-                       dup_ref->elt = ref->elt;
-                       ref->elt->refcount++;
+       TAILQ_FOREACH(ref, &keyval->list, next) {
+               dup_ref = ec_calloc(1, sizeof(*ref));
+               if (dup_ref == NULL)
+                       goto fail;
+               dup_ref->elt = ref->elt;
+               ref->elt->refcount++;
 
-                       if (__ec_keyval_set(dup, dup_ref) < 0)
-                               goto fail;
-               }
+               if (__ec_keyval_set(dup, dup_ref) < 0)
+                       goto fail;
        }
 
        return dup;
@@ -429,7 +379,7 @@ EC_INIT_REGISTER(ec_keyval_init);
 static int ec_keyval_testcase(void)
 {
        struct ec_keyval *keyval, *dup;
-       struct ec_keyval_iter *iter;
+       struct ec_keyval_elt_ref *iter;
        char *val;
        size_t i, count;
        int ret, testres = 0;
@@ -445,11 +395,10 @@ static int ec_keyval_testcase(void)
 
        count = 0;
        for (iter = ec_keyval_iter(keyval);
-            ec_keyval_iter_valid(iter);
-            ec_keyval_iter_next(iter)) {
+            iter != NULL;
+            iter = ec_keyval_iter_next(iter)) {
                count++;
        }
-       ec_keyval_iter_free(iter);
        testres |= EC_TEST_CHECK(count == 0, "invalid count in iterator");
 
        testres |= EC_TEST_CHECK(ec_keyval_len(keyval) == 0, "bad keyval len");
@@ -535,11 +484,10 @@ static int ec_keyval_testcase(void)
 
        count = 0;
        for (iter = ec_keyval_iter(keyval);
-            ec_keyval_iter_valid(iter);
-            ec_keyval_iter_next(iter)) {
+            iter != NULL;
+            iter = ec_keyval_iter_next(iter)) {
                count++;
        }
-       ec_keyval_iter_free(iter);
        testres |= EC_TEST_CHECK(count == 100, "invalid count in iterator");
 
        /* einval */