duplicate and rename keyval in dict + htable
authorOlivier Matz <zer0@droids-corp.org>
Thu, 21 Mar 2019 19:21:41 +0000 (20:21 +0100)
committerOlivier Matz <zer0@droids-corp.org>
Thu, 21 Mar 2019 19:42:41 +0000 (20:42 +0100)
next commit will refactorize code

24 files changed:
examples/readline/main.c
include/ecoli_complete.h
include/ecoli_config.h
include/ecoli_dict.h [new file with mode: 0644]
include/ecoli_htable.h [new file with mode: 0644]
include/ecoli_keyval.h [deleted file]
include/ecoli_node.h
include/ecoli_parse.h
include/ecoli_strvec.h
include/meson.build
src/ecoli_complete.c
src/ecoli_config.c
src/ecoli_dict.c [new file with mode: 0644]
src/ecoli_editline.c
src/ecoli_htable.c [new file with mode: 0644]
src/ecoli_keyval.c [deleted file]
src/ecoli_node.c
src/ecoli_node_any.c
src/ecoli_node_dynamic.c
src/ecoli_node_re_lex.c
src/ecoli_parse.c
src/ecoli_strvec.c
src/ecoli_yaml.c
src/meson.build

index 2c81c53..a30953d 100644 (file)
@@ -15,7 +15,7 @@
 #include <ecoli_node.h>
 #include <ecoli_parse.h>
 #include <ecoli_complete.h>
-#include <ecoli_keyval.h>
+#include <ecoli_dict.h>
 #include <ecoli_node_str.h>
 #include <ecoli_node_seq.h>
 #include <ecoli_node_space.h>
@@ -118,7 +118,7 @@ static char *get_node_help(const struct ec_comp_item *item)
             state = ec_parse_get_parent(state)) {
                node = ec_parse_get_node(state);
                if (node_help == NULL)
-                       node_help = ec_keyval_get(ec_node_attrs(node), "help");
+                       node_help = ec_dict_get(ec_node_attrs(node), "help");
                if (node_desc == NULL)
                        node_desc = ec_node_desc(node);
        }
@@ -244,13 +244,13 @@ static int create_commands(void)
        );
        if (cmd == NULL)
                goto fail;
-       ec_keyval_set(ec_node_attrs(cmd), "help",
+       ec_dict_set(ec_node_attrs(cmd), "help",
                "say hello to someone several times", NULL);
-       ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "john")),
+       ec_dict_set(ec_node_attrs(ec_node_find(cmd, "john")),
                "help", "specific help for john", NULL);
-       ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "name")),
+       ec_dict_set(ec_node_attrs(ec_node_find(cmd, "name")),
                "help", "the name of the person", NULL);
-       ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "int")),
+       ec_dict_set(ec_node_attrs(ec_node_find(cmd, "int")),
                "help", "an integer (0-10)", NULL);
        if (ec_node_or_add(cmdlist, cmd) < 0)
                goto fail;
@@ -261,11 +261,11 @@ static int create_commands(void)
                        ec_node_int("count", 0, 10, 10));
        if (cmd == NULL)
                goto fail;
-       ec_keyval_set(ec_node_attrs(cmd), "help",
+       ec_dict_set(ec_node_attrs(cmd), "help",
                "say good morning to someone several times", NULL);
-       ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "name")), "help",
+       ec_dict_set(ec_node_attrs(ec_node_find(cmd, "name")), "help",
                "the person to greet", NULL);
-       ec_keyval_set(ec_node_attrs(ec_node_find(cmd, "count")), "help",
+       ec_dict_set(ec_node_attrs(ec_node_find(cmd, "count")), "help",
                "how many times to greet (0-10)", NULL);
        if (ec_node_or_add(cmdlist, cmd) < 0)
                goto fail;
@@ -275,7 +275,7 @@ static int create_commands(void)
                        "buy potatoes,carrots,pumpkins");
        if (cmd == NULL)
                goto fail;
-       ec_keyval_set(ec_node_attrs(cmd), "help",
+       ec_dict_set(ec_node_attrs(cmd), "help",
                "buy some vegetables", NULL);
        if (ec_node_or_add(cmdlist, cmd) < 0)
                goto fail;
@@ -292,7 +292,7 @@ static int create_commands(void)
                        1, 0));
        if (cmd == NULL)
                goto fail;
-       ec_keyval_set(ec_node_attrs(cmd), "help",
+       ec_dict_set(ec_node_attrs(cmd), "help",
                "eat vegetables (take some more potatoes)", NULL);
        if (ec_node_or_add(cmdlist, cmd) < 0)
                goto fail;
@@ -301,7 +301,7 @@ static int create_commands(void)
        cmd = EC_NODE_SEQ(EC_NO_ID,
                ec_node_str(EC_NO_ID, "bye")
        );
-       ec_keyval_set(ec_node_attrs(cmd), "help", "say bye", NULL);
+       ec_dict_set(ec_node_attrs(cmd), "help", "say bye", NULL);
        if (ec_node_or_add(cmdlist, cmd) < 0)
                goto fail;
 
@@ -310,7 +310,7 @@ static int create_commands(void)
                ec_node_str(EC_NO_ID, "load"),
                ec_node("file", EC_NO_ID)
        );
-       ec_keyval_set(ec_node_attrs(cmd), "help", "load a file", NULL);
+       ec_dict_set(ec_node_attrs(cmd), "help", "load a file", NULL);
        if (ec_node_or_add(cmdlist, cmd) < 0)
                goto fail;
 
index dee4123..4c71b5d 100644 (file)
@@ -36,7 +36,7 @@ struct ec_comp_group {
        const struct ec_node *node;
        struct ec_comp_item_list items;
        struct ec_parse *state;
-       struct ec_keyval *attrs;
+       struct ec_dict *attrs;
 };
 
 TAILQ_HEAD(ec_comp_group_list, ec_comp_group);
@@ -49,7 +49,7 @@ struct ec_comp {
        struct ec_parse *cur_state;
        struct ec_comp_group *cur_group;
        struct ec_comp_group_list groups;
-       struct ec_keyval *attrs;
+       struct ec_dict *attrs;
 };
 
 /*
index 7aa427f..b6d638e 100644 (file)
@@ -16,7 +16,7 @@
 #endif
 
 struct ec_config;
-struct ec_keyval;
+struct ec_dict;
 
 /**
  * The type identifier for a config value.
@@ -66,7 +66,7 @@ struct ec_config {
                uint64_t u64;   /** Unsigned integer value */
                char *string;   /** String value */
                struct ec_node *node;       /** Node value */
-               struct ec_keyval *dict;     /** Hash table value */
+               struct ec_dict *dict;     /** Hash table value */
                struct ec_config_list list; /** List value */
        };
 
