From dbfe1240e07241130c262f8d5f05dd4fdfa834fa Mon Sep 17 00:00:00 2001 From: Daniel Salzman <daniel.salzman@nic.cz> Date: Tue, 27 Sep 2016 16:48:59 +0200 Subject: [PATCH] qp-trie: remove the "qp-" prefix from the API --- Knot.files | 2 +- src/contrib/hat-trie/hat-trie.h | 39 +++++------ src/contrib/qp-trie/qp.c | 67 +++++++++---------- src/contrib/qp-trie/qp.h | 37 +++++----- src/libknot/db/db_trie.c | 1 + tests/.gitignore | 2 +- tests/Makefile.am | 2 +- .../{test_hat-trie.c => test_qp-trie.c} | 51 +++++++------- 8 files changed, 100 insertions(+), 101 deletions(-) rename tests/contrib/{test_hat-trie.c => test_qp-trie.c} (78%) diff --git a/Knot.files b/Knot.files index 1a01d8840..35f47d8db 100644 --- a/Knot.files +++ b/Knot.files @@ -540,11 +540,11 @@ tests/confio.c tests/contrib/test_base32hex.c tests/contrib/test_base64.c tests/contrib/test_endian.c -tests/contrib/test_hat-trie.c tests/contrib/test_heap.c tests/contrib/test_hhash.c tests/contrib/test_net.c tests/contrib/test_net_shortwrite.c +tests/contrib/test_qp-trie.c tests/contrib/test_sockaddr.c tests/contrib/test_string.c tests/contrib/test_strtonum.c diff --git a/src/contrib/hat-trie/hat-trie.h b/src/contrib/hat-trie/hat-trie.h index ff988a8aa..7ce5f0d6d 100644 --- a/src/contrib/hat-trie/hat-trie.h +++ b/src/contrib/hat-trie/hat-trie.h @@ -16,86 +16,83 @@ #pragma once -#include <stdbool.h> -#include <stddef.h> - #include "contrib/qp-trie/qp.h" -#include "contrib/macros.h" -typedef struct qp_trie hattrie_t; -typedef struct qp_trie_it hattrie_iter_t; +typedef trie_t hattrie_t; +typedef trie_val_t value_t; +typedef trie_it_t hattrie_iter_t; inline static hattrie_t* hattrie_create(struct knot_mm *mm) { - return qp_trie_create(mm); + return trie_create(mm); } inline static void hattrie_free(hattrie_t *trie) { - qp_trie_free(trie); + trie_free(trie); } inline static void hattrie_clear(hattrie_t *trie) { - qp_trie_clear(trie); + trie_clear(trie); } inline static size_t hattrie_weight(const hattrie_t *trie) { - return qp_trie_weight(trie); + return trie_weight(trie); } inline static int hattrie_apply_rev(hattrie_t *trie, int (*f)(value_t*,void*), void* d) { - return qp_trie_apply(trie, f, d); + return trie_apply(trie, f, d); } inline static value_t* hattrie_tryget(hattrie_t *trie, const char *key, size_t len) { - return qp_trie_get_try(trie, key, len); + return trie_get_try(trie, key, len); } inline static value_t* hattrie_get(hattrie_t *trie, const char *key, size_t len) { - return qp_trie_get_ins(trie, key, len); + return trie_get_ins(trie, key, len); } inline static int hattrie_find_leq(hattrie_t *trie, const char *key, size_t len, value_t **dst) { - return qp_trie_get_leq(trie, key, len, dst); + return trie_get_leq(trie, key, len, dst); } inline static int hattrie_del(hattrie_t *trie, const char* key, size_t len, value_t *val) { - return qp_trie_del(trie, key, len, val); + return trie_del(trie, key, len, val); } inline static hattrie_iter_t* hattrie_iter_begin(hattrie_t *trie) { - return qp_trie_it_begin(trie); + return trie_it_begin(trie); } inline static void hattrie_iter_next(hattrie_iter_t *it) { - qp_trie_it_next(it); + trie_it_next(it); } inline static bool hattrie_iter_finished(hattrie_iter_t *it) { - return qp_trie_it_finished(it); + return trie_it_finished(it); } inline static void hattrie_iter_free(hattrie_iter_t *it) { - qp_trie_it_free(it); + trie_it_free(it); } inline static const char* hattrie_iter_key(hattrie_iter_t *it, size_t *len) { - return qp_trie_it_key(it, len); + return trie_it_key(it, len); } inline static value_t* hattrie_iter_val(hattrie_iter_t *it) { - return qp_trie_it_val(it); + return trie_it_val(it); } diff --git a/src/contrib/qp-trie/qp.c b/src/contrib/qp-trie/qp.c index 6eaaa36d5..3efba093a 100644 --- a/src/contrib/qp-trie/qp.c +++ b/src/contrib/qp-trie/qp.c @@ -22,8 +22,8 @@ #include <string.h> #include "contrib/qp-trie/qp.h" -#include "contrib/mempattern.h" #include "contrib/macros.h" +#include "contrib/mempattern.h" #include "libknot/errcode.h" #if defined(__i386) || defined(__x86_64) || defined(_M_IX86) \ @@ -51,14 +51,13 @@ typedef unsigned char byte; typedef unsigned int uint; typedef uint bitmap_t; /*! Bit-maps, using the range of 1<<0 to 1<<16 (inclusive). */ -/*! \brief A trie node is either leaf_t or branch_t. */ -typedef union node node_t; - -/*! \brief What we use as trie key internally. */ -typedef struct tkey tkey_t; +typedef struct { + uint32_t len; // 32 bits are enough for key lengths; probably even 16 bits would be. + char chars[]; +} tkey_t; /*! \brief Leaf of trie. */ -typedef struct leaf { +typedef struct { #if !FLAGS_HACK byte flags; #endif @@ -66,10 +65,8 @@ typedef struct leaf { trie_val_t val; } leaf_t; -struct tkey { - uint32_t len; // 32 bits are enough for key lengths; probably even 16 bits would be. - char chars[]; -}; +/*! \brief A trie node is either leaf_t or branch_t. */ +typedef union node node_t; /*! * \brief Branch node of trie. @@ -91,7 +88,7 @@ struct tkey { * \note The branch nodes are never allocated individually, but they are * always part of either the root node or the twigs array of the parent. */ -typedef struct branch { +typedef struct { #if FLAGS_HACK uint32_t flags : 2, bitmap : 17; /*!< The first bitmap bit is for end-of-string child. */ @@ -104,15 +101,15 @@ typedef struct branch { } branch_t; union node { - struct leaf leaf; - struct branch branch; + leaf_t leaf; + branch_t branch; }; -typedef struct qp_trie { +struct trie { node_t root; // undefined when weight == 0, see empty_root() size_t weight; knot_mm_t mm; -} trie_t; +}; /*! \brief Make the root node empty (debug-only). */ static inline void empty_root(node_t *root) { @@ -232,7 +229,7 @@ static int key_cmp(const char *k1, uint32_t k1_len, const char *k2, uint32_t k2_ } } -struct qp_trie* qp_trie_create(knot_mm_t *mm) +trie_t* trie_create(knot_mm_t *mm) { assert_portability(); trie_t *trie = mm_alloc(mm, sizeof(trie_t)); @@ -261,7 +258,7 @@ static void clear_trie(node_t *trie, knot_mm_t *mm) } } -void qp_trie_free(struct qp_trie *tbl) +void trie_free(trie_t *tbl) { if (tbl == NULL) return; @@ -270,7 +267,7 @@ void qp_trie_free(struct qp_trie *tbl) mm_free(&tbl->mm, tbl); } -void qp_trie_clear(struct qp_trie *tbl) +void trie_clear(trie_t *tbl) { assert(tbl); if (!tbl->weight) @@ -280,13 +277,13 @@ void qp_trie_clear(struct qp_trie *tbl) tbl->weight = 0; } -size_t qp_trie_weight(const struct qp_trie *tbl) +size_t trie_weight(const trie_t *tbl) { assert(tbl); return tbl->weight; } -trie_val_t* qp_trie_get_try(trie_t *tbl, const char *key, uint32_t len) +trie_val_t* trie_get_try(trie_t *tbl, const char *key, uint32_t len) { assert(tbl); if (!tbl->weight) @@ -304,7 +301,7 @@ trie_val_t* qp_trie_get_try(trie_t *tbl, const char *key, uint32_t len) return &t->leaf.val; } -int qp_trie_del(struct qp_trie *tbl, const char *key, uint32_t len, trie_val_t *val) +int trie_del(trie_t *tbl, const char *key, uint32_t len, trie_val_t *val) { assert(tbl); if (!tbl->weight) @@ -356,11 +353,11 @@ int qp_trie_del(struct qp_trie *tbl, const char *key, uint32_t len, trie_val_t * /*! * \brief Stack of nodes, storing a path down a trie. * - * The structure also serves directly as the public qp_trie_it_t type, + * The structure also serves directly as the public trie_it_t type, * in which case it always points to the current leaf, unless we've finished * (i.e. it->len == 0). */ -typedef struct qp_trie_it { +typedef struct trie_it { node_t* *stack; /*!< The stack; malloc is used directly instead of mm. */ uint32_t len; /*!< Current length of the stack. */ uint32_t alen; /*!< Allocated/available length of the stack. */ @@ -369,7 +366,7 @@ typedef struct qp_trie_it { } nstack_t; /*! \brief Create a node stack containing just the root (or empty). */ -static void ns_init(nstack_t *ns, struct qp_trie *tbl) +static void ns_init(nstack_t *ns, trie_t *tbl) { assert(tbl); ns->stack = ns->stack_init; @@ -608,7 +605,7 @@ static int ns_next_leaf(nstack_t *ns) } while (true); } -int qp_trie_get_leq(struct qp_trie *tbl, const char *key, uint32_t len, trie_val_t **val) +int trie_get_leq(trie_t *tbl, const char *key, uint32_t len, trie_val_t **val) { assert(tbl && val); *val = NULL; // so on failure we can just return; @@ -683,7 +680,7 @@ static int mk_leaf(node_t *leaf, const char *key, uint32_t len, knot_mm_t *mm) return KNOT_EOK; } -trie_val_t* qp_trie_get_ins(struct qp_trie *tbl, const char *key, uint32_t len) +trie_val_t* trie_get_ins(trie_t *tbl, const char *key, uint32_t len) { assert(tbl); // First leaf in an empty tbl? @@ -764,7 +761,7 @@ static int apply_trie(node_t *t, int (*f)(trie_val_t *, void *), void *d) return KNOT_EOK; } -int qp_trie_apply(struct qp_trie *tbl, int (*f)(trie_val_t *, void *), void *d) +int trie_apply(trie_t *tbl, int (*f)(trie_val_t *, void *), void *d) { assert(tbl && f); if (!tbl->weight) @@ -773,10 +770,10 @@ int qp_trie_apply(struct qp_trie *tbl, int (*f)(trie_val_t *, void *), void *d) } /* These are all thin wrappers around static Tns* functions. */ -qp_trie_it_t* qp_trie_it_begin(struct qp_trie *tbl) +trie_it_t* trie_it_begin(trie_t *tbl) { assert(tbl); - qp_trie_it_t *it = malloc(sizeof(nstack_t)); + trie_it_t *it = malloc(sizeof(nstack_t)); if (!it) return NULL; ns_init(it, tbl); @@ -790,20 +787,20 @@ qp_trie_it_t* qp_trie_it_begin(struct qp_trie *tbl) return it; } -void qp_trie_it_next(qp_trie_it_t *it) +void trie_it_next(trie_it_t *it) { assert(it && it->len); if (ns_next_leaf(it) != KNOT_EOK) it->len = 0; } -bool qp_trie_it_finished(qp_trie_it_t *it) +bool trie_it_finished(trie_it_t *it) { assert(it); return it->len == 0; } -void qp_trie_it_free(qp_trie_it_t *it) +void trie_it_free(trie_it_t *it) { if (!it) return; @@ -811,7 +808,7 @@ void qp_trie_it_free(qp_trie_it_t *it) free(it); } -const char* qp_trie_it_key(qp_trie_it_t *it, size_t *len) +const char* trie_it_key(trie_it_t *it, size_t *len) { assert(it && it->len); node_t *t = it->stack[it->len - 1]; @@ -822,7 +819,7 @@ const char* qp_trie_it_key(qp_trie_it_t *it, size_t *len) return key->chars; } -trie_val_t* qp_trie_it_val(qp_trie_it_t *it) +trie_val_t* trie_it_val(trie_it_t *it) { assert(it && it->len); node_t *t = it->stack[it->len - 1]; diff --git a/src/contrib/qp-trie/qp.h b/src/contrib/qp-trie/qp.h index b841f97fb..c52a0b23e 100644 --- a/src/contrib/qp-trie/qp.h +++ b/src/contrib/qp-trie/qp.h @@ -33,26 +33,29 @@ /*! \brief Element value. */ typedef void* trie_val_t; -/*! Opaque type for holding a QP-trie iterator. */ -typedef struct qp_trie_it qp_trie_it_t; +/*! \brief Opaque structure holding a QP-trie. */ +typedef struct trie trie_t; + +/*! \brief Opaque type for holding a QP-trie iterator. */ +typedef struct trie_it trie_it_t; /*! \brief Create a trie instance. */ -struct qp_trie* qp_trie_create(knot_mm_t *mm); +trie_t* trie_create(knot_mm_t *mm); /*! \brief Free a trie instance. */ -void qp_trie_free(struct qp_trie *tbl); +void trie_free(trie_t *tbl); /*! \brief Clear a trie instance (make it empty). */ -void qp_trie_clear(struct qp_trie *tbl); +void trie_clear(trie_t *tbl); /*! \brief Return the number of keys in the trie. */ -size_t qp_trie_weight(const struct qp_trie *tbl); +size_t trie_weight(const trie_t *tbl); /*! \brief Search the trie, returning NULL on failure. */ -trie_val_t* qp_trie_get_try(struct qp_trie *tbl, const char *key, uint32_t len); +trie_val_t* trie_get_try(trie_t *tbl, const char *key, uint32_t len); /*! \brief Search the trie, inserting NULL trie_val_t on failure. */ -trie_val_t* qp_trie_get_ins(struct qp_trie *tbl, const char *key, uint32_t len); +trie_val_t* trie_get_ins(trie_t *tbl, const char *key, uint32_t len); /*! * \brief Search for less-or-equal element. @@ -61,24 +64,24 @@ trie_val_t* qp_trie_get_ins(struct qp_trie *tbl, const char *key, uint32_t len); * \return KNOT_EOK for exact match, 1 for previous, KNOT_ENOENT for not-found, * or KNOT_E*. */ -int qp_trie_get_leq(struct qp_trie *tbl, const char *key, uint32_t len, trie_val_t **val); +int trie_get_leq(trie_t *tbl, const char *key, uint32_t len, trie_val_t **val); /*! * \brief Apply a function to every trie_val_t, in order. * * \return KNOT_EOK if success or KNOT_E* if error. */ -int qp_trie_apply(struct qp_trie *tbl, int (*f)(trie_val_t *, void *), void *d); +int trie_apply(trie_t *tbl, int (*f)(trie_val_t *, void *), void *d); /*! * \brief Remove an item, returning KNOT_EOK if succeeded or KNOT_ENOENT if not found. * * If val!=NULL and deletion succeeded, the deleted value is set. */ -int qp_trie_del(struct qp_trie *tbl, const char *key, uint32_t len, trie_val_t *val); +int trie_del(trie_t *tbl, const char *key, uint32_t len, trie_val_t *val); /*! \brief Create a new iterator pointing to the first element (if any). */ -qp_trie_it_t* qp_trie_it_begin(struct qp_trie *tbl); +trie_it_t* trie_it_begin(trie_t *tbl); /*! * \brief Advance the iterator to the next element. @@ -86,16 +89,16 @@ qp_trie_it_t* qp_trie_it_begin(struct qp_trie *tbl); * Iteration is in ascending lexicographical order. * In particular, the empty string would be considered as the very first. */ -void qp_trie_it_next(qp_trie_it_t *it); +void trie_it_next(trie_it_t *it); /*! \brief Test if the iterator has gone past the last element. */ -bool qp_trie_it_finished(qp_trie_it_t *it); +bool trie_it_finished(trie_it_t *it); /*! \brief Free any resources of the iterator. It's OK to call it on NULL. */ -void qp_trie_it_free(qp_trie_it_t *it); +void trie_it_free(trie_it_t *it); /*! \brief Return pointer to the key of the current element. */ -const char* qp_trie_it_key(qp_trie_it_t *it, size_t *len); +const char* trie_it_key(trie_it_t *it, size_t *len); /*! \brief Return pointer to the value of the current element (writable). */ -trie_val_t* qp_trie_it_val(qp_trie_it_t *it); +trie_val_t* trie_it_val(trie_it_t *it); diff --git a/src/libknot/db/db_trie.c b/src/libknot/db/db_trie.c index 0a865416c..8f1141812 100644 --- a/src/libknot/db/db_trie.c +++ b/src/libknot/db/db_trie.c @@ -20,6 +20,7 @@ #include "libknot/errcode.h" #include "libknot/db/db_trie.h" #include "contrib/hat-trie/hat-trie.h" +#include "contrib/macros.h" #include "contrib/mempattern.h" static int init(knot_db_t **db, knot_mm_t *mm, void *arg) diff --git a/tests/.gitignore b/tests/.gitignore index 93aa897f9..3d3af24a5 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -5,11 +5,11 @@ /contrib/test_base32hex /contrib/test_base64 /contrib/test_endian -/contrib/test_hat-trie /contrib/test_heap /contrib/test_hhash /contrib/test_net /contrib/test_net_shortwrite +/contrib/test_qp-trie /contrib/test_sockaddr /contrib/test_string /contrib/test_strtonum diff --git a/tests/Makefile.am b/tests/Makefile.am index 9c6f59421..ab2bef9c5 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -14,11 +14,11 @@ check_PROGRAMS = \ contrib/test_base32hex \ contrib/test_base64 \ contrib/test_endian \ - contrib/test_hat-trie \ contrib/test_heap \ contrib/test_hhash \ contrib/test_net \ contrib/test_net_shortwrite \ + contrib/test_qp-trie \ contrib/test_sockaddr \ contrib/test_string \ contrib/test_strtonum \ diff --git a/tests/contrib/test_hat-trie.c b/tests/contrib/test_qp-trie.c similarity index 78% rename from tests/contrib/test_hat-trie.c rename to tests/contrib/test_qp-trie.c index 3955cd426..e1a04c79d 100644 --- a/tests/contrib/test_hat-trie.c +++ b/tests/contrib/test_qp-trie.c @@ -14,11 +14,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>. */ +#include <stdlib.h> #include <string.h> #include <time.h> #include <tap/basic.h> -#include "contrib/hat-trie/hat-trie.h" +#include "contrib/qp-trie/qp.h" #include "contrib/macros.h" #include "contrib/string.h" #include "libknot/errcode.h" @@ -45,12 +46,12 @@ static char *str_key_rand(size_t len) } /* \brief Check lesser or equal result. */ -static bool str_key_find_leq(hattrie_t *trie, char **keys, size_t i, size_t size) +static bool str_key_get_leq(trie_t *trie, char **keys, size_t i, size_t size) { static char key_buf[KEY_MAXLEN]; int ret = 0; - value_t *val = NULL; + trie_val_t *val = NULL; const char *key = keys[i]; size_t key_len = strlen(key) + 1; memcpy(key_buf, key, key_len); @@ -68,13 +69,13 @@ static bool str_key_find_leq(hattrie_t *trie, char **keys, size_t i, size_t size /* Before current key. */ key_buf[key_len - 2] -= 1; if (i < first_key_count) { - ret = hattrie_find_leq(trie, key_buf, key_len, &val); + ret = trie_get_leq(trie, key_buf, key_len, &val); if (ret != KNOT_ENOENT) { diag("%s: leq for key BEFORE %zu/'%s' ret = %d", __func__, i, keys[i], ret); return false; /* No key before first. */ } } else { - ret = hattrie_find_leq(trie, key_buf, key_len, &val); + ret = trie_get_leq(trie, key_buf, key_len, &val); if (ret < KNOT_EOK || strcmp(*val, key_buf) > 0) { diag("%s: '%s' is not before the key %zu/'%s'", __func__, (char*)*val, i, keys[i]); return false; /* Found key must be LEQ than searched. */ @@ -83,7 +84,7 @@ static bool str_key_find_leq(hattrie_t *trie, char **keys, size_t i, size_t size /* Current key. */ key_buf[key_len - 2] += 1; - ret = hattrie_find_leq(trie, key_buf, key_len, &val); + ret = trie_get_leq(trie, key_buf, key_len, &val); if (! (ret == KNOT_EOK && val && strcmp(*val, key_buf) == 0)) { diag("%s: leq for key %zu/'%s' ret = %d", __func__, i, keys[i], ret); return false; /* Must find equal match. */ @@ -91,7 +92,7 @@ static bool str_key_find_leq(hattrie_t *trie, char **keys, size_t i, size_t size /* After the current key. */ key_buf[key_len - 2] += 1; - ret = hattrie_find_leq(trie, key_buf, key_len, &val); + ret = trie_get_leq(trie, key_buf, key_len, &val); if (! (ret >= KNOT_EOK && strcmp(*val, key_buf) <= 0)) { diag("%s: leq for key AFTER %zu/'%s' ret = %d %s", __func__, i, keys[i], ret, (char*)*val); return false; /* Every key must have its LEQ match. */ @@ -117,15 +118,15 @@ int main(int argc, char *argv[]) str_key_sort(keys, key_count); /* Create trie */ - value_t *val = NULL; - hattrie_t *trie = hattrie_create(NULL); - ok(trie != NULL, "hattrie: create"); + trie_val_t *val = NULL; + trie_t *trie = trie_create(NULL); + ok(trie != NULL, "trie: create"); /* Insert keys */ bool passed = true; size_t inserted = 0; for (unsigned i = 0; i < key_count; ++i) { - val = hattrie_get(trie, keys[i], strlen(keys[i]) + 1); + val = trie_get_ins(trie, keys[i], strlen(keys[i]) + 1); if (!val) { passed = false; break; @@ -135,29 +136,29 @@ int main(int argc, char *argv[]) ++inserted; } } - ok(passed, "hattrie: insert"); + ok(passed, "trie: insert"); /* Check total insertions against trie weight. */ - is_int(hattrie_weight(trie), inserted, "hattrie: trie weight matches insertions"); + is_int(trie_weight(trie), inserted, "trie: trie weight matches insertions"); /* Lookup all keys */ passed = true; for (unsigned i = 0; i < key_count; ++i) { - val = hattrie_tryget(trie, keys[i], strlen(keys[i]) + 1); + val = trie_get_try(trie, keys[i], strlen(keys[i]) + 1); if (val && (*val == keys[i] || strcmp(*val, keys[i]) == 0)) { continue; } else { - diag("hattrie: mismatch on element '%u'", i); + diag("trie: mismatch on element '%u'", i); passed = false; break; } } - ok(passed, "hattrie: lookup all keys"); + ok(passed, "trie: lookup all keys"); /* Lesser or equal lookup. */ passed = true; for (unsigned i = 0; i < key_count; ++i) { - if (!str_key_find_leq(trie, keys, i, key_count)) { + if (!str_key_get_leq(trie, keys, i, key_count)) { passed = false; for (int off = -10; off < 10; ++off) { int k = (int)i + off; @@ -169,15 +170,15 @@ int main(int argc, char *argv[]) break; } } - ok(passed, "hattrie: find lesser or equal for all keys"); + ok(passed, "trie: find lesser or equal for all keys"); /* Sorted iteration. */ char key_buf[KEY_MAXLEN] = {'\0'}; size_t iterated = 0; - hattrie_iter_t *it = hattrie_iter_begin(trie); - while (!hattrie_iter_finished(it)) { + trie_it_t *it = trie_it_begin(trie); + while (!trie_it_finished(it)) { size_t cur_key_len = 0; - const char *cur_key = hattrie_iter_key(it, &cur_key_len); + const char *cur_key = trie_it_key(it, &cur_key_len); if (iterated > 0) { /* Only if previous exists. */ if (strcmp(key_buf, cur_key) > 0) { diag("'%s' <= '%s' FAIL\n", key_buf, cur_key); @@ -186,16 +187,16 @@ int main(int argc, char *argv[]) } ++iterated; memcpy(key_buf, cur_key, cur_key_len); - hattrie_iter_next(it); + trie_it_next(it); } - is_int(inserted, iterated, "hattrie: sorted iteration"); - hattrie_iter_free(it); + is_int(inserted, iterated, "trie: sorted iteration"); + trie_it_free(it); /* Cleanup */ for (unsigned i = 0; i < key_count; ++i) { free(keys[i]); } free(keys); - hattrie_free(trie); + trie_free(trie); return 0; } -- GitLab