Add initial implementation of a reference counting trie.

This commit is contained in:
Danila Fedorin 2018-04-06 23:55:56 -07:00
parent dabab1e870
commit 1960ded070
3 changed files with 170 additions and 1 deletions

View File

@ -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)

80
include/ref_trie.h Normal file
View File

@ -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

89
src/ref_trie.c Normal file
View File

@ -0,0 +1,89 @@
#include "ref_trie.h"
#include <stdlib.h>
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 &current->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);
}