From e6801255fa2a88d5ee83adb4deb2a72be7b2ce6b Mon Sep 17 00:00:00 2001 From: Danila Fedorin Date: Sat, 31 Mar 2018 20:44:01 -0700 Subject: [PATCH] Add a vector of reference counted values. --- CMakeLists.txt | 2 +- include/ref_vec.h | 69 ++++++++++++++++++++++++++++++++++++++++++++++ include/refcount.h | 4 +-- src/ref_vec.c | 66 ++++++++++++++++++++++++++++++++++++++++++++ src/refcount.c | 4 +-- 5 files changed, 140 insertions(+), 5 deletions(-) create mode 100644 include/ref_vec.h create mode 100644 src/ref_vec.c diff --git a/CMakeLists.txt b/CMakeLists.txt index c3c6030..b24fdc8 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/type.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/type.c src/ref_vec.c) add_executable(libabacus src/main.c) add_subdirectory(external/liblex) diff --git a/include/ref_vec.h b/include/ref_vec.h new file mode 100644 index 0000000..31afcc0 --- /dev/null +++ b/include/ref_vec.h @@ -0,0 +1,69 @@ +#ifndef LIBABACUS_REF_VEC_H +#define LIBABACUS_REF_VEC_H + +#include "result.h" +#include "refcount.h" +#include + +#define LIBABACUS_REF_VEC_INITIAL_SIZE 4 + +/** + * A vector of reference counter pointers. + */ +struct libab_ref_vec_s { + /* + * The capacity of the vector (how many elements + * can be stored inside). + */ + size_t capacity; + /** + * The number of elements inside the vector. + */ + size_t size; + /** + * The array of references. + */ + libab_ref* data; +}; + +typedef struct libab_ref_vec_s libab_ref_vec; + +/** + * Initializes a new vector. + * @param vec the vector to initialize. + * @return the result of the initialization. + */ +libab_result libab_ref_vec_init(libab_ref_vec* vec); +/** + * Inserts an existing reference counted value into the vector. + * This bumps the reference's refcount, thereby preventing its + * deallocation. + * @param vec the vector to insert into. + * @param data the reference to insert. + * @return the result of the insertion. + */ +libab_result libab_ref_vec_insert(libab_ref_vec* vec, libab_ref* data); +/** + * Inserts an allocated value into the vector after wrapping it in a reference. + * @param vec the vector to insert into. + * @param data the value to convert to a refcounted pointer. + * @param free_func the function called to release the value (besides free) + * @return the result of the insertion. + */ +libab_result libab_ref_vec_insert_value(libab_ref_vec* vec, void* data, void (*free_func)(void*)); +/** + * Returns the value at the given index in the vector, or null or the value doesn't + * exist. + * @param vec the vector to get a value from. + * @param index the index to look at. + * @return the reference stored at the given index. + */ +const libab_ref* libab_ref_vec_index(libab_ref_vec* vec, size_t index); +/** + * Releases the memory allocated by the vector. + * The references stored in the vector have their refcount decreased. + * @param vec the vector to free. + */ +void libab_ref_vec_free(libab_ref_vec* vec); + +#endif diff --git a/include/refcount.h b/include/refcount.h index aa74c23..21f6935 100644 --- a/include/refcount.h +++ b/include/refcount.h @@ -70,10 +70,10 @@ void libab_ref_free(libab_ref* ref); /** * Copies this reference, thereby increasing the reference count. */ -void libab_ref_copy(libab_ref* ref, libab_ref* into); +void libab_ref_copy(const libab_ref* ref, libab_ref* into); /** * Gets the value of the reference. */ -void* libab_ref_get(libab_ref* ref); +void* libab_ref_get(const libab_ref* ref); #endif diff --git a/src/ref_vec.c b/src/ref_vec.c new file mode 100644 index 0000000..0b2c020 --- /dev/null +++ b/src/ref_vec.c @@ -0,0 +1,66 @@ +#include "ref_vec.h" +#include + +libab_result libab_ref_vec_init(libab_ref_vec* vec) { + libab_result result = LIBAB_SUCCESS; + vec->capacity = LIBABACUS_REF_VEC_INITIAL_SIZE; + vec->size = 0; + vec->data = + malloc(sizeof(*vec->data) * LIBABACUS_REF_VEC_INITIAL_SIZE); + if(vec->data == NULL) { + result = LIBAB_MALLOC; + } + return result; +} + +libab_result _libab_ref_vec_try_resize(libab_ref_vec* vec) { + libab_result result = LIBAB_SUCCESS; + if(vec->size == vec->capacity) { + libab_ref* new_memory = realloc(vec->data, (vec->capacity *= 2) * sizeof(*vec->data)); + if(new_memory == NULL) { + free(vec->data); + result = LIBAB_MALLOC; + } + } + return result; +} + +libab_result libab_ref_vec_insert(libab_ref_vec* vec, libab_ref* data) { + libab_result result = _libab_ref_vec_try_resize(vec); + + if(result == LIBAB_SUCCESS) { + libab_ref_copy(data, &vec->data[vec->size++]); + } + + return result; +} + +libab_result libab_ref_vec_insert_value(libab_ref_vec* vec, void* data, void (*free_func)(void*)) { + libab_result result = _libab_ref_vec_try_resize(vec); + + if(result == LIBAB_SUCCESS) { + result = libab_ref_new(&vec->data[vec->size], data, free_func); + } + + if(result == LIBAB_SUCCESS) { + vec->size++; + } + + return result; +} + +const libab_ref* libab_ref_vec_index(libab_ref_vec* vec, size_t index) { + const libab_ref* to_return = NULL; + if(index < vec->size) { + to_return = &vec->data[index]; + } + return to_return; +} + +void libab_ref_vec_free(libab_ref_vec* vec) { + size_t i = 0; + for(; i < vec->size; i++) { + libab_ref_free(&vec->data[i]); + } + free(vec->data); +} diff --git a/src/refcount.c b/src/refcount.c index aa426e1..5d32cee 100644 --- a/src/refcount.c +++ b/src/refcount.c @@ -42,13 +42,13 @@ void libab_ref_free(libab_ref* ref) { _libab_ref_changed(ref); } -void libab_ref_copy(libab_ref* ref, libab_ref* into) { +void libab_ref_copy(const libab_ref* ref, libab_ref* into) { ref->count->strong++; ref->count->weak++; memcpy(into, ref, sizeof(*ref)); } -void* libab_ref_get(libab_ref* ref) { +void* libab_ref_get(const libab_ref* ref) { void* to_return = NULL; if(ref->count->strong > 0) { to_return = ref->data;