From 1960ded07071c037bb894aed34bc664eee572183 Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Fri, 6 Apr 2018 23:55:56 -0700 Subject: [PATCH] Add initial implementation of a reference counting trie. --- CMakeLists.txt | 2 +- include/ref_trie.h | 80 +++++++++++++++++++++++++++++++++++++++++ src/ref_trie.c | 89 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 include/ref_trie.h create mode 100644 src/ref_trie.c diff --git a/CMakeLists.txt b/CMakeLists.txt index a4f9274..4547d95 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ project(libabacus) add_compile_options(-pedantic -Wall) -add_library(abacus STATIC src/lexer.c src/util.c src/table.c src/parser.c src/libabacus.c src/tree.c src/debug.c src/parsetype.c src/reserved.c src/trie.c src/refcount.c src/ref_vec.c) +add_library(abacus STATIC src/lexer.c src/util.c src/table.c src/parser.c src/libabacus.c src/tree.c src/debug.c src/parsetype.c src/reserved.c src/trie.c src/refcount.c src/ref_vec.c src/ref_trie.c) add_executable(libabacus src/main.c) add_subdirectory(external/liblex) diff --git a/include/ref_trie.h b/include/ref_trie.h new file mode 100644 index 0000000..21532da --- /dev/null +++ b/include/ref_trie.h @@ -0,0 +1,80 @@ +#ifndef LIBABACUS_REF_TRIE_H +#define LIBABACUS_REF_TRIE_H + +#include "refcount.h" +#include "result.h" + +/** + * A node in the trie. + * unlike the normal libab_trie, + * this trie only has at most one value for each key. + */ +struct libab_ref_trie_node_s { + /** + * The next child of this trie node, which represents + * a letter the same distance from the beginning. + */ + struct libab_ref_trie_node_s* next; + /** + * The child of this node, which represents a letter + * one further away than this node, with the same prefix. + */ + struct libab_ref_trie_node_s* child; + /** + * The key of this node. + */ + char key; + /** + * The reference pointed to by this node. + */ + libab_ref ref; +}; + +/** + * The struct that holds the trie. + */ +struct libab_ref_trie_s { + /** + * The first node in the trie. + */ + struct libab_ref_trie_node_s* head; + /** + * Reference (initialized to NULL) returned + * if no key is found. + */ + libab_ref null_ref; +}; + +typedef struct libab_ref_trie_node_s libab_ref_trie_node; +typedef struct libab_ref_trie_s libab_ref_trie; + +/** + * Initializes the trie with no nodes. + * @param trie the trie to initialize. + */ +void libab_ref_trie_init(libab_ref_trie* trie); +/** + * Stores a reference counted value into the trie. + * This releases the reference for the given key, if one + * already exists. This increments the refcoutn. + * @param trie the trie to insert into. + * @param key the key to insert under. + * @param ref the reference to insert. + * @return the result of the insertion. + */ +libab_result libab_ref_trie_put(libab_ref_trie* trie, const char* key, libab_ref* ref); +/** + * Retreives a reference under the given key in the trie. + * @param trie the trie to retreive from. + * @param key the key to look under. + * @return a reference stored under the given key. This can be a NULL reference. + */ +const libab_ref* libab_ref_trie_get(const libab_ref_trie* trie, const char* key); +/** + * Releases the trie, decrementing the refcounts of all + * the values stored inside. + * @param trie the trie to release. + */ +void libab_ref_trie_free(libab_ref_trie* trie); + +#endif diff --git a/src/ref_trie.c b/src/ref_trie.c new file mode 100644 index 0000000..9c1c778 --- /dev/null +++ b/src/ref_trie.c @@ -0,0 +1,89 @@ +#include "ref_trie.h" +#include + +void libab_ref_trie_init(libab_ref_trie* trie) { + libab_ref_null(&trie->null_ref); + trie->head = NULL; +} + +libab_result _libab_ref_trie_put(libab_ref_trie_node** node, const char* key, libab_ref* ref) { + libab_result result = LIBAB_SUCCESS; + if((*node = malloc(sizeof(**node)))) { + (*node)->key = *key; + (*node)->next = NULL; + + if(*(key + 1)) { + libab_ref_null(&(*node)->ref); + result = _libab_ref_trie_put(&(*node)->child, key + 1, ref); + } else { + libab_ref_copy(ref, &(*node)->ref); + (*node)->child = NULL; + } + } else { + result = LIBAB_MALLOC; + } + + if(result != LIBAB_SUCCESS) { + if(*node) libab_ref_free(&(*node)->ref); + free(*node); + *node = NULL; + } + + return result; +} + +libab_result libab_ref_trie_put(libab_ref_trie* trie, const char* key, libab_ref* ref) { + libab_result result = LIBAB_SUCCESS; + libab_ref_trie_node** current = &trie->head; + char search; + while(*key) { + search = *key; + while(*current && (*current)->key != search) { + current = &(*current)->next; + } + if(*current) { + if(*(key + 1)) { + current = &(*current)->child; + } else { + libab_ref_free(&(*current)->ref); + libab_ref_copy(ref, &(*current)->ref); + } + key++; + } else { + result = _libab_ref_trie_put(current, key, ref); + break; + } + } + return result; +} + +const libab_ref* libab_ref_trie_get(const libab_ref_trie* trie, const char* key) { + libab_ref_trie_node* current = trie->head; + while(current && *key) { + while(current && current->key != *key) { + current = current->next; + } + if(current == NULL) break; + + if(*(key + 1)) { + current = current->child; + key++; + } else { + return ¤t->ref; + } + } + return &trie->null_ref; +} + +void _libab_ref_trie_free(libab_ref_trie_node* node) { + if(node == NULL) return; + _libab_ref_trie_free(node->next); + _libab_ref_trie_free(node->child); + libab_ref_free(&node->ref); + free(node); +} + +void libab_ref_trie_free(libab_ref_trie* trie) { + _libab_ref_trie_free(trie->head); + libab_ref_free(&trie->null_ref); +}