Add initial implementation of a reference counting trie.
This commit is contained in:
parent
dabab1e870
commit
1960ded070
@ -8,7 +8,7 @@ project(libabacus)
|
|||||||
|
|
||||||
add_compile_options(-pedantic -Wall)
|
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_executable(libabacus src/main.c)
|
||||||
add_subdirectory(external/liblex)
|
add_subdirectory(external/liblex)
|
||||||
|
|
||||||
|
80
include/ref_trie.h
Normal file
80
include/ref_trie.h
Normal 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
89
src/ref_trie.c
Normal 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 ¤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);
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user