Switch values to having their data refcounted separately.

This allows for values to be "cast" and have a different type, while
still referencing the same data.
This commit is contained in:
Danila Fedorin 2018-05-14 17:41:41 -07:00
parent 3e8c814215
commit cf3136a237
5 changed files with 72 additions and 20 deletions

View File

@ -80,7 +80,15 @@ libab_result libab_create_table(libab_ref* into, libab_ref* parent);
* @param type the type to give the value. * @param type the type to give the value.
* @return the result of necessary allocations. * @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. * Creates a function list object, storing it in to the given reference.
* @param into the reference to store into. * @param into the reference to store into.

View File

@ -15,19 +15,28 @@ struct libab_value_s {
/** /**
* The data that is specific to this value. * The data that is specific to this value.
*/ */
void* data; libab_ref data;
}; };
typedef struct libab_value_s libab_value; 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. * and the given type.
* @param data the data for this value. It is freed when the value is released * @param value the value to initialize.
* according to the free function of the base type. * @param data the data for this value. Its refcount is decreased when the value is freed.
* @param type the type of this value. * @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. * Frees the given value.
* @param value the value to free. * @param value the value to free.

View File

@ -25,7 +25,7 @@ libab_result _interpreter_create_num_val(struct interpreter_state* state,
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
if((data = state->ab->impl.parse_num(from))) { 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) { if(result != LIBAB_SUCCESS) {
((libab_parsetype*) libab_ref_get(&state->ab->type_num))->data_u.base->free_function(data); ((libab_parsetype*) libab_ref_get(&state->ab->type_num))->data_u.base->free_function(data);

View File

@ -155,11 +155,11 @@ void _free_value(void* value) {
free(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_value* value;
libab_result result = LIBAB_SUCCESS; libab_result result = LIBAB_SUCCESS;
if((value = malloc(sizeof(*value)))) { 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); result = libab_ref_new(into, value, _free_value);
if(result != LIBAB_SUCCESS) { if(result != LIBAB_SUCCESS) {
@ -175,6 +175,31 @@ libab_result libab_create_value(libab_ref* into, void* data, libab_ref* type) {
return result; 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_result libab_create_function_list(libab_ref* into, libab_ref* type) {
libab_function_list* list; libab_function_list* list;
libab_result result = LIBAB_SUCCESS; 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) { if(result == LIBAB_SUCCESS) {
result = libab_create_value(into, list, type); result = libab_create_value_raw(into, list, type);
if(result != LIBAB_SUCCESS) { if(result != LIBAB_SUCCESS) {
libab_function_list_free(list); libab_function_list_free(list);
libab_ref_free(into); libab_ref_free(into);

View File

@ -1,17 +1,27 @@
#include "value.h" #include "value.h"
#include "parsetype.h" #include "parsetype.h"
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) {
value->data = data; libab_ref_copy(data, &value->data);
libab_ref_copy(type, &value->type); libab_ref_copy(type, &value->type);
} }
void libab_value_free(libab_value* value) { libab_result libab_value_init_raw(libab_value* value, void* data, libab_ref* type) {
void (*free_function)(void*); libab_result result = LIBAB_SUCCESS;
libab_parsetype* value_type; libab_ref tmp_ref;
value_type = libab_ref_get(&value->type);
free_function = value_type->data_u.base->free_function; result = libab_ref_new(&tmp_ref, data,
libab_ref_free(&value->type); ((libab_parsetype*) libab_ref_get(type))->data_u.base->free_function);
if (free_function)
free_function(value->data); 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);
} }