diff --git a/include/ecoli_dict.h b/include/ecoli_dict.h
new file mode 100644 (file)
index 0000000..5519c4c
--- /dev/null
@@ -0,0 +1,187 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
+ */
+
+/**
+ * Simple hash table API
+ *
+ * This file provides functions to store objects in hash tables, using strings
+ * as keys.
+ */
+
+#ifndef ECOLI_KEYVAL_
+#define ECOLI_KEYVAL_
+
+#include <stdio.h>
+#include <stdbool.h>
+
+typedef void (*ec_dict_elt_free_t)(void *);
+
+struct ec_dict;
+struct ec_dict_elt_ref;
+
+/**
+ * Create a hash table.
+ *
+ * @return
+ *   The hash table, or NULL on error (errno is set).
+ */
+struct ec_dict *ec_dict(void);
+
+/**
+ * Get a value from the hash table.
+ *
+ * @param dict
+ *   The hash table.
+ * @param key
+ *   The key string.
+ * @return
+ *   The element if it is found, or NULL on error (errno is set).
+ *   In case of success but the element is NULL, errno is set to 0.
+ */
+void *ec_dict_get(const struct ec_dict *dict, const char *key);
+
+/**
+ * Check if the hash table contains this key.
+ *
+ * @param dict
+ *   The hash table.
+ * @param key
+ *   The key string.
+ * @return
+ *   true if it contains the key, else false.
+ */
+bool ec_dict_has_key(const struct ec_dict *dict, const char *key);
+
+/**
+ * Delete an object from the hash table.
+ *
+ * @param dict
+ *   The hash table.
+ * @param key
+ *   The key string.
+ * @return
+ *   0 on success, or -1 on error (errno is set).
+ */
+int ec_dict_del(struct ec_dict *dict, const char *key);
+
+/**
+ * Add/replace an object in the hash table.
+ *
+ * @param dict
+ *   The hash table.
+ * @param key
+ *   The key string.
+ * @param val
+ *   The pointer to be saved in the hash table.
+ * @param free_cb
+ *   An optional pointer to a destructor function called when an
+ *   object is destroyed (ec_dict_del() or ec_dict_free()).
+ * @return
+ *   0 on success, or -1 on error (errno is set).
+ *   On error, the passed value is freed (free_cb(val) is called).
+ */
+int ec_dict_set(struct ec_dict *dict, const char *key, void *val,
+       ec_dict_elt_free_t free_cb);
+
+/**
+ * Free a hash table an all its objects.
+ *
+ * @param dict
+ *   The hash table.
+ */
+void ec_dict_free(struct ec_dict *dict);
+
+/**
+ * Get the length of a hash table.
+ *
+ * @param dict
+ *   The hash table.
+ * @return
+ *   The length of the hash table.
+ */
+size_t ec_dict_len(const struct ec_dict *dict);
+
+/**
+ * Duplicate a hash table
+ *
+ * A reference counter is shared between the clones of
+ * hash tables so that the objects are freed only when
+ * the last reference is destroyed.
+ *
+ * @param dict
+ *   The hash table.
+ * @return
+ *   The duplicated hash table, or NULL on error (errno is set).
+ */
+struct ec_dict *ec_dict_dup(const struct ec_dict *dict);
+
+/**
+ * Dump a hash table.
+ *
+ * @param out
+ *   The stream where the dump is sent.
+ * @param dict
+ *   The hash table.
+ */
+void ec_dict_dump(FILE *out, const struct ec_dict *dict);
+
+/**
+ * Iterate the elements in the hash table.
+ *
+ * The typical usage is as below:
+ *
+ *     // dump elements
+ *     for (iter = ec_dict_iter(dict);
+ *          iter != NULL;
+ *          iter = ec_dict_iter_next(iter)) {
+ *             printf("  %s: %p\n",
+ *                     ec_dict_iter_get_key(iter),
+ *                     ec_dict_iter_get_val(iter));
+ *     }
+ *
+ * @param dict
+ *   The hash table.
+ * @return
+ *   An iterator element, or NULL if the dict is empty.
+ */
+struct ec_dict_elt_ref *
+ec_dict_iter(const struct ec_dict *dict);
+
+/**
+ * Make the iterator point to the next element in the hash table.
+ *
+ * @param iter
+ *   The hash table iterator.
+ * @return
+ *   An iterator element, or NULL there is no more element.
+ */
+struct ec_dict_elt_ref *
+ec_dict_iter_next(struct ec_dict_elt_ref *iter);
+
+/**
+ * Get the key of the current element.
+ *
+ * @param iter
+ *   The hash table iterator.
+ * @return
+ *   The current element key, or NULL if the iterator points to an
+ *   invalid element.
+ */
+const char *
+ec_dict_iter_get_key(const struct ec_dict_elt_ref *iter);
+
+/**
+ * Get the value of the current element.
+ *
+ * @param iter
+ *   The hash table iterator.
+ * @return
+ *   The current element value, or NULL if the iterator points to an
+ *   invalid element.
+ */
+void *
+ec_dict_iter_get_val(const struct ec_dict_elt_ref *iter);
+
+
+#endif
diff --git a/include/ecoli_htable.h b/include/ecoli_htable.h
new file mode 100644 (file)
index 0000000..6729d91
--- /dev/null
@@ -0,0 +1,197 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
+ */
+
+/**
+ * Simple hash table API
+ *
+ * This file provides functions to store objects in hash tables,
+ * using arbitrary data as keys.
+ */
+
+#ifndef ECOLI_HTABLE_
+#define ECOLI_HTABLE_
+
+#include <stdio.h>
+#include <stdbool.h>
+
+typedef void (*ec_htable_elt_free_t)(void *);
+
+struct ec_htable;
+struct ec_htable_elt_ref;
+
+/**
+ * Create a hash table.
+ *
+ * @return
+ *   The hash table, or NULL on error (errno is set).
+ */
+struct ec_htable *ec_htable(void);
+
+/**
+ * Get a value from the hash table.
+ *
+ * @param htable
+ *   The hash table.
+ * @param key
+ *   The key.
+ * @param key_len
+ *   The key length.
+ * @return
+ *   The element if it is found, or NULL on error (errno is set).
+ *   In case of success but the element is NULL, errno is set to 0.
+ */
+void *ec_htable_get(const struct ec_htable *htable,
+               const void *key, size_t key_len);
+
+/**
+ * Check if the hash table contains this key.
+ *
+ * @param htable
+ *   The hash table.
+ * @param key
+ *   The key.
+ * @param key_len
+ *   The key length.
+ * @return
+ *   true if it contains the key, else false.
+ */
+bool ec_htable_has_key(const struct ec_htable *htable,
+               const void *key, size_t key_len);
+
+/**
+ * Delete an object from the hash table.
+ *
+ * @param htable
+ *   The hash table.
+ * @param key
+ *   The key.
+ * @param key_len
+ *   The key length.
+ * @return
+ *   0 on success, or -1 on error (errno is set).
+ */
+int ec_htable_del(struct ec_htable *htable, const void *key, size_t key_len);
+
+/**
+ * Add/replace an object in the hash table.
+ *
+ * @param htable
+ *   The hash table.
+ * @param key
+ *   The key.
+ * @param key_len
+ *   The key length.
+ * @param val
+ *   The pointer to be saved in the hash table.
+ * @param free_cb
+ *   An optional pointer to a destructor function called when an
+ *   object is destroyed (ec_htable_del() or ec_htable_free()).
+ * @return
+ *   0 on success, or -1 on error (errno is set).
+ *   On error, the passed value is freed (free_cb(val) is called).
+ */
+int ec_htable_set(struct ec_htable *htable, const void *key, size_t key_len,
+               void *val, ec_htable_elt_free_t free_cb);
+
+/**
+ * Free a hash table an all its objects.
+ *
+ * @param htable
+ *   The hash table.
+ */
+void ec_htable_free(struct ec_htable *htable);
+
+/**
+ * Get the length of a hash table.
+ *
+ * @param htable
+ *   The hash table.
+ * @return
+ *   The length of the hash table.
+ */
+size_t ec_htable_len(const struct ec_htable *htable);
+
+/**
+ * Duplicate a hash table
+ *
+ * A reference counter is shared between the clones of
+ * hash tables so that the objects are freed only when
+ * the last reference is destroyed.
+ *
+ * @param htable
+ *   The hash table.
+ * @return
+ *   The duplicated hash table, or NULL on error (errno is set).
+ */
+struct ec_htable *ec_htable_dup(const struct ec_htable *htable);
+
+/**
+ * Dump a hash table.
+ *
+ * @param out
+ *   The stream where the dump is sent.
+ * @param htable
+ *   The hash table.
+ */
+void ec_htable_dump(FILE *out, const struct ec_htable *htable);
+
+/**
+ * Iterate the elements in the hash table.
+ *
+ * The typical usage is as below:
+ *
+ *     // dump elements
+ *     for (iter = ec_htable_iter(htable);
+ *          iter != NULL;
+ *          iter = ec_htable_iter_next(iter)) {
+ *             printf("  %s: %p\n",
+ *                     ec_htable_iter_get_key(iter),
+ *                     ec_htable_iter_get_val(iter));
+ *     }
+ *
+ * @param htable
+ *   The hash table.
+ * @return
+ *   An iterator element, or NULL if the dict is empty.
+ */
+struct ec_htable_elt_ref *
+ec_htable_iter(const struct ec_htable *htable);
+
+/**
+ * Make the iterator point to the next element in the hash table.
+ *
+ * @param iter
+ *   The hash table iterator.
+ * @return
+ *   An iterator element, or NULL there is no more element.
+ */
+struct ec_htable_elt_ref *
+ec_htable_iter_next(struct ec_htable_elt_ref *iter);
+
+/**
+ * Get the key of the current element.
+ *
+ * @param iter
+ *   The hash table iterator.
+ * @return
+ *   The current element key, or NULL if the iterator points to an
+ *   invalid element.
+ */
+const char *
+ec_htable_iter_get_key(const struct ec_htable_elt_ref *iter);
+
+/**
+ * Get the value of the current element.
+ *
+ * @param iter
+ *   The hash table iterator.
+ * @return
+ *   The current element value, or NULL if the iterator points to an
+ *   invalid element.
+ */
+void *
+ec_htable_iter_get_val(const struct ec_htable_elt_ref *iter);
+
+
+#endif
diff --git a/include/ecoli_keyval.h b/include/ecoli_keyval.h
deleted file mode 100644 (file)
index 38b0d40..0000000
+++ /dev/null
@@ -1,187 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
- */
-
-/**
- * Simple hash table API
- *
- * This file provides functions to store objects in hash tables, using strings
- * as keys.
- */
-
-#ifndef ECOLI_KEYVAL_
-#define ECOLI_KEYVAL_
-
-#include <stdio.h>
-#include <stdbool.h>
-
-typedef void (*ec_keyval_elt_free_t)(void *);
-
-struct ec_keyval;
-struct ec_keyval_elt_ref;
-
-/**
- * Create a hash table.
- *
- * @return
- *   The hash table, or NULL on error (errno is set).
- */
-struct ec_keyval *ec_keyval(void);
-
-/**
- * Get a value from the hash table.
- *
- * @param keyval
- *   The hash table.
- * @param key
- *   The key string.
- * @return
- *   The element if it is found, or NULL on error (errno is set).
- *   In case of success but the element is NULL, errno is set to 0.
- */
-void *ec_keyval_get(const struct ec_keyval *keyval, const char *key);
-
-/**
- * Check if the hash table contains this key.
- *
- * @param keyval
- *   The hash table.
- * @param key
- *   The key string.
- * @return
- *   true if it contains the key, else false.
- */
-bool ec_keyval_has_key(const struct ec_keyval *keyval, const char *key);
-
-/**
- * Delete an object from the hash table.
- *
- * @param keyval
- *   The hash table.
- * @param key
- *   The key string.
- * @return
- *   0 on success, or -1 on error (errno is set).
- */
-int ec_keyval_del(struct ec_keyval *keyval, const char *key);
-
-/**
- * Add/replace an object in the hash table.
- *
- * @param keyval
- *   The hash table.
- * @param key
- *   The key string.
- * @param val
- *   The pointer to be saved in the hash table.
- * @param free_cb
- *   An optional pointer to a destructor function called when an
- *   object is destroyed (ec_keyval_del() or ec_keyval_free()).
- * @return
- *   0 on success, or -1 on error (errno is set).
- *   On error, the passed value is freed (free_cb(val) is called).
- */
-int ec_keyval_set(struct ec_keyval *keyval, const char *key, void *val,
-       ec_keyval_elt_free_t free_cb);
-
-/**
- * Free a hash table an all its objects.
- *
- * @param keyval
- *   The hash table.
- */
-void ec_keyval_free(struct ec_keyval *keyval);
-
-/**
- * Get the length of a hash table.
- *
- * @param keyval
- *   The hash table.
- * @return
- *   The length of the hash table.
- */
-size_t ec_keyval_len(const struct ec_keyval *keyval);
-
-/**
- * Duplicate a hash table
- *
- * A reference counter is shared between the clones of
- * hash tables so that the objects are freed only when
- * the last reference is destroyed.
- *
- * @param keyval
- *   The hash table.
- * @return
- *   The duplicated hash table, or NULL on error (errno is set).
- */
-struct ec_keyval *ec_keyval_dup(const struct ec_keyval *keyval);
-
-/**
- * Dump a hash table.
- *
- * @param out
- *   The stream where the dump is sent.
- * @param keyval
- *   The hash table.
- */
-void ec_keyval_dump(FILE *out, const struct ec_keyval *keyval);
-
-/**
- * Iterate the elements in the hash table.
- *
- * The typical usage is as below:
- *
- *     // dump elements
- *     for (iter = ec_keyval_iter(keyval);
- *          iter != NULL;
- *          iter = ec_keyval_iter_next(iter)) {
- *             printf("  %s: %p\n",
- *                     ec_keyval_iter_get_key(iter),
- *                     ec_keyval_iter_get_val(iter));
- *     }
- *
- * @param keyval
- *   The hash table.
- * @return
- *   An iterator element, or NULL if the dict is empty.
- */
-struct ec_keyval_elt_ref *
-ec_keyval_iter(const struct ec_keyval *keyval);
-
-/**
- * Make the iterator point to the next element in the hash table.
- *
- * @param iter
- *   The hash table iterator.
- * @return
- *   An iterator element, or NULL there is no more element.
- */
-struct ec_keyval_elt_ref *
-ec_keyval_iter_next(struct ec_keyval_elt_ref *iter);
-
-/**
- * Get the key of the current element.
- *
- * @param iter
- *   The hash table iterator.
- * @return
- *   The current element key, or NULL if the iterator points to an
- *   invalid element.
- */
-const char *
-ec_keyval_iter_get_key(const struct ec_keyval_elt_ref *iter);
-
-/**
- * Get the value of the current element.
- *
- * @param iter
- *   The hash table iterator.
- * @return
- *   The current element value, or NULL if the iterator points to an
- *   invalid element.
- */
-void *
-ec_keyval_iter_get_val(const struct ec_keyval_elt_ref *iter);
-
-
-#endif
index 45f3e74..acd1daa 100644 (file)
@@ -54,7 +54,7 @@ struct ec_node;
 struct ec_parse;
 struct ec_comp;
 struct ec_strvec;
-struct ec_keyval;
+struct ec_dict;
 struct ec_config;
 struct ec_config_schema;
 
