struct ec_keyval_elt_ref_list *table;
};
+struct ec_keyval_iter {
+ const struct ec_keyval *keyval;
+ size_t cur_idx;
+ const struct ec_keyval_elt_ref *cur_ref;
+};
+
struct ec_keyval *ec_keyval(void)
{
struct ec_keyval *keyval;
return keyval->len;
}
-void ec_keyval_dump(FILE *out, const struct ec_keyval *keyval)
+void
+ec_keyval_iter_free(struct ec_keyval_iter *iter)
{
- struct ec_keyval_elt_ref *ref;
+ ec_free(iter);
+}
+
+struct ec_keyval_iter *
+ec_keyval_iter(const struct ec_keyval *keyval)
+{
+ struct ec_keyval_iter *iter = NULL;
+
+ iter = ec_calloc(1, sizeof(*iter));
+ if (iter == NULL)
+ return NULL;
+
+ iter->keyval = keyval;
+ iter->cur_idx = 0;
+ iter->cur_ref = NULL;
+
+ ec_keyval_iter_next(iter);
+
+ return iter;
+}
+
+void
+ec_keyval_iter_next(struct ec_keyval_iter *iter)
+{
+ const struct ec_keyval_elt_ref *ref;
size_t i;
+ i = iter->cur_idx;
+ if (i == iter->keyval->table_size)
+ return; /* no more element */
+
+ if (iter->cur_ref != NULL) {
+ ref = LIST_NEXT(iter->cur_ref, next);
+ if (ref != NULL) {
+ iter->cur_ref = ref;
+ return;
+ }
+ i++;
+ }
+
+ for (; i < iter->keyval->table_size; i++) {
+ LIST_FOREACH(ref, &iter->keyval->table[i], next) {
+ iter->cur_idx = i;
+ iter->cur_ref = LIST_FIRST(&iter->keyval->table[i]);
+ return;
+ }
+ }
+
+ iter->cur_idx = iter->keyval->table_size;
+ iter->cur_ref = NULL;
+}
+
+bool
+ec_keyval_iter_valid(const struct ec_keyval_iter *iter)
+{
+ if (iter == NULL || iter->cur_ref == NULL)
+ return false;
+
+ return true;
+}
+
+const char *
+ec_keyval_iter_get_key(const struct ec_keyval_iter *iter)
+{
+ if (iter == NULL || iter->cur_ref == NULL)
+ return NULL;
+
+ return iter->cur_ref->elt->key;
+}
+
+void *
+ec_keyval_iter_get_val(const struct ec_keyval_iter *iter)
+{
+ if (iter == NULL || iter->cur_ref == NULL)
+ return NULL;
+
+ return iter->cur_ref->elt->val;
+}
+
+void ec_keyval_dump(FILE *out, const struct ec_keyval *keyval)
+{
+ struct ec_keyval_iter *iter;
+
if (keyval == NULL) {
fprintf(out, "empty keyval\n");
return;
}
fprintf(out, "keyval:\n");
- for (i = 0; i < keyval->table_size; i++) {
- LIST_FOREACH(ref, &keyval->table[i], next) {
- fprintf(out, " %s: %p\n",
- ref->elt->key, ref->elt->val);
- }
+ for (iter = ec_keyval_iter(keyval);
+ ec_keyval_iter_valid(iter);
+ ec_keyval_iter_next(iter)) {
+ fprintf(out, " %s: %p\n",
+ ec_keyval_iter_get_key(iter),
+ ec_keyval_iter_get_val(iter));
}
+ ec_keyval_iter_free(iter);
}
struct ec_keyval *ec_keyval_dup(const struct ec_keyval *keyval)
static int ec_keyval_testcase(void)
{
struct ec_keyval *keyval, *dup;
+ struct ec_keyval_iter *iter;
char *val;
- size_t i;
+ size_t i, count;
int ret, testres = 0;
+ FILE *f = NULL;
+ char *buf = NULL;
+ size_t buflen = 0;
keyval = ec_keyval();
if (keyval == NULL) {
return -1;
}
+ count = 0;
+ for (iter = ec_keyval_iter(keyval);
+ ec_keyval_iter_valid(iter);
+ ec_keyval_iter_next(iter)) {
+ count++;
+ }
+ ec_keyval_iter_free(iter);
+ testres |= EC_TEST_CHECK(count == 0, "invalid count in iterator");
+
testres |= EC_TEST_CHECK(ec_keyval_len(keyval) == 0, "bad keyval len");
ret = ec_keyval_set(keyval, "key1", "val1", NULL);
testres |= EC_TEST_CHECK(ret == 0, "cannot set key");
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 key");
+ testres |= EC_TEST_CHECK(ret == 0, "cannot del key1");
testres |= EC_TEST_CHECK(ec_keyval_len(keyval) == 1,
"invalid keyval len");
-
- ec_keyval_dump(stdout, NULL);
- ec_keyval_dump(stdout, keyval);
+ 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];
dup = NULL;
}
+ count = 0;
+ for (iter = ec_keyval_iter(keyval);
+ ec_keyval_iter_valid(iter);
+ ec_keyval_iter_next(iter)) {
+ count++;
+ }
+ ec_keyval_iter_free(iter);
+ 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");
ec_keyval_free(keyval);
return testres;
+
+fail:
+ ec_keyval_free(keyval);
+ if (f)
+ fclose(f);
+ free(buf);
+ return -1;
}
/* LCOV_EXCL_STOP */
typedef void (*ec_keyval_elt_free_t)(void *);
struct ec_keyval;
+struct ec_keyval_iter;
/**
* Create a 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);
+ * ec_keyval_iter_valid(iter);
+ * ec_keyval_iter_next(iter)) {
+ * printf(" %s: %p\n",
+ * ec_keyval_iter_get_key(iter),
+ * ec_keyval_iter_get_val(iter));
+ * }
+ * ec_keyval_iter_free(iter);
+ *
+ * @param keyval
+ * The hash table.
+ * @return
+ * An iterator, or NULL on error (errno is set).
+ */
+struct ec_keyval_iter *
+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.
+ */
+void ec_keyval_iter_next(struct ec_keyval_iter *iter);
+
+/**
+ * Free the iterator.
+ *
+ * @param iter
+ * The hash table iterator.
+ */
+void ec_keyval_iter_free(struct ec_keyval_iter *iter);
+
+/**
+ * Check if the iterator points to a valid element.
+ *
+ * @param iter
+ * The hash table iterator.
+ * @return
+ * true if the element is valid, else false.
+ */
+bool
+ec_keyval_iter_valid(const struct ec_keyval_iter *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_iter *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_iter *iter);
+
+
#endif