diff --git a/include/util.h b/include/util.h index a9a1aed..dd44440 100644 --- a/include/util.h +++ b/include/util.h @@ -80,7 +80,15 @@ libab_result libab_create_table(libab_ref* into, libab_ref* parent); * @param type the type to give the value. * @return the result of necessary allocations. */ -libab_result libab_create_value(libab_ref* into, void* data, libab_ref* type); +libab_result libab_create_value_ref(libab_ref* into, libab_ref* data, libab_ref* type); +/** + * Allocates a new reference counted value with the given type and data. + * @param into the reference to store the allocated data into. + * @param data the type-specific data this value holds. + * @param type the type to give the value. + * @return the result of necessary allocations. + */ +libab_result libab_create_value_raw(libab_ref* into, void* data, libab_ref* type); /** * Creates a function list object, storing it in to the given reference. * @param into the reference to store into. diff --git a/include/value.h b/include/value.h index 834505a..f4f8eb6 100644 --- a/include/value.h +++ b/include/value.h @@ -15,19 +15,28 @@ struct libab_value_s { /** * The data that is specific to this value. */ - void* data; + libab_ref data; }; typedef struct libab_value_s libab_value; /** - * Initializes a new value with the given allocated memory for the data, + * Initializes a new value with the given reference counted data * and the given type. - * @param data the data for this value. It is freed when the value is released - * according to the free function of the base type. + * @param value the value to initialize. + * @param data the data for this value. Its refcount is decreased when the value is freed. * @param type the type of this value. */ -void libab_value_init(libab_value* value, void* data, libab_ref* type); +void libab_value_init_ref(libab_value* value, libab_ref* data, libab_ref* type); +/** + * Initializes a new value with the given raw allocated data, and a type, + * whose basetype's free function is used to release the data when the value is freed. + * @param value the value to initialize. + * @param data the data this value holds. + * @param type the type of this value. + * @return the result of any necessary allocations. + */ +libab_result libab_value_init_raw(libab_value* value, void* data, libab_ref* type); /** * Frees the given value. * @param value the value to free. diff --git a/src/interpreter.c b/src/interpreter.c index 0470913..5888a3f 100644 --- a/src/interpreter.c +++ b/src/interpreter.c @@ -25,7 +25,7 @@ libab_result _interpreter_create_num_val(struct interpreter_state* state, libab_result result = LIBAB_SUCCESS; if((data = state->ab->impl.parse_num(from))) { - result = libab_create_value(into, data, &state->ab->type_num); + result = libab_create_value_raw(into, data, &state->ab->type_num); if(result != LIBAB_SUCCESS) { ((libab_parsetype*) libab_ref_get(&state->ab->type_num))->data_u.base->free_function(data); diff --git a/src/util.c b/src/util.c index b0e6897..9f061ef 100644 --- a/src/util.c +++ b/src/util.c @@ -155,11 +155,11 @@ void _free_value(void* value) { free(value); } -libab_result libab_create_value(libab_ref* into, void* data, libab_ref* type) { +libab_result libab_create_value_ref(libab_ref* into, libab_ref* data, libab_ref* type) { libab_value* value; libab_result result = LIBAB_SUCCESS; if((value = malloc(sizeof(*value)))) { - libab_value_init(value, data, type); + libab_value_init_ref(value, data, type); result = libab_ref_new(into, value, _free_value); if(result != LIBAB_SUCCESS) { @@ -175,6 +175,31 @@ libab_result libab_create_value(libab_ref* into, void* data, libab_ref* type) { return result; } +libab_result libab_create_value_raw(libab_ref* into, void* data, libab_ref* type) { + libab_value* value; + libab_result result = LIBAB_SUCCESS; + + if((value = malloc(sizeof(*value)))) { + result = libab_value_init_raw(value, data, type); + } else { + result = LIBAB_MALLOC; + } + + if(result == LIBAB_SUCCESS) { + result = libab_ref_new(into, value, _free_value); + if(result != LIBAB_SUCCESS) { + libab_value_free(value); + } + } + + if(result != LIBAB_SUCCESS) { + libab_ref_null(into); + free(value); + } + + return result; +} + libab_result libab_create_function_list(libab_ref* into, libab_ref* type) { libab_function_list* list; libab_result result = LIBAB_SUCCESS; @@ -186,7 +211,7 @@ libab_result libab_create_function_list(libab_ref* into, libab_ref* type) { } if(result == LIBAB_SUCCESS) { - result = libab_create_value(into, list, type); + result = libab_create_value_raw(into, list, type); if(result != LIBAB_SUCCESS) { libab_function_list_free(list); libab_ref_free(into); diff --git a/src/value.c b/src/value.c index 84323e5..81f212d 100644 --- a/src/value.c +++ b/src/value.c @@ -1,17 +1,27 @@ #include "value.h" #include "parsetype.h" -void libab_value_init(libab_value* value, void* data, libab_ref* type) { - value->data = data; +void libab_value_init_ref(libab_value* value, libab_ref* data, libab_ref* type) { + libab_ref_copy(data, &value->data); libab_ref_copy(type, &value->type); } -void libab_value_free(libab_value* value) { - void (*free_function)(void*); - libab_parsetype* value_type; - value_type = libab_ref_get(&value->type); - free_function = value_type->data_u.base->free_function; - libab_ref_free(&value->type); - if (free_function) - free_function(value->data); +libab_result libab_value_init_raw(libab_value* value, void* data, libab_ref* type) { + libab_result result = LIBAB_SUCCESS; + libab_ref tmp_ref; + + result = libab_ref_new(&tmp_ref, data, + ((libab_parsetype*) libab_ref_get(type))->data_u.base->free_function); + + if(result == LIBAB_SUCCESS) { + libab_value_init_ref(value, &tmp_ref, type); + libab_ref_free(&tmp_ref); + } + + return result; +} + +void libab_value_free(libab_value* value) { + libab_ref_free(&value->data); + libab_ref_free(&value->type); }