@@ -157,7 +157,7 @@ struct ec_node {
        struct ec_config *config;    /**< Generic configuration. */
        char *id;
        char *desc;
-       struct ec_keyval *attrs;
+       struct ec_dict *attrs;
        unsigned int refcnt;
        struct {
                enum ec_node_free_state state; /**< State of loop detection */
@@ -192,7 +192,7 @@ ec_node_get_child(const struct ec_node *node, size_t i,
 
 /* XXX add more accessors */
 const struct ec_node_type *ec_node_type(const struct ec_node *node);
-struct ec_keyval *ec_node_attrs(const struct ec_node *node);
+struct ec_dict *ec_node_attrs(const struct ec_node *node);
 const char *ec_node_id(const struct ec_node *node);
 const char *ec_node_desc(const struct ec_node *node);
 
index 9048808..c88fc18 100644 (file)
@@ -197,7 +197,7 @@ void ec_parse_del_last_child(struct ec_parse *parse);
  *
  *
  */
-struct ec_keyval *ec_parse_get_attrs(struct ec_parse *parse);
+struct ec_dict *ec_parse_get_attrs(struct ec_parse *parse);
 
 /**
  *
index cabe6b2..727d4c8 100644 (file)
@@ -166,7 +166,7 @@ const char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx);
  *   The read-only attributes (dictionnary) of the string at specified
  *   index, or NULL if there is no attribute.
  */
-const struct ec_keyval *ec_strvec_get_attrs(const struct ec_strvec *strvec,
+const struct ec_dict *ec_strvec_get_attrs(const struct ec_strvec *strvec,
        size_t idx);
 
 /**
@@ -183,7 +183,7 @@ const struct ec_keyval *ec_strvec_get_attrs(const struct ec_strvec *strvec,
  *   are freed and must not be used by the caller.
  */
 int ec_strvec_set_attrs(struct ec_strvec *strvec, size_t idx,
-                       struct ec_keyval *attrs);
+                       struct ec_dict *attrs);
 
 /**
  * Compare two string vectors
index ea33eb4..1b97922 100644 (file)
@@ -5,8 +5,9 @@ libecoli_headers = [
        'ecoli_assert.h',
        'ecoli_complete.h',
        'ecoli_config.h',
+       'ecoli_dict.h',
        'ecoli_init.h',
-       'ecoli_keyval.h',
+       'ecoli_htable.h',
        'ecoli_log.h',
        'ecoli_malloc.h',
        'ecoli_murmurhash.h',
index a9becdf..e2f150a 100644 (file)
@@ -11,7 +11,7 @@
 #include <ecoli_malloc.h>
 #include <ecoli_string.h>
 #include <ecoli_strvec.h>
-#include <ecoli_keyval.h>
+#include <ecoli_dict.h>
 #include <ecoli_log.h>
 #include <ecoli_test.h>
 #include <ecoli_node.h>
@@ -31,7 +31,7 @@ struct ec_comp_item {
        char *full;       /* the full token after completion */
        char *completion; /* chars that are added, NULL if not applicable */
        char *display;    /* what should be displayed by help/completers */
-       struct ec_keyval *attrs;
+       struct ec_dict *attrs;
 };
 
 struct ec_comp *ec_comp(struct ec_parse *state)
@@ -42,7 +42,7 @@ struct ec_comp *ec_comp(struct ec_parse *state)
        if (comp == NULL)
                goto fail;
 
-       comp->attrs = ec_keyval();
+       comp->attrs = ec_dict();
        if (comp->attrs == NULL)
                goto fail;
 
@@ -54,7 +54,7 @@ struct ec_comp *ec_comp(struct ec_parse *state)
 
  fail:
        if (comp != NULL)
-               ec_keyval_free(comp->attrs);
+               ec_dict_free(comp->attrs);
        ec_free(comp);
 
        return NULL;
@@ -165,7 +165,7 @@ ec_comp_group(const struct ec_node *node, struct ec_parse *parse)
        if (grp == NULL)
                return NULL;
 
-       grp->attrs = ec_keyval();
+       grp->attrs = ec_dict();
        if (grp->attrs == NULL)
                goto fail;
 
@@ -181,7 +181,7 @@ ec_comp_group(const struct ec_node *node, struct ec_parse *parse)
 fail:
        if (grp != NULL) {
                ec_parse_free(grp->state);
-               ec_keyval_free(grp->attrs);
+               ec_dict_free(grp->attrs);
        }
        ec_free(grp);
        return NULL;
@@ -192,7 +192,7 @@ ec_comp_item(enum ec_comp_type type,
        const char *start, const char *full)
 {
        struct ec_comp_item *item = NULL;
-       struct ec_keyval *attrs = NULL;
+       struct ec_dict *attrs = NULL;
        char *comp_cp = NULL, *start_cp = NULL;
        char *full_cp = NULL, *display_cp = NULL;
 
@@ -209,7 +209,7 @@ ec_comp_item(enum ec_comp_type type,
        if (item == NULL)
                goto fail;
 
-       attrs = ec_keyval();
+       attrs = ec_dict();
        if (attrs == NULL)
                goto fail;
 
@@ -243,7 +243,7 @@ ec_comp_item(enum ec_comp_type type,
        return item;
 
 fail:
-       ec_keyval_free(attrs);
+       ec_dict_free(attrs);
        ec_free(comp_cp);
        ec_free(start_cp);
        ec_free(full_cp);
@@ -417,7 +417,7 @@ ec_comp_item_free(struct ec_comp_item *item)
        ec_free(item->start);
        ec_free(item->completion);
        ec_free(item->display);
-       ec_keyval_free(item->attrs);
+       ec_dict_free(item->attrs);
        ec_free(item);
 }
 
@@ -481,7 +481,7 @@ static void ec_comp_group_free(struct ec_comp_group *grp)
                ec_comp_item_free(item);
        }
        ec_parse_free(ec_parse_get_root(grp->state));
-       ec_keyval_free(grp->attrs);
+       ec_dict_free(grp->attrs);
        ec_free(grp);
 }
 
@@ -497,7 +497,7 @@ void ec_comp_free(struct ec_comp *comp)
                TAILQ_REMOVE(&comp->groups, grp, next);
                ec_comp_group_free(grp);
        }
-       ec_keyval_free(comp->attrs);
+       ec_dict_free(comp->attrs);
        ec_free(comp);
 }
 
index 3a98843..c8cd316 100644 (file)
@@ -10,7 +10,7 @@
 
 #include <ecoli_string.h>
 #include <ecoli_malloc.h>
-#include <ecoli_keyval.h>
+#include <ecoli_dict.h>
 #include <ecoli_node.h>
 #include <ecoli_log.h>
 #include <ecoli_test.h>
@@ -29,7 +29,7 @@ static int
 __ec_config_dump(FILE *out, const char *key, const struct ec_config *config,
        size_t indent);
 static int
-ec_config_dict_validate(const struct ec_keyval *dict,
+ec_config_dict_validate(const struct ec_dict *dict,
                        const struct ec_config_schema *schema);
 
 bool
@@ -324,9 +324,9 @@ struct ec_config *
 ec_config_dict(void)
 {
        struct ec_config *value = NULL;
-       struct ec_keyval *dict = NULL;
+       struct ec_dict *dict = NULL;
 
-       dict = ec_keyval();
+       dict = ec_dict();
        if (dict == NULL)
                goto fail;
 
@@ -340,7 +340,7 @@ ec_config_dict(void)
        return value;
 
 fail:
-       ec_keyval_free(dict);
+       ec_dict_free(dict);
        ec_free(value);
        return NULL;
 }
@@ -428,7 +428,7 @@ ec_config_free(struct ec_config *value)
                }
                break;
        case EC_CONFIG_TYPE_DICT:
-               ec_keyval_free(value->dict);
+               ec_dict_free(value->dict);
                break;
        default:
                break;
@@ -455,24 +455,24 @@ ec_config_list_cmp(const struct ec_config_list *list1,
        return 0;
 }
 
-/* XXX -> ec_keyval_cmp() */
+/* XXX -> ec_dict_cmp() */
 static int
