#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>
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);
}
);
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;
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;
"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;
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;
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;
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;
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);
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;
};
/*
#endif
struct ec_config;
-struct ec_keyval;
+struct ec_dict;
/**
* The type identifier for a config value.
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 */
};
--- /dev/null
+/* 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
--- /dev/null
+/* 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
+++ /dev/null
-/* 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
struct ec_parse;
struct ec_comp;
struct ec_strvec;
-struct ec_keyval;
+struct ec_dict;
struct ec_config;
struct ec_config_schema;
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 */
/* 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);
*
*
*/
-struct ec_keyval *ec_parse_get_attrs(struct ec_parse *parse);
+struct ec_dict *ec_parse_get_attrs(struct ec_parse *parse);
/**
*
* 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);
/**
* 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
'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',
#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>
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)
if (comp == NULL)
goto fail;
- comp->attrs = ec_keyval();
+ comp->attrs = ec_dict();
if (comp->attrs == NULL)
goto fail;
fail:
if (comp != NULL)
- ec_keyval_free(comp->attrs);
+ ec_dict_free(comp->attrs);
ec_free(comp);
return NULL;
if (grp == NULL)
return NULL;
- grp->attrs = ec_keyval();
+ grp->attrs = ec_dict();
if (grp->attrs == NULL)
goto fail;
fail:
if (grp != NULL) {
ec_parse_free(grp->state);
- ec_keyval_free(grp->attrs);
+ ec_dict_free(grp->attrs);
}
ec_free(grp);
return NULL;
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;
if (item == NULL)
goto fail;
- attrs = ec_keyval();
+ attrs = ec_dict();
if (attrs == NULL)
goto fail;
return item;
fail:
- ec_keyval_free(attrs);
+ ec_dict_free(attrs);
ec_free(comp_cp);
ec_free(start_cp);
ec_free(full_cp);
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);
}
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);
}
TAILQ_REMOVE(&comp->groups, grp, next);
ec_comp_group_free(grp);
}
- ec_keyval_free(comp->attrs);
+ ec_dict_free(comp->attrs);
ec_free(comp);
}
#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>
__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
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;
return value;
fail:
- ec_keyval_free(dict);
+ ec_dict_free(dict);
ec_free(value);
return NULL;
}
}
break;
case EC_CONFIG_TYPE_DICT:
- ec_keyval_free(value->dict);
+ ec_dict_free(value->dict);
break;
default:
break;
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;
}
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;
return NULL;
}
- return ec_keyval_get(config->dict, key);
+ return ec_dict_get(config->dict, key);
}
struct ec_config *
goto fail;
}
- return ec_keyval_set(config->dict, key, value,
+ return ec_dict_set(config->dict, key, value,
(void (*)(void *))free_cb);
fail:
return -1;
}
- return ec_keyval_del(config->dict, key);
+ return ec_dict_del(config->dict, key);
}
/* value is consumed */
}
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)
}
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, "",
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;
}
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;
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;
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;
--- /dev/null
+/* 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);
#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>
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);
}
--- /dev/null
+/* 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);
+++ /dev/null
-/* 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);
#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>
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;
fail:
if (node != NULL) {
- ec_keyval_free(node->attrs);
+ ec_dict_free(node->attrs);
ec_free(node->desc);
ec_free(node->id);
}
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--;
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;
}
}
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;
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);
/* 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");
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");
}
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");
#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>
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;
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;
}
#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>
/* 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 */
/* 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 */
#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>
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;
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,
#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>
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,
TAILQ_INIT(&parse->children);
parse->node = node;
- parse->attrs = ec_keyval();
+ parse->attrs = ec_dict();
if (parse->attrs == NULL)
goto fail;
fail:
if (parse != NULL)
- ec_keyval_free(parse->attrs);
+ ec_dict_free(parse->attrs);
ec_free(parse);
return NULL;
{
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;
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) {
ec_parse_free_children(parse);
ec_strvec_free(parse->strvec);
- ec_keyval_free(parse->attrs);
+ ec_dict_free(parse->attrs);
ec_free(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)
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");
#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);
struct ec_strvec_elt {
unsigned int refcnt;
char *str;
- struct ec_keyval *attrs;
+ struct ec_dict *attrs;
};
struct ec_strvec {
elt->refcnt--;
if (elt->refcnt == 0) {
ec_free(elt->str);
- ec_keyval_free(elt->attrs);
+ ec_dict_free(elt->attrs);
ec_free(elt);
}
}
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) {
}
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;
}
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;
}
{
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;
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;
}
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) {
fail:
if (f != NULL)
fclose(f);
- ec_keyval_free(attrs);
+ ec_dict_free(attrs);
ec_strvec_free(strvec);
ec_strvec_free(strvec2);
free(buf);
#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>
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;
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;
'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',