-ec_config_dict_cmp(const struct ec_keyval *d1,
-               const struct ec_keyval *d2)
+ec_config_dict_cmp(const struct ec_dict *d1,
+               const struct ec_dict *d2)
 {
        const struct ec_config *v1, *v2;
-       struct ec_keyval_elt_ref *iter = NULL;
+       struct ec_dict_elt_ref *iter = NULL;
        const char *key;
 
-       if (ec_keyval_len(d1) != ec_keyval_len(d2))
+       if (ec_dict_len(d1) != ec_dict_len(d2))
                return -1;
 
-       for (iter = ec_keyval_iter(d1);
+       for (iter = ec_dict_iter(d1);
             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);
+            iter = ec_dict_iter_next(iter)) {
+               key = ec_dict_iter_get_key(iter);
+               v1 = ec_dict_iter_get_val(iter);
+               v2 = ec_dict_get(d2, key);
 
                if (ec_config_cmp(v1, v2))
                        goto fail;
@@ -550,20 +550,20 @@ ec_config_list_validate(const struct ec_config_list *list,
 }
 
 static int
-ec_config_dict_validate(const struct ec_keyval *dict,
+ec_config_dict_validate(const struct ec_dict *dict,
                        const struct ec_config_schema *schema)
 {
        const struct ec_config *value;
-       struct ec_keyval_elt_ref *iter = NULL;
+       struct ec_dict_elt_ref *iter = NULL;
        const struct ec_config_schema *sch;
        const char *key;
 
-       for (iter = ec_keyval_iter(dict);
+       for (iter = ec_dict_iter(dict);
             iter != NULL;
-            iter = ec_keyval_iter_next(iter)) {
+            iter = ec_dict_iter_next(iter)) {
 
-               key = ec_keyval_iter_get_key(iter);
-               value = ec_keyval_iter_get_val(iter);
+               key = ec_dict_iter_get_key(iter);
+               value = ec_dict_iter_get_val(iter);
                sch = ec_config_schema_lookup(schema, key);
                if (sch == NULL || sch->type != value->type) {
                        errno = EBADMSG;
@@ -617,7 +617,7 @@ ec_config_dict_get(const struct ec_config *config, const char *key)
                return NULL;
        }
 
-       return ec_keyval_get(config->dict, key);
+       return ec_dict_get(config->dict, key);
 }
 
 struct ec_config *
@@ -653,7 +653,7 @@ int ec_config_dict_set(struct ec_config *config, const char *key,
                goto fail;
        }
 
-       return ec_keyval_set(config->dict, key, value,
+       return ec_dict_set(config->dict, key, value,
                        (void (*)(void *))free_cb);
 
 fail:
@@ -672,7 +672,7 @@ int ec_config_dict_del(struct ec_config *config, const char *key)
                return -1;
        }
 
-       return ec_keyval_del(config->dict, key);
+       return ec_dict_del(config->dict, key);
 }
 
 /* value is consumed */
@@ -731,21 +731,21 @@ fail:
 }
 
 static struct ec_config *
-ec_config_dict_dup(const struct ec_keyval *dict)
+ec_config_dict_dup(const struct ec_dict *dict)
 {
        struct ec_config *dup = NULL, *value;
-       struct ec_keyval_elt_ref *iter = NULL;
+       struct ec_dict_elt_ref *iter = NULL;
        const char *key;
 
        dup = ec_config_dict();
        if (dup == NULL)
                goto fail;
 
-       for (iter = ec_keyval_iter(dict);
+       for (iter = ec_dict_iter(dict);
             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));
+            iter = ec_dict_iter_next(iter)) {
+               key = ec_dict_iter_get_key(iter);
+               value = ec_config_dup(ec_dict_iter_get_val(iter));
                if (value == NULL)
                        goto fail;
                if (ec_config_dict_set(dup, key, value) < 0)
@@ -810,11 +810,11 @@ ec_config_list_dump(FILE *out, const char *key,
 }
 
 static int
-ec_config_dict_dump(FILE *out, const char *key, const struct ec_keyval *dict,
+ec_config_dict_dump(FILE *out, const char *key, const struct ec_dict *dict,
                size_t indent)
 {
        const struct ec_config *value;
-       struct ec_keyval_elt_ref *iter;
+       struct ec_dict_elt_ref *iter;
        const char *k;
 
        fprintf(out, "%*s" "%s%s%stype=dict\n", (int)indent * 4, "",
@@ -822,11 +822,11 @@ ec_config_dict_dump(FILE *out, const char *key, const struct ec_keyval *dict,
                key ? key: "",
                key ? " ": "");
 
-       for (iter = ec_keyval_iter(dict);
+       for (iter = ec_dict_iter(dict);
             iter != NULL;
-            iter = ec_keyval_iter_next(iter)) {
-               k = ec_keyval_iter_get_key(iter);
-               value = ec_keyval_iter_get_val(iter);
+            iter = ec_dict_iter_next(iter)) {
+               k = ec_dict_iter_get_key(iter);
+               value = ec_dict_iter_get_val(iter);
                if (__ec_config_dump(out, k, value, indent + 1) < 0)
                        goto fail;
        }
@@ -981,7 +981,7 @@ static const struct ec_config_schema sch_baseconfig[] = {
 static int ec_config_testcase(void)
 {
        struct ec_node *node = NULL;
-       struct ec_keyval *dict = NULL;
+       struct ec_dict *dict = NULL;
        const struct ec_config *value = NULL;
        struct ec_config *config = NULL, *config2 = NULL;
        struct ec_config *list = NULL, *subconfig = NULL;
@@ -1139,7 +1139,7 @@ static int ec_config_testcase(void)
        ec_config_free(list);
        ec_config_free(subconfig);
        ec_config_free(config);
-       ec_keyval_free(dict);
+       ec_dict_free(dict);
        ec_node_free(node);
 
        return testres;
@@ -1149,7 +1149,7 @@ fail:
        ec_config_free(subconfig);
        ec_config_free(config);
        ec_config_free(config2);
-       ec_keyval_free(dict);
+       ec_dict_free(dict);
        ec_node_free(node);
 
        return -1;
diff --git a/src/ecoli_dict.c b/src/ecoli_dict.c
new file mode 100644 (file)
index 0000000..09d7dda
--- /dev/null
@@ -0,0 +1,517 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <ecoli_init.h>
+#include <ecoli_malloc.h>
+#include <ecoli_log.h>
+#include <ecoli_test.h>
+#include <ecoli_murmurhash.h>
+#include <ecoli_dict.h>
+
+#define FACTOR 3
+
+EC_LOG_TYPE_REGISTER(dict);
+
+static uint32_t ec_dict_seed;
+
+struct ec_dict_elt {
+       char *key;
+       void *val;
+       uint32_t hash;
+       ec_dict_elt_free_t free;
+       unsigned int refcount;
+};
+
+struct ec_dict_elt_ref {
+       TAILQ_ENTRY(ec_dict_elt_ref) next;
+       TAILQ_ENTRY(ec_dict_elt_ref) hnext;
+       struct ec_dict_elt *elt;
+};
+
+TAILQ_HEAD(ec_dict_elt_ref_list, ec_dict_elt_ref);
+
+struct ec_dict {
+       size_t len;
+       size_t table_size;
+       struct ec_dict_elt_ref_list list;
+       struct ec_dict_elt_ref_list *table;
+};
+
+struct ec_dict *ec_dict(void)
+{
+       struct ec_dict *dict;
+
+       dict = ec_calloc(1, sizeof(*dict));
+       if (dict == NULL)
+               return NULL;
+       TAILQ_INIT(&dict->list);
+
+       return dict;
+}
+
+static struct ec_dict_elt_ref *
+ec_dict_lookup(const struct ec_dict *dict, const char *key)
+{
+       struct ec_dict_elt_ref *ref;
+       uint32_t h, mask = dict->table_size - 1;
+
+       if (dict == NULL || key == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+       if (dict->table_size == 0) {
+               errno = ENOENT;
+               return NULL;
+       }
+
+       h = ec_murmurhash3(key, strlen(key), ec_dict_seed);
+       TAILQ_FOREACH(ref, &dict->table[h & mask], hnext) {
+               if (strcmp(ref->elt->key, key) == 0)
+                       return ref;
+       }
+
+       errno = ENOENT;
+       return NULL;
+}
+
+static void ec_dict_elt_ref_free(struct ec_dict_elt_ref *ref)
+{
+       struct ec_dict_elt *elt;
+
+       if (ref == NULL)
+               return;
+
+       elt = ref->elt;
+       if (elt != NULL && --elt->refcount == 0) {
+               ec_free(elt->key);
+               if (elt->free != NULL)
+                       elt->free(elt->val);
+               ec_free(elt);
+       }
+       ec_free(ref);
+}
+
+bool ec_dict_has_key(const struct ec_dict *dict, const char *key)
+{
+       return !!ec_dict_lookup(dict, key);
+}
+
+void *ec_dict_get(const struct ec_dict *dict, const char *key)
+{
+       struct ec_dict_elt_ref *ref;
+
+       ref = ec_dict_lookup(dict, key);
+       if (ref == NULL)
+               return NULL;
+
+       return ref->elt->val;
+}
+
+int ec_dict_del(struct ec_dict *dict, const char *key)
+{
+       struct ec_dict_elt_ref *ref;
+       size_t idx;
+
+       ref = ec_dict_lookup(dict, key);
+       if (ref == NULL)
+               return -1;
+
+       /* we could resize table here */
+
+       TAILQ_REMOVE(&dict->list, ref, next);
+       idx = ref->elt->hash & (dict->table_size - 1);
+       TAILQ_REMOVE(&dict->table[idx], ref, hnext);
+       ec_dict_elt_ref_free(ref);
+       dict->len--;
+
+       return 0;
+}
+
+static int ec_dict_table_resize(struct ec_dict *dict, size_t new_size)
+{
+       struct ec_dict_elt_ref_list *new_table;
+       struct ec_dict_elt_ref *ref;
+       size_t i;
+
+       if (new_size == 0 || (new_size & (new_size - 1))) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       new_table = ec_calloc(new_size, sizeof(*dict->table));
+       if (new_table == NULL)
+               return -1;
+       for (i = 0; i < new_size; i++)
+               TAILQ_INIT(&new_table[i]);
+
+       TAILQ_FOREACH(ref, &dict->list, next) {
+               i = ref->elt->hash & (dict->table_size - 1);
+               TAILQ_REMOVE(&dict->table[i], ref, hnext);
+               i = ref->elt->hash & (new_size - 1);
+               TAILQ_INSERT_TAIL(&new_table[i], ref, hnext);
+       }
+
+       ec_free(dict->table);
+       dict->table = new_table;
+       dict->table_size = new_size;
+
+       return 0;
+}
+
+static int
+__ec_dict_set(struct ec_dict *dict, struct ec_dict_elt_ref *ref)
+{
+       size_t new_size;
+       uint32_t mask;
+       int ret;
+
+       /* remove previous entry if any */
+       ec_dict_del(dict, ref->elt->key);
+
+       if (dict->len >= dict->table_size) {
+               if (dict->table_size != 0)
+                       new_size =  dict->table_size << FACTOR;
+               else
+                       new_size =  1 << FACTOR;
+               ret = ec_dict_table_resize(dict, new_size);
+               if (ret < 0)
+                       return ret;
+       }
+
+       mask = dict->table_size - 1;
+       TAILQ_INSERT_TAIL(&dict->table[ref->elt->hash & mask], ref, hnext);
+       TAILQ_INSERT_TAIL(&dict->list, ref, next);
+       dict->len++;
+
+       return 0;
+}
+
+int ec_dict_set(struct ec_dict *dict, const char *key, void *val,
+       ec_dict_elt_free_t free_cb)
+{
+       struct ec_dict_elt *elt = NULL;
+       struct ec_dict_elt_ref *ref = NULL;
+       uint32_t h;
+
+       if (dict == NULL || key == NULL) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       ref = ec_calloc(1, sizeof(*ref));
+       if (ref == NULL)
+               goto fail;
+
+       elt = ec_calloc(1, sizeof(*elt));
+       if (elt == NULL)
+               goto fail;
+
+       ref->elt = elt;
+       elt->refcount = 1;
+       elt->val = val;
+       val = NULL;
+       elt->free = free_cb;
+       elt->key = ec_strdup(key);
+       if (elt->key == NULL)
+               goto fail;
+       h = ec_murmurhash3(key, strlen(key), ec_dict_seed);
+       elt->hash = h;
+
+       if (__ec_dict_set(dict, ref) < 0)
+               goto fail;
+
+       return 0;
+
+fail:
+       if (free_cb != NULL && val != NULL)
+               free_cb(val);
+       ec_dict_elt_ref_free(ref);
+       return -1;
+}
+
+void ec_dict_free(struct ec_dict *dict)
+{
+       struct ec_dict_elt_ref *ref;
+       size_t idx;
+
+       if (dict == NULL)
+               return;
+
+       while (!TAILQ_EMPTY(&dict->list)) {
+               ref = TAILQ_FIRST(&dict->list);
+               TAILQ_REMOVE(&dict->list, ref, next);
+               idx = ref->elt->hash & (dict->table_size - 1);
+               TAILQ_REMOVE(&dict->table[idx], ref, hnext);
+               ec_dict_elt_ref_free(ref);
+       }
+       ec_free(dict->table);
+       ec_free(dict);
+}
+
+size_t ec_dict_len(const struct ec_dict *dict)
+{
+       return dict->len;
+}
+
+struct ec_dict_elt_ref *
+ec_dict_iter(const struct ec_dict *dict)
+{
+       if (dict == NULL)
+               return NULL;
+
+       return TAILQ_FIRST(&dict->list);
+}
+
+struct ec_dict_elt_ref *
+ec_dict_iter_next(struct ec_dict_elt_ref *iter)
+{
+       if (iter == NULL)
+               return NULL;
+
+       return TAILQ_NEXT(iter, next);
+}
+
+const char *
+ec_dict_iter_get_key(const struct ec_dict_elt_ref *iter)
+{
+       if (iter == NULL)
+               return NULL;
+
+       return iter->elt->key;
+}
+
+void *
+ec_dict_iter_get_val(const struct ec_dict_elt_ref *iter)
+{
+       if (iter == NULL)
+               return NULL;
+
+       return iter->elt->val;
+}
+
+void ec_dict_dump(FILE *out, const struct ec_dict *dict)
+{
+       struct ec_dict_elt_ref *iter;
+
+       if (dict == NULL) {
+               fprintf(out, "empty dict\n");
+               return;
+       }
+
+       fprintf(out, "dict:\n");
+       for (iter = ec_dict_iter(dict);
+            iter != NULL;
+            iter = ec_dict_iter_next(iter)) {
+               fprintf(out, "  %s: %p\n",
+                       ec_dict_iter_get_key(iter),
+                       ec_dict_iter_get_val(iter));
+       }
+}
+
+struct ec_dict *ec_dict_dup(const struct ec_dict *dict)
+{
+       struct ec_dict *dup = NULL;
+       struct ec_dict_elt_ref *ref, *dup_ref = NULL;
+
+       dup = ec_dict();
+       if (dup == NULL)
+               return NULL;
+
+       TAILQ_FOREACH(ref, &dict->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_dict_set(dup, dup_ref) < 0)
+                       goto fail;
+       }
+
+       return dup;
+
+fail:
+       ec_dict_elt_ref_free(dup_ref);
+       ec_dict_free(dup);
+       return NULL;
+}
+
+static int ec_dict_init_func(void)
+{
+       int fd;
+       ssize_t ret;
+
+       return 0;//XXX for test reproduceability
+
+       fd = open("/dev/urandom", 0);
+       if (fd == -1) {
+               fprintf(stderr, "failed to open /dev/urandom\n");
+               return -1;
+       }
+       ret = read(fd, &ec_dict_seed, sizeof(ec_dict_seed));
+       if (ret != sizeof(ec_dict_seed)) {
+               fprintf(stderr, "failed to read /dev/urandom\n");
+               return -1;
+       }
+       close(fd);
+       return 0;
+}
+
+static struct ec_init ec_dict_init = {
+       .init = ec_dict_init_func,
+       .priority = 50,
+};
+
+EC_INIT_REGISTER(ec_dict_init);
+
+/* LCOV_EXCL_START */
+static int ec_dict_testcase(void)
+{
+       struct ec_dict *dict, *dup;
+       struct ec_dict_elt_ref *iter;
+       char *val;
+       size_t i, count;
+       int ret, testres = 0;
+       FILE *f = NULL;
+       char *buf = NULL;
+       size_t buflen = 0;
+
+       dict = ec_dict();
+       if (dict == NULL) {
+               EC_LOG(EC_LOG_ERR, "cannot create dict\n");
+               return -1;
+       }
+
+       count = 0;
+       for (iter = ec_dict_iter(dict);
+            iter != NULL;
+            iter = ec_dict_iter_next(iter)) {
+               count++;
+       }
+       testres |= EC_TEST_CHECK(count == 0, "invalid count in iterator");
+
+       testres |= EC_TEST_CHECK(ec_dict_len(dict) == 0, "bad dict len");
+       ret = ec_dict_set(dict, "key1", "val1", NULL);
+       testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
+       ret = ec_dict_set(dict, "key2", ec_strdup("val2"), ec_free_func);
+       testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
+       testres |= EC_TEST_CHECK(ec_dict_len(dict) == 2, "bad dict len");
+
+       val = ec_dict_get(dict, "key1");
+       testres |= EC_TEST_CHECK(val != NULL && !strcmp(val, "val1"),
+                               "invalid dict value");
+       val = ec_dict_get(dict, "key2");
+       testres |= EC_TEST_CHECK(val != NULL && !strcmp(val, "val2"),
+                               "invalid dict value");
+       val = ec_dict_get(dict, "key3");
+       testres |= EC_TEST_CHECK(val == NULL, "key3 should be NULL");
+
+       ret = ec_dict_set(dict, "key1", "another_val1", NULL);
+       testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
+       ret = ec_dict_set(dict, "key2", ec_strdup("another_val2"),
+                       ec_free_func);
+       testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
+       testres |= EC_TEST_CHECK(ec_dict_len(dict) == 2,
+                               "bad dict len");
+
+       val = ec_dict_get(dict, "key1");
+       testres |= EC_TEST_CHECK(val != NULL && !strcmp(val, "another_val1"),
+               "invalid dict value");
+       val = ec_dict_get(dict, "key2");
+       testres |= EC_TEST_CHECK(val != NULL && !strcmp(val, "another_val2"),
+               "invalid dict value");
+       testres |= EC_TEST_CHECK(ec_dict_has_key(dict, "key1"),
+               "key1 should be in dict");
+
+       f = open_memstream(&buf, &buflen);
+       if (f == NULL)
+               goto fail;
+       ec_dict_dump(f, NULL);
+       fclose(f);
+       f = NULL;
+       free(buf);
+       buf = NULL;
+
+       f = open_memstream(&buf, &buflen);
+       if (f == NULL)
+               goto fail;
+       ec_dict_dump(f, dict);
+       fclose(f);
+       f = NULL;
+       free(buf);
+       buf = NULL;
+
+       ret = ec_dict_del(dict, "key1");
+       testres |= EC_TEST_CHECK(ret == 0, "cannot del key1");
+       testres |= EC_TEST_CHECK(ec_dict_len(dict) == 1,
+               "invalid dict len");
+       ret = ec_dict_del(dict, "key2");
+       testres |= EC_TEST_CHECK(ret == 0, "cannot del key2");
+       testres |= EC_TEST_CHECK(ec_dict_len(dict) == 0,
+               "invalid dict len");
+
+       for (i = 0; i < 100; i++) {
+               char key[8];
+               snprintf(key, sizeof(key), "k%zd", i);
+               ret = ec_dict_set(dict, key, "val", NULL);
+               testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
+       }
+       dup = ec_dict_dup(dict);
+       testres |= EC_TEST_CHECK(dup != NULL, "cannot duplicate dict");
+       if (dup != NULL) {
+               for (i = 0; i < 100; i++) {
+                       char key[8];
+                       snprintf(key, sizeof(key), "k%zd", i);
+                       val = ec_dict_get(dup, key);
+                       testres |= EC_TEST_CHECK(
+                               val != NULL && !strcmp(val, "val"),
+                               "invalid dict value");
+               }
+               ec_dict_free(dup);
+               dup = NULL;
+       }
+
+       count = 0;
+       for (iter = ec_dict_iter(dict);
+            iter != NULL;
+            iter = ec_dict_iter_next(iter)) {
+               count++;
+       }
+       testres |= EC_TEST_CHECK(count == 100, "invalid count in iterator");
+
+       /* einval */
+       ret = ec_dict_set(dict, NULL, "val1", NULL);
+       testres |= EC_TEST_CHECK(ret == -1, "should not be able to set key");
+       val = ec_dict_get(dict, NULL);
+       testres |= EC_TEST_CHECK(val == NULL, "get(NULL) should no success");
+
+       ec_dict_free(dict);
+
+       return testres;
+
+fail:
+       ec_dict_free(dict);
+       if (f)
+               fclose(f);
+       free(buf);
+       return -1;
+}
+/* LCOV_EXCL_STOP */
+
+static struct ec_test ec_dict_test = {
+       .name = "dict",
+       .test = ec_dict_testcase,
+};
+
+EC_TEST_REGISTER(ec_dict_test);
index 4cc7ec4..ed8ea21 100644 (file)
@@ -12,7 +12,7 @@
 #include <ecoli_malloc.h>
 #include <ecoli_string.h>
 #include <ecoli_editline.h>
-#include <ecoli_keyval.h>
+#include <ecoli_dict.h>
 #include <ecoli_node.h>
 #include <ecoli_parse.h>
 #include <ecoli_complete.h>
@@ -397,7 +397,7 @@ static int get_node_help(const struct ec_comp_item *item,
             state = ec_parse_get_parent(state)) {
                node = ec_parse_get_node(state);
                if (node_help == NULL)
-                       node_help = ec_keyval_get(ec_node_attrs(node), "help");
+                       node_help = ec_dict_get(ec_node_attrs(node), "help");
                if (node_desc == NULL)
                        node_desc = ec_node_desc(node);
        }
diff --git a/src/ecoli_htable.c b/src/ecoli_htable.c
new file mode 100644 (file)
index 0000000..4b45a76
--- /dev/null
@@ -0,0 +1,448 @@
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/queue.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <ecoli_init.h>
+#include <ecoli_malloc.h>
+#include <ecoli_log.h>
+#include <ecoli_test.h>
+#include <ecoli_murmurhash.h>
+#include <ecoli_htable.h>
+
+#define FACTOR 3
+
+EC_LOG_TYPE_REGISTER(htable);
+
+static uint32_t ec_htable_seed;
+
+struct ec_htable_elt {
+       void *key;
+       size_t key_len;
+       void *val;
+       uint32_t hash;
+       ec_htable_elt_free_t free;
+       unsigned int refcount;
+};
+
+struct ec_htable_elt_ref {
+       TAILQ_ENTRY(ec_htable_elt_ref) next;
+       TAILQ_ENTRY(ec_htable_elt_ref) hnext;
+       struct ec_htable_elt *elt;
+};
+
+TAILQ_HEAD(ec_htable_elt_ref_list, ec_htable_elt_ref);
+
+struct ec_htable {
+       size_t len;
+       size_t table_size;
+       struct ec_htable_elt_ref_list list;
+       struct ec_htable_elt_ref_list *table;
+};
+
+struct ec_htable *ec_htable(void)
+{
+       struct ec_htable *htable;
+
+       htable = ec_calloc(1, sizeof(*htable));
+       if (htable == NULL)
+               return NULL;
+       TAILQ_INIT(&htable->list);
+
+       return htable;
+}
+
+static struct ec_htable_elt_ref *
+ec_htable_lookup(const struct ec_htable *htable, const void *key,
+               size_t key_len)
+{
+       struct ec_htable_elt_ref *ref;
+       uint32_t h, mask = htable->table_size - 1;
+
+       if (htable == NULL || key == NULL) {
+               errno = EINVAL;
+               return NULL;
+       }
+       if (htable->table_size == 0) {
+               errno = ENOENT;
+               return NULL;
+       }
+
+       h = ec_murmurhash3(key, key_len, ec_htable_seed);
+       TAILQ_FOREACH(ref, &htable->table[h & mask], hnext) {
+               if (ref->elt->key_len != key_len)
+                       continue;
+               if (memcmp(ref->elt->key, key, key_len) == 0)
+                       return ref;
+       }
+
+       errno = ENOENT;
+       return NULL;
+}
+
+static void ec_htable_elt_ref_free(struct ec_htable_elt_ref *ref)
+{
+       struct ec_htable_elt *elt;
+
+       if (ref == NULL)
+               return;
+
+       elt = ref->elt;
+       if (elt != NULL && --elt->refcount == 0) {
+               ec_free(elt->key);
+               if (elt->free != NULL)
+                       elt->free(elt->val);
+               ec_free(elt);
+       }
+       ec_free(ref);
+}
+
+bool ec_htable_has_key(const struct ec_htable *htable, const void *key,
+               size_t key_len)
+{
+       return !!ec_htable_lookup(htable, key, key_len);
+}
+
+void *ec_htable_get(const struct ec_htable *htable, const void *key,
+               size_t key_len)
+{
+       struct ec_htable_elt_ref *ref;
+
+       ref = ec_htable_lookup(htable, key, key_len);
+       if (ref == NULL)
+               return NULL;
+
+       return ref->elt->val;
+}
+
+int ec_htable_del(struct ec_htable *htable, const void *key, size_t key_len)
+{
+       struct ec_htable_elt_ref *ref;
+       size_t idx;
+
+       ref = ec_htable_lookup(htable, key, key_len);
+       if (ref == NULL)
+               return -1;
+
+       /* we could resize table here */
+
+       TAILQ_REMOVE(&htable->list, ref, next);
+       idx = ref->elt->hash & (htable->table_size - 1);
+       TAILQ_REMOVE(&htable->table[idx], ref, hnext);
+       ec_htable_elt_ref_free(ref);
+       htable->len--;
+
+       return 0;
+}
+
+static int ec_htable_table_resize(struct ec_htable *htable, size_t new_size)
+{
+       struct ec_htable_elt_ref_list *new_table;
+       struct ec_htable_elt_ref *ref;
+       size_t i;
+
+       if (new_size == 0 || (new_size & (new_size - 1))) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       new_table = ec_calloc(new_size, sizeof(*htable->table));
+       if (new_table == NULL)
+               return -1;
+       for (i = 0; i < new_size; i++)
+               TAILQ_INIT(&new_table[i]);
+
+       TAILQ_FOREACH(ref, &htable->list, next) {
+               i = ref->elt->hash & (htable->table_size - 1);
+               TAILQ_REMOVE(&htable->table[i], ref, hnext);
+               i = ref->elt->hash & (new_size - 1);
+               TAILQ_INSERT_TAIL(&new_table[i], ref, hnext);
+       }
+
+       ec_free(htable->table);
+       htable->table = new_table;
+       htable->table_size = new_size;
+
+       return 0;
+}
+
+static int
+__ec_htable_set(struct ec_htable *htable, struct ec_htable_elt_ref *ref)
+{
+       size_t new_size;
+       uint32_t mask;
+       int ret;
+
+       /* remove previous entry if any */
+       ec_htable_del(htable, ref->elt->key, ref->elt->key_len);
+
+       if (htable->len >= htable->table_size) {
+               if (htable->table_size != 0)
+                       new_size =  htable->table_size << FACTOR;
+               else
+                       new_size =  1 << FACTOR;
+               ret = ec_htable_table_resize(htable, new_size);
+               if (ret < 0)
+                       return ret;
+       }
+
+       mask = htable->table_size - 1;
+       TAILQ_INSERT_TAIL(&htable->table[ref->elt->hash & mask], ref, hnext);
+       TAILQ_INSERT_TAIL(&htable->list, ref, next);
+       htable->len++;
+
+       return 0;
+}
+
+int ec_htable_set(struct ec_htable *htable, const void *key, size_t key_len,
+               void *val, ec_htable_elt_free_t free_cb)
+{
+       struct ec_htable_elt *elt = NULL;
+       struct ec_htable_elt_ref *ref = NULL;
+       uint32_t h;
+
+       if (htable == NULL || key == NULL || key_len == 0) {
+               errno = EINVAL;
+               return -1;
+       }
+
+       ref = ec_calloc(1, sizeof(*ref));
+       if (ref == NULL)
+               goto fail;
+
+       elt = ec_calloc(1, sizeof(*elt));
+       if (elt == NULL)
+               goto fail;
+
+       ref->elt = elt;
+       elt->refcount = 1;
+       elt->val = val;
+       val = NULL;
+       elt->free = free_cb;
+       elt->key_len = key_len;
+       elt->key = ec_malloc(key_len);
+       if (elt->key == NULL)
+               goto fail;
+       memcpy(elt->key, key, key_len);
+       h = ec_murmurhash3(key, key_len, ec_htable_seed);
+       elt->hash = h;
+
+       if (__ec_htable_set(htable, ref) < 0)
+               goto fail;
+
+       return 0;
+
+fail:
+       if (free_cb != NULL && val != NULL)
+               free_cb(val);
+       ec_htable_elt_ref_free(ref);
+       return -1;
+}
+
+void ec_htable_free(struct ec_htable *htable)
+{
+       struct ec_htable_elt_ref *ref;
+       size_t idx;
+
+       if (htable == NULL)
+               return;
+
+       while (!TAILQ_EMPTY(&htable->list)) {
+               ref = TAILQ_FIRST(&htable->list);
+               TAILQ_REMOVE(&htable->list, ref, next);
+               idx = ref->elt->hash & (htable->table_size - 1);
+               TAILQ_REMOVE(&htable->table[idx], ref, hnext);
+               ec_htable_elt_ref_free(ref);
+       }
+       ec_free(htable->table);
+       ec_free(htable);
+}
+
+size_t ec_htable_len(const struct ec_htable *htable)
+{
+       return htable->len;
+}
+
+struct ec_htable_elt_ref *
+ec_htable_iter(const struct ec_htable *htable)
+{
+       if (htable == NULL)
+               return NULL;
+
+       return TAILQ_FIRST(&htable->list);
+}
+
+struct ec_htable_elt_ref *
+ec_htable_iter_next(struct ec_htable_elt_ref *iter)
+{
+       if (iter == NULL)
+               return NULL;
+
+       return TAILQ_NEXT(iter, next);
+}
+
+const char *
+ec_htable_iter_get_key(const struct ec_htable_elt_ref *iter)
+{
+       if (iter == NULL)
+               return NULL;
+
+       return iter->elt->key;
+}
+
+void *
+ec_htable_iter_get_val(const struct ec_htable_elt_ref *iter)
+{
+       if (iter == NULL)
+               return NULL;
+
+       return iter->elt->val;
+}
+
+void ec_htable_dump(FILE *out, const struct ec_htable *htable)
+{
+       if (htable == NULL) {
+               fprintf(out, "empty htable\n");
+               return;
+       }
+
+       fprintf(out, "htable: %zd elements\n", htable->len);
+}
+
+struct ec_htable *ec_htable_dup(const struct ec_htable *htable)
+{
+       struct ec_htable *dup = NULL;
+       struct ec_htable_elt_ref *ref, *dup_ref = NULL;
+
+       dup = ec_htable();
+       if (dup == NULL)
+               return NULL;
+
+       TAILQ_FOREACH(ref, &htable->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_htable_set(dup, dup_ref) < 0)
+                       goto fail;
+       }
+
+       return dup;
+
+fail:
+       ec_htable_elt_ref_free(dup_ref);
+       ec_htable_free(dup);
+       return NULL;
+}
+
+static int ec_htable_init_func(void)
+{
+       int fd;
+       ssize_t ret;
+
+       return 0;//XXX for test reproduceability
+
+       fd = open("/dev/urandom", 0);
+       if (fd == -1) {
+               fprintf(stderr, "failed to open /dev/urandom\n");
+               return -1;
+       }
+       ret = read(fd, &ec_htable_seed, sizeof(ec_htable_seed));
+       if (ret != sizeof(ec_htable_seed)) {
+               fprintf(stderr, "failed to read /dev/urandom\n");
+               return -1;
+       }
+       close(fd);
+       return 0;
+}
+
+static struct ec_init ec_htable_init = {
+       .init = ec_htable_init_func,
+       .priority = 50,
+};
+
+EC_INIT_REGISTER(ec_htable_init);
+
+/* LCOV_EXCL_START */
+static int ec_htable_testcase(void)
+{
+       struct ec_htable *htable;
+       struct ec_htable_elt_ref *iter;
+       size_t count;
+       int ret, testres = 0;
+       FILE *f = NULL;
+       char *buf = NULL;
+       size_t buflen = 0;
+
+       /* Minimal test, since ec_dict also uses this code and is better
+        * tested. */
+
+       htable = ec_htable();
+       if (htable == NULL) {
+               EC_LOG(EC_LOG_ERR, "cannot create htable\n");
+               return -1;
+       }
+
+       count = 0;
+       for (iter = ec_htable_iter(htable);
+            iter != NULL;
+            iter = ec_htable_iter_next(iter)) {
+               count++;
+       }
+       testres |= EC_TEST_CHECK(count == 0, "invalid count in iterator");
+
+       testres |= EC_TEST_CHECK(ec_htable_len(htable) == 0, "bad htable len");
+       ret = ec_htable_set(htable, "key1", 4, "val1", NULL);
+       testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
+       ret = ec_htable_set(htable, "key2", 4, ec_strdup("val2"), ec_free_func);
+       testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
+       testres |= EC_TEST_CHECK(ec_htable_len(htable) == 2, "bad htable len");
+
+       f = open_memstream(&buf, &buflen);
+       if (f == NULL)
+               goto fail;
+       ec_htable_dump(f, NULL);
+       fclose(f);
+       f = NULL;
+       free(buf);
+       buf = NULL;
+
+       f = open_memstream(&buf, &buflen);
+       if (f == NULL)
+               goto fail;
+       ec_htable_dump(f, htable);
+       fclose(f);
+       f = NULL;
+       free(buf);
+       buf = NULL;
+
+       ec_htable_free(htable);
+
+       return testres;
+
+fail:
+       ec_htable_free(htable);
+       if (f)
+               fclose(f);
+       free(buf);
+       return -1;
+}
+/* LCOV_EXCL_STOP */
+
+static struct ec_test ec_htable_test = {
+       .name = "htable",
+       .test = ec_htable_testcase,
+};
+
+EC_TEST_REGISTER(ec_htable_test);
diff --git a/src/ecoli_keyval.c b/src/ecoli_keyval.c
deleted file mode 100644 (file)
index a99aaf0..0000000
+++ /dev/null
@@ -1,517 +0,0 @@
-/* SPDX-License-Identifier: BSD-3-Clause
- * Copyright 2016, Olivier MATZ <zer0@droids-corp.org>
- */
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/queue.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <unistd.h>
-#include <assert.h>
-#include <errno.h>
-#include <fcntl.h>
-
-#include <ecoli_init.h>
-#include <ecoli_malloc.h>
-#include <ecoli_log.h>
-#include <ecoli_test.h>
-#include <ecoli_murmurhash.h>
-#include <ecoli_keyval.h>
-
-#define FACTOR 3
-
-EC_LOG_TYPE_REGISTER(keyval);
-
-static uint32_t ec_keyval_seed;
-
-struct ec_keyval_elt {
-       char *key;
-       void *val;
-       uint32_t hash;
-       ec_keyval_elt_free_t free;
-       unsigned int refcount;
-};
-
-struct ec_keyval_elt_ref {
-       TAILQ_ENTRY(ec_keyval_elt_ref) next;
-       TAILQ_ENTRY(ec_keyval_elt_ref) hnext;
-       struct ec_keyval_elt *elt;
-};
-
-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 *ec_keyval(void)
-{
-       struct ec_keyval *keyval;
-
-       keyval = ec_calloc(1, sizeof(*keyval));
-       if (keyval == NULL)
-               return NULL;
-       TAILQ_INIT(&keyval->list);
-
-       return keyval;
-}
-
-static struct ec_keyval_elt_ref *
-ec_keyval_lookup(const struct ec_keyval *keyval, const char *key)
-{
-       struct ec_keyval_elt_ref *ref;
-       uint32_t h, mask = keyval->table_size - 1;
-
-       if (keyval == NULL || key == NULL) {
-               errno = EINVAL;
-               return NULL;
-       }
-       if (keyval->table_size == 0) {
-               errno = ENOENT;
-               return NULL;
-       }
-
-       h = ec_murmurhash3(key, strlen(key), ec_keyval_seed);
-       TAILQ_FOREACH(ref, &keyval->table[h & mask], hnext) {
-               if (strcmp(ref->elt->key, key) == 0)
-                       return ref;
-       }
-
-       errno = ENOENT;
-       return NULL;
-}
-
-static void ec_keyval_elt_ref_free(struct ec_keyval_elt_ref *ref)
-{
-       struct ec_keyval_elt *elt;
-
-       if (ref == NULL)
-               return;
-
-       elt = ref->elt;
-       if (elt != NULL && --elt->refcount == 0) {
-               ec_free(elt->key);
-               if (elt->free != NULL)
-                       elt->free(elt->val);
-               ec_free(elt);
-       }
-       ec_free(ref);
-}
-
-bool ec_keyval_has_key(const struct ec_keyval *keyval, const char *key)
-{
-       return !!ec_keyval_lookup(keyval, key);
-}
-
-void *ec_keyval_get(const struct ec_keyval *keyval, const char *key)
-{
-       struct ec_keyval_elt_ref *ref;
-
-       ref = ec_keyval_lookup(keyval, key);
-       if (ref == NULL)
-               return NULL;
-
-       return ref->elt->val;
-}
-
-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)
-               return -1;
-
-       /* we could resize table here */
-
-       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--;
-
-       return 0;
-}
-
-static int ec_keyval_table_resize(struct ec_keyval *keyval, size_t new_size)
-{
-       struct ec_keyval_elt_ref_list *new_table;
-       struct ec_keyval_elt_ref *ref;
-       size_t i;
-
-       if (new_size == 0 || (new_size & (new_size - 1))) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       new_table = ec_calloc(new_size, sizeof(*keyval->table));
-       if (new_table == NULL)
-               return -1;
-       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);
-       keyval->table = new_table;
-       keyval->table_size = new_size;
-
-       return 0;
-}
-
-static int
-__ec_keyval_set(struct ec_keyval *keyval, struct ec_keyval_elt_ref *ref)
-{
-       size_t new_size;
-       uint32_t mask;
-       int ret;
-
-       /* remove previous entry if any */
-       ec_keyval_del(keyval, ref->elt->key);
-
-       if (keyval->len >= keyval->table_size) {
-               if (keyval->table_size != 0)
-                       new_size =  keyval->table_size << FACTOR;
-               else
-                       new_size =  1 << FACTOR;
-               ret = ec_keyval_table_resize(keyval, new_size);
-               if (ret < 0)
-                       return ret;
-       }
-
-       mask = keyval->table_size - 1;
-       TAILQ_INSERT_TAIL(&keyval->table[ref->elt->hash & mask], ref, hnext);
-       TAILQ_INSERT_TAIL(&keyval->list, ref, next);
-       keyval->len++;
-
-       return 0;
-}
-
-int ec_keyval_set(struct ec_keyval *keyval, const char *key, void *val,
-       ec_keyval_elt_free_t free_cb)
-{
-       struct ec_keyval_elt *elt = NULL;
-       struct ec_keyval_elt_ref *ref = NULL;
-       uint32_t h;
-
-       if (keyval == NULL || key == NULL) {
-               errno = EINVAL;
-               return -1;
-       }
-
-       ref = ec_calloc(1, sizeof(*ref));
-       if (ref == NULL)
-               goto fail;
-
-       elt = ec_calloc(1, sizeof(*elt));
-       if (elt == NULL)
-               goto fail;
-
-       ref->elt = elt;
-       elt->refcount = 1;
-       elt->val = val;
-       val = NULL;
-       elt->free = free_cb;
-       elt->key = ec_strdup(key);
-       if (elt->key == NULL)
-               goto fail;
-       h = ec_murmurhash3(key, strlen(key), ec_keyval_seed);
-       elt->hash = h;
-
-       if (__ec_keyval_set(keyval, ref) < 0)
-               goto fail;
-
-       return 0;
-
-fail:
-       if (free_cb != NULL && val != NULL)
-               free_cb(val);
-       ec_keyval_elt_ref_free(ref);
-       return -1;
-}
-
-void ec_keyval_free(struct ec_keyval *keyval)
-{
-       struct ec_keyval_elt_ref *ref;
-       size_t idx;
-
-       if (keyval == NULL)
-               return;
-
-       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);
-}
-
-size_t ec_keyval_len(const struct ec_keyval *keyval)
-{
-       return keyval->len;
-}
-
-struct ec_keyval_elt_ref *
-ec_keyval_iter(const struct ec_keyval *keyval)
-{
-       if (keyval == NULL)
-               return NULL;
-
-       return TAILQ_FIRST(&keyval->list);
-}
-
-struct ec_keyval_elt_ref *
-ec_keyval_iter_next(struct ec_keyval_elt_ref *iter)
-{
-       if (iter == NULL)
-               return NULL;
-
-       return TAILQ_NEXT(iter, next);
-}
-
-const char *
-ec_keyval_iter_get_key(const struct ec_keyval_elt_ref *iter)
-{
-       if (iter == NULL)
-               return NULL;
-
-       return iter->elt->key;
-}
-
-void *
-ec_keyval_iter_get_val(const struct ec_keyval_elt_ref *iter)
-{
-       if (iter == NULL)
-               return NULL;
-
-       return iter->elt->val;
-}
-
-void ec_keyval_dump(FILE *out, const struct ec_keyval *keyval)
-{
-       struct ec_keyval_elt_ref *iter;
-
-       if (keyval == NULL) {
-               fprintf(out, "empty keyval\n");
-               return;
-       }
-
-       fprintf(out, "keyval:\n");
-       for (iter = ec_keyval_iter(keyval);
-            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));
-       }
-}
-
-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;
-
-       dup = ec_keyval();
-       if (dup == NULL)
-               return NULL;
-
-       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;
-       }
-
-       return dup;
-
-fail:
-       ec_keyval_elt_ref_free(dup_ref);
-       ec_keyval_free(dup);
-       return NULL;
-}
-
-static int ec_keyval_init_func(void)
-{
-       int fd;
-       ssize_t ret;
-
-       return 0;//XXX for test reproduceability
-
-       fd = open("/dev/urandom", 0);
-       if (fd == -1) {
-               fprintf(stderr, "failed to open /dev/urandom\n");
-               return -1;
-       }
-       ret = read(fd, &ec_keyval_seed, sizeof(ec_keyval_seed));
-       if (ret != sizeof(ec_keyval_seed)) {
-               fprintf(stderr, "failed to read /dev/urandom\n");
-               return -1;
-       }
-       close(fd);
-       return 0;
-}
-
-static struct ec_init ec_keyval_init = {
-       .init = ec_keyval_init_func,
-       .priority = 50,
-};
-
-EC_INIT_REGISTER(ec_keyval_init);
-
-/* LCOV_EXCL_START */
-static int ec_keyval_testcase(void)
-{
-       struct ec_keyval *keyval, *dup;
-       struct ec_keyval_elt_ref *iter;
-       char *val;
-       size_t i, count;
-       int ret, testres = 0;
-       FILE *f = NULL;
-       char *buf = NULL;
-       size_t buflen = 0;
-
-       keyval = ec_keyval();
-       if (keyval == NULL) {
-               EC_LOG(EC_LOG_ERR, "cannot create keyval\n");
-               return -1;
-       }
-
-       count = 0;
-       for (iter = ec_keyval_iter(keyval);
-            iter != NULL;
-            iter = ec_keyval_iter_next(iter)) {
-               count++;
-       }
-       testres |= EC_TEST_CHECK(count == 0, "invalid count in iterator");
-
-       testres |= EC_TEST_CHECK(ec_keyval_len(keyval) == 0, "bad keyval len");
-       ret = ec_keyval_set(keyval, "key1", "val1", NULL);
-       testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
-       ret = ec_keyval_set(keyval, "key2", ec_strdup("val2"), ec_free_func);
-       testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
-       testres |= EC_TEST_CHECK(ec_keyval_len(keyval) == 2, "bad keyval len");
-
-       val = ec_keyval_get(keyval, "key1");
-       testres |= EC_TEST_CHECK(val != NULL && !strcmp(val, "val1"),
-                               "invalid keyval value");
-       val = ec_keyval_get(keyval, "key2");
-       testres |= EC_TEST_CHECK(val != NULL && !strcmp(val, "val2"),
-                               "invalid keyval value");
-       val = ec_keyval_get(keyval, "key3");
-       testres |= EC_TEST_CHECK(val == NULL, "key3 should be NULL");
-
-       ret = ec_keyval_set(keyval, "key1", "another_val1", NULL);
-       testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
-       ret = ec_keyval_set(keyval, "key2", ec_strdup("another_val2"),
-                       ec_free_func);
-       testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
-       testres |= EC_TEST_CHECK(ec_keyval_len(keyval) == 2,
-                               "bad keyval len");
-
-       val = ec_keyval_get(keyval, "key1");
-       testres |= EC_TEST_CHECK(val != NULL && !strcmp(val, "another_val1"),
-               "invalid keyval value");
-       val = ec_keyval_get(keyval, "key2");
-       testres |= EC_TEST_CHECK(val != NULL && !strcmp(val, "another_val2"),
-               "invalid keyval value");
-       testres |= EC_TEST_CHECK(ec_keyval_has_key(keyval, "key1"),
-               "key1 should be in keyval");
-
-       f = open_memstream(&buf, &buflen);
-       if (f == NULL)
-               goto fail;
-       ec_keyval_dump(f, NULL);
-       fclose(f);
-       f = NULL;
-       free(buf);
-       buf = NULL;
-
-       f = open_memstream(&buf, &buflen);
-       if (f == NULL)
-               goto fail;
-       ec_keyval_dump(f, keyval);
-       fclose(f);
-       f = NULL;
-       free(buf);
-       buf = NULL;
-
-       ret = ec_keyval_del(keyval, "key1");
-       testres |= EC_TEST_CHECK(ret == 0, "cannot del key1");
-       testres |= EC_TEST_CHECK(ec_keyval_len(keyval) == 1,
-               "invalid keyval len");
-       ret = ec_keyval_del(keyval, "key2");
-       testres |= EC_TEST_CHECK(ret == 0, "cannot del key2");
-       testres |= EC_TEST_CHECK(ec_keyval_len(keyval) == 0,
-               "invalid keyval len");
-
-       for (i = 0; i < 100; i++) {
-               char key[8];
-               snprintf(key, sizeof(key), "k%zd", i);
-               ret = ec_keyval_set(keyval, key, "val", NULL);
-               testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
-       }
-       dup = ec_keyval_dup(keyval);
-       testres |= EC_TEST_CHECK(dup != NULL, "cannot duplicate keyval");
-       if (dup != NULL) {
-               for (i = 0; i < 100; i++) {
-                       char key[8];
-                       snprintf(key, sizeof(key), "k%zd", i);
-                       val = ec_keyval_get(dup, key);
-                       testres |= EC_TEST_CHECK(
-                               val != NULL && !strcmp(val, "val"),
-                               "invalid keyval value");
-               }
-               ec_keyval_free(dup);
-               dup = NULL;
-       }
-
-       count = 0;
-       for (iter = ec_keyval_iter(keyval);
-            iter != NULL;
-            iter = ec_keyval_iter_next(iter)) {
-               count++;
-       }
-       testres |= EC_TEST_CHECK(count == 100, "invalid count in iterator");
-
-       /* einval */
-       ret = ec_keyval_set(keyval, NULL, "val1", NULL);
-       testres |= EC_TEST_CHECK(ret == -1, "should not be able to set key");
-       val = ec_keyval_get(keyval, NULL);
-       testres |= EC_TEST_CHECK(val == NULL, "get(NULL) should no success");
-
-       ec_keyval_free(keyval);
-
-       return testres;
-
-fail:
-       ec_keyval_free(keyval);
-       if (f)
-               fclose(f);
-       free(buf);
-       return -1;
-}
-/* LCOV_EXCL_STOP */
-
-static struct ec_test ec_keyval_test = {
-       .name = "keyval",
-       .test = ec_keyval_testcase,
-};
-
-EC_TEST_REGISTER(ec_keyval_test);
index 9789102..07ef9e5 100644 (file)
@@ -12,7 +12,7 @@
 #include <ecoli_malloc.h>
 #include <ecoli_string.h>
 #include <ecoli_strvec.h>
-#include <ecoli_keyval.h>
+#include <ecoli_dict.h>
 #include <ecoli_log.h>
 #include <ecoli_config.h>
 #include <ecoli_test.h>
@@ -90,7 +90,7 @@ struct ec_node *ec_node_from_type(const struct ec_node_type *type, const char *i
        if (ec_asprintf(&node->desc, "<%s>", type->name) < 0)
                goto fail;
 
-       node->attrs = ec_keyval();
+       node->attrs = ec_dict();
        if (node->attrs == NULL)
                goto fail;
 
@@ -103,7 +103,7 @@ struct ec_node *ec_node_from_type(const struct ec_node_type *type, const char *i
 
  fail:
        if (node != NULL) {
-               ec_keyval_free(node->attrs);
+               ec_dict_free(node->attrs);
                ec_free(node->desc);
                ec_free(node->id);
        }
@@ -245,7 +245,7 @@ void ec_node_free(struct ec_node *node)
                        node->type->free_priv(node);
                ec_free(node->id);
                ec_free(node->desc);
-               ec_keyval_free(node->attrs);
+               ec_dict_free(node->attrs);
        }
 
        node->refcnt--;
@@ -340,7 +340,7 @@ const struct ec_node_type *ec_node_type(const struct ec_node *node)
        return node->type;
 }
 
-struct ec_keyval *ec_node_attrs(const struct ec_node *node)
+struct ec_dict *ec_node_attrs(const struct ec_node *node)
 {
        return node->attrs;
 }
@@ -351,7 +351,7 @@ const char *ec_node_id(const struct ec_node *node)
 }
 
 static void __ec_node_dump(FILE *out,
-       const struct ec_node *node, size_t indent, struct ec_keyval *dict)
+       const struct ec_node *node, size_t indent, struct ec_dict *dict)
 {
        const char *id, *typename;
        struct ec_node *child;
@@ -364,13 +364,13 @@ static void __ec_node_dump(FILE *out,
        typename = node->type->name;
 
        snprintf(buf, sizeof(buf), "%p", node);
-       if (ec_keyval_has_key(dict, buf)) {
+       if (ec_dict_has_key(dict, buf)) {
                fprintf(out, "%*s" "type=%s id=%s %p... (loop)\n",
                        (int)indent * 4, "", typename, id, node);
                return;
        }
 
-       ec_keyval_set(dict, buf, NULL, NULL);
+       ec_dict_set(dict, buf, NULL, NULL);
        fprintf(out, "%*s" "type=%s id=%s %p refs=%u free_state=%d free_refs=%d\n",
                (int)indent * 4, "", typename, id, node, node->refcnt,
                node->free.state, node->free.refcnt);
@@ -386,7 +386,7 @@ static void __ec_node_dump(FILE *out,
 /* XXX this is too much debug-oriented, we should have a parameter or 2 funcs */
 void ec_node_dump(FILE *out, const struct ec_node *node)
 {
-       struct ec_keyval *dict = NULL;
+       struct ec_dict *dict = NULL;
 
        fprintf(out, "------------------- node dump:\n");
 
@@ -395,17 +395,17 @@ void ec_node_dump(FILE *out, const struct ec_node *node)
                return;
        }
 
-       dict = ec_keyval();
+       dict = ec_dict();
        if (dict == NULL)
                goto fail;
 
        __ec_node_dump(out, node, 0, dict);
 
-       ec_keyval_free(dict);
+       ec_dict_free(dict);
        return;
 
 fail:
-       ec_keyval_free(dict);
+       ec_dict_free(dict);
        EC_LOG(EC_LOG_ERR, "failed to dump node\n");
 }
 
@@ -507,7 +507,7 @@ static int ec_node_testcase(void)
        testres |= EC_TEST_CHECK(child == NULL,
                "child with wrong id should be NULL");
 
-       ret = ec_keyval_set(ec_node_attrs(node), "key", "val", NULL);
+       ret = ec_dict_set(ec_node_attrs(node), "key", "val", NULL);
        testres |= EC_TEST_CHECK(ret == 0,
                "cannot set node attribute\n");
 
index fbcc460..88ac542 100644 (file)
@@ -14,7 +14,7 @@
 #include <ecoli_node.h>
 #include <ecoli_parse.h>
 #include <ecoli_complete.h>
-#include <ecoli_keyval.h>
+#include <ecoli_dict.h>
 #include <ecoli_config.h>
 #include <ecoli_node_any.h>
 
@@ -30,7 +30,7 @@ static int ec_node_any_parse(const struct ec_node *gen_node,
                        const struct ec_strvec *strvec)
 {
        struct ec_node_any *node = (struct ec_node_any *)gen_node;
-       const struct ec_keyval *attrs;
+       const struct ec_dict *attrs;
 
        (void)state;
 
@@ -38,7 +38,7 @@ static int ec_node_any_parse(const struct ec_node *gen_node,
                return EC_PARSE_NOMATCH;
        if (node->attr_name != NULL) {
                attrs = ec_strvec_get_attrs(strvec, 0);
-               if (attrs == NULL || !ec_keyval_has_key(attrs, node->attr_name))
+               if (attrs == NULL || !ec_dict_has_key(attrs, node->attr_name))
                        return EC_PARSE_NOMATCH;
        }
 
index 7c73b65..a7130aa 100644 (file)
@@ -11,7 +11,7 @@
 #include <ecoli_malloc.h>
 #include <ecoli_test.h>
 #include <ecoli_strvec.h>
-#include <ecoli_keyval.h>
+#include <ecoli_dict.h>
 #include <ecoli_node.h>
 #include <ecoli_parse.h>
 #include <ecoli_complete.h>
@@ -47,7 +47,7 @@ ec_node_dynamic_parse(const struct ec_node *gen_node,
        /* add the node pointer in the attributes, so it will be freed
         * when parse is freed */
        snprintf(key, sizeof(key), "_dyn_%p", child);
-       ret = ec_keyval_set(ec_parse_get_attrs(parse), key, child,
+       ret = ec_dict_set(ec_parse_get_attrs(parse), key, child,
                        (void *)node_free);
        if (ret < 0) {
                child = NULL; /* already freed */
@@ -81,7 +81,7 @@ ec_node_dynamic_complete(const struct ec_node *gen_node,
        /* add the node pointer in the attributes, so it will be freed
         * when parse is freed */
        snprintf(key, sizeof(key), "_dyn_%p", child);
-       ret = ec_keyval_set(comp->attrs, key, child,
+       ret = ec_dict_set(comp->attrs, key, child,
                        (void *)node_free);
        if (ret < 0) {
                child = NULL; /* already freed */
index e7751ac..a007aba 100644 (file)
@@ -13,7 +13,7 @@
 #include <ecoli_log.h>
 #include <ecoli_test.h>
 #include <ecoli_strvec.h>
-#include <ecoli_keyval.h>
+#include <ecoli_dict.h>
 #include <ecoli_node.h>
 #include <ecoli_complete.h>
 #include <ecoli_parse.h>
@@ -44,7 +44,7 @@ static struct ec_strvec *
 tokenize(struct regexp_pattern *table, size_t table_len, const char *str)
 {
        struct ec_strvec *strvec = NULL;
-       struct ec_keyval *attrs = NULL;
+       struct ec_dict *attrs = NULL;
        char *dup = NULL;
        char c;
        size_t len, off = 0;
@@ -81,10 +81,10 @@ tokenize(struct regexp_pattern *table, size_t table_len, const char *str)
                                goto fail;
 
                        if (table[i].attr_name != NULL) {
-                               attrs = ec_keyval();
+                               attrs = ec_dict();
                                if (attrs == NULL)
                                        goto fail;
-                               if (ec_keyval_set(attrs, table[i].attr_name,
+                               if (ec_dict_set(attrs, table[i].attr_name,
                                                NULL, NULL) < 0)
                                        goto fail;
                                if (ec_strvec_set_attrs(strvec,
index f224fda..e01ff0a 100644 (file)
@@ -12,7 +12,7 @@
 #include <ecoli_assert.h>
 #include <ecoli_malloc.h>
 #include <ecoli_strvec.h>
-#include <ecoli_keyval.h>
+#include <ecoli_dict.h>
 #include <ecoli_log.h>
 #include <ecoli_test.h>
 #include <ecoli_node.h>
@@ -31,7 +31,7 @@ struct ec_parse {
        struct ec_parse *parent;
        const struct ec_node *node;
        struct ec_strvec *strvec;
-       struct ec_keyval *attrs;
+       struct ec_dict *attrs;
 };
 
 static int __ec_node_parse_child(const struct ec_node *node,
@@ -149,7 +149,7 @@ struct ec_parse *ec_parse(const struct ec_node *node)
        TAILQ_INIT(&parse->children);
 
        parse->node = node;
-       parse->attrs = ec_keyval();
+       parse->attrs = ec_dict();
        if (parse->attrs == NULL)
                goto fail;
 
@@ -157,7 +157,7 @@ struct ec_parse *ec_parse(const struct ec_node *node)
 
  fail:
        if (parse != NULL)
-               ec_keyval_free(parse->attrs);
+               ec_dict_free(parse->attrs);
        ec_free(parse);
 
        return NULL;
@@ -169,7 +169,7 @@ __ec_parse_dup(const struct ec_parse *root, const struct ec_parse *ref,
 {
        struct ec_parse *dup = NULL;
        struct ec_parse *child, *dup_child;
-       struct ec_keyval *attrs = NULL;
+       struct ec_dict *attrs = NULL;
 
        if (root == NULL)
                return NULL;
@@ -181,10 +181,10 @@ __ec_parse_dup(const struct ec_parse *root, const struct ec_parse *ref,
        if (root == ref)
                *new_ref = dup;
 
-       attrs = ec_keyval_dup(root->attrs);
+       attrs = ec_dict_dup(root->attrs);
        if (attrs == NULL)
                goto fail;
-       ec_keyval_free(dup->attrs);
+       ec_dict_free(dup->attrs);
        dup->attrs = attrs;
 
        if (root->strvec != NULL) {
@@ -246,7 +246,7 @@ void ec_parse_free(struct ec_parse *parse)
 
        ec_parse_free_children(parse);
        ec_strvec_free(parse->strvec);
-       ec_keyval_free(parse->attrs);
+       ec_dict_free(parse->attrs);
        ec_free(parse);
 }
 
@@ -416,7 +416,7 @@ struct ec_parse *ec_parse_find(struct ec_parse *parse,
        return ec_parse_find_next(parse, NULL, id, 1);
 }
 
-struct ec_keyval *
+struct ec_dict *
 ec_parse_get_attrs(struct ec_parse *parse)
 {
        if (parse == NULL)
@@ -497,7 +497,7 @@ static int ec_parse_testcase(void)
        testres |= EC_TEST_CHECK(
                ec_parse_len(p) == 1, "bad parse len\n");
 
-       ret = ec_keyval_set(ec_parse_get_attrs(p), "key", "val", NULL);
+       ret = ec_dict_set(ec_parse_get_attrs(p), "key", "val", NULL);
        testres |= EC_TEST_CHECK(ret == 0,
                "cannot set parse attribute\n");
 
index 98a952f..bf2eca7 100644 (file)
@@ -11,7 +11,7 @@
 #include <ecoli_malloc.h>
 #include <ecoli_test.h>
 #include <ecoli_log.h>
-#include <ecoli_keyval.h>
+#include <ecoli_dict.h>
 #include <ecoli_strvec.h>
 
 EC_LOG_TYPE_REGISTER(strvec);
@@ -19,7 +19,7 @@ EC_LOG_TYPE_REGISTER(strvec);
 struct ec_strvec_elt {
        unsigned int refcnt;
        char *str;
-       struct ec_keyval *attrs;
+       struct ec_dict *attrs;
 };
 
 struct ec_strvec {
@@ -63,7 +63,7 @@ __ec_strvec_elt_free(struct ec_strvec_elt *elt)
        elt->refcnt--;
        if (elt->refcnt == 0) {
                ec_free(elt->str);
-               ec_keyval_free(elt->attrs);
+               ec_dict_free(elt->attrs);
                ec_free(elt);
        }
 }
@@ -217,7 +217,7 @@ const char *ec_strvec_val(const struct ec_strvec *strvec, size_t idx)
        return strvec->vec[idx]->str;
 }
 
-const struct ec_keyval *ec_strvec_get_attrs(const struct ec_strvec *strvec,
+const struct ec_dict *ec_strvec_get_attrs(const struct ec_strvec *strvec,
        size_t idx)
 {
        if (strvec == NULL || idx >= strvec->len) {
@@ -229,7 +229,7 @@ const struct ec_keyval *ec_strvec_get_attrs(const struct ec_strvec *strvec,
 }
 
 int ec_strvec_set_attrs(struct ec_strvec *strvec, size_t idx,
-                       struct ec_keyval *attrs)
+                       struct ec_dict *attrs)
 {
        struct ec_strvec_elt *elt;
 
@@ -246,14 +246,14 @@ int ec_strvec_set_attrs(struct ec_strvec *strvec, size_t idx,
        }
 
        if (elt->attrs != NULL)
-               ec_keyval_free(elt->attrs);
+               ec_dict_free(elt->attrs);
 
        elt->attrs = attrs;
 
        return 0;
 
 fail:
-       ec_keyval_free(attrs);
+       ec_dict_free(attrs);
        return -1;
 }
 
@@ -317,8 +317,8 @@ static int ec_strvec_testcase(void)
 {
        struct ec_strvec *strvec = NULL;
        struct ec_strvec *strvec2 = NULL;
-       const struct ec_keyval *const_attrs = NULL;
-       struct ec_keyval *attrs = NULL;
+       const struct ec_dict *const_attrs = NULL;
+       struct ec_dict *attrs = NULL;
        FILE *f = NULL;
        char *buf = NULL;
        size_t buflen = 0;
@@ -475,12 +475,12 @@ static int ec_strvec_testcase(void)
                EC_TEST_ERR("cannot create strvec from array\n");
                goto fail;
        }
-       attrs = ec_keyval();
+       attrs = ec_dict();
        if (attrs == NULL) {
                EC_TEST_ERR("cannot create attrs\n");
                goto fail;
        }
-       if (ec_keyval_set(attrs, "key", "value", NULL) < 0) {
+       if (ec_dict_set(attrs, "key", "value", NULL) < 0) {
                EC_TEST_ERR("cannot set attr\n");
                goto fail;
        }
@@ -500,7 +500,7 @@ static int ec_strvec_testcase(void)
                goto fail;
        }
        testres |= EC_TEST_CHECK(
-               ec_keyval_has_key(const_attrs, "key"), "cannot get attrs key\n");
+               ec_dict_has_key(const_attrs, "key"), "cannot get attrs key\n");
 
        strvec2 = EC_STRVEC("a", "b", "c", "d", "e", "f");
        if (strvec2 == NULL) {
@@ -519,7 +519,7 @@ static int ec_strvec_testcase(void)
 fail:
        if (f != NULL)
                fclose(f);
-       ec_keyval_free(attrs);
+       ec_dict_free(attrs);
        ec_strvec_free(strvec);
        ec_strvec_free(strvec2);
        free(buf);
index 326af56..4843ef0 100644 (file)
@@ -13,7 +13,7 @@
 #include <yaml.h>
 
 #include <ecoli_malloc.h>
-#include <ecoli_keyval.h>
+#include <ecoli_dict.h>
 #include <ecoli_node.h>
 #include <ecoli_config.h>
 #include <ecoli_yaml.h>
@@ -466,7 +466,7 @@ parse_ec_node(struct enode_table *table,
        config = NULL; /* freed */
 
        if (help != NULL) {
-               if (ec_keyval_set(ec_node_attrs(enode), "help", help,
+               if (ec_dict_set(ec_node_attrs(enode), "help", help,
                                        ec_free_func) < 0) {
                        fprintf(stderr, "Failed to set help\n");
                        help = NULL;
@@ -486,7 +486,7 @@ parse_ec_node(struct enode_table *table,
                        value_dup = ec_strdup(value_str);
                        if (value_dup == NULL)
                                goto fail;
-                       if (ec_keyval_set(ec_node_attrs(enode), key_str,
+                       if (ec_dict_set(ec_node_attrs(enode), key_str,
                                                value_dup, ec_free_func) < 0) {
                                value_dup = NULL;
                                goto fail;
index db350eb..cfd1d04 100644 (file)
@@ -7,8 +7,9 @@ libecoli_sources = [
        'ecoli_assert.c',
        'ecoli_complete.c',
        'ecoli_config.c',
+       'ecoli_dict.c',
        'ecoli_init.c',
-       'ecoli_keyval.c',
+       'ecoli_htable.c',
        'ecoli_log.c',
        'ecoli_malloc.c',
        'ecoli_murmurhash.c',