Implement an initial version of reference counting.
This commit is contained in:
parent
7dd81f5e9b
commit
c5fa68fdf5
|
@ -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)
|
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)
|
||||||
add_executable(libabacus src/main.c)
|
add_executable(libabacus src/main.c)
|
||||||
add_subdirectory(external/liblex)
|
add_subdirectory(external/liblex)
|
||||||
|
|
||||||
|
|
79
include/refcount.h
Normal file
79
include/refcount.h
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
#ifndef LIBABACUS_REFCOUNT_H
|
||||||
|
#define LIBABACUS_REFCOUNT_H
|
||||||
|
|
||||||
|
#include "result.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A struct for holding
|
||||||
|
* the number of references
|
||||||
|
* to a value, as well as the function required
|
||||||
|
* to free the value.
|
||||||
|
*/
|
||||||
|
struct libab_ref_count_s {
|
||||||
|
/**
|
||||||
|
* The fucntion to free the value.
|
||||||
|
* Can be NULL for no-op.
|
||||||
|
*/
|
||||||
|
void (*free_func)(void* data);
|
||||||
|
/**
|
||||||
|
* The number of references that
|
||||||
|
* prevent the deallocation of the value.
|
||||||
|
*/
|
||||||
|
int strong;
|
||||||
|
/**
|
||||||
|
* The number of references
|
||||||
|
* that still exist, even to a freed instance.
|
||||||
|
*/
|
||||||
|
int weak;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A reference to a value.
|
||||||
|
*/
|
||||||
|
struct libab_ref_s {
|
||||||
|
/**
|
||||||
|
* Whether this reference is a strong reference.
|
||||||
|
*/
|
||||||
|
int strong;
|
||||||
|
/**
|
||||||
|
* The reference count struct keeping track
|
||||||
|
* of how many references are pointing to the value.
|
||||||
|
*/
|
||||||
|
struct libab_ref_count_s* count;
|
||||||
|
/**
|
||||||
|
* The value this reference holds.
|
||||||
|
*/
|
||||||
|
void* data;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct libab_ref_s libab_ref;
|
||||||
|
typedef struct libab_ref_count_s libab_ref_count;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new referene, using the given data and free function.
|
||||||
|
* @param ref the reference to initialize with the given data.
|
||||||
|
* @param data the data to reference count.
|
||||||
|
* @param free_func the function to use to realease the data when refcount reaches 0.
|
||||||
|
* @return the result of the construction of the reference.
|
||||||
|
*/
|
||||||
|
libab_result libab_ref_new(libab_ref* ref, void* data, void (*free_func)(void* data));
|
||||||
|
/**
|
||||||
|
* Turns the given reference into a weak reference,
|
||||||
|
* making it not keep the data allocated.
|
||||||
|
*/
|
||||||
|
void libab_ref_weaken(libab_ref* ref);
|
||||||
|
/**
|
||||||
|
* Releases this particular reference to the data.
|
||||||
|
* This doesn't necessarily free the underlying data.
|
||||||
|
*/
|
||||||
|
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);
|
||||||
|
/**
|
||||||
|
* Gets the value of the reference.
|
||||||
|
*/
|
||||||
|
void* libab_ref_get(libab_ref* ref);
|
||||||
|
|
||||||
|
#endif
|
57
src/refcount.c
Normal file
57
src/refcount.c
Normal file
|
@ -0,0 +1,57 @@
|
||||||
|
#include "refcount.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
libab_result libab_ref_new(libab_ref* ref, void* data, void (*free_func)(void* data)) {
|
||||||
|
libab_result result = LIBAB_SUCCESS;
|
||||||
|
ref->strong = 1;
|
||||||
|
ref->data = data;
|
||||||
|
if((ref->count = malloc(sizeof(*(ref->count))))) {
|
||||||
|
ref->count->strong = ref->count->weak = 1;
|
||||||
|
ref->count->free_func = free_func;
|
||||||
|
} else {
|
||||||
|
result = LIBAB_MALLOC;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _libab_ref_changed(libab_ref* ref) {
|
||||||
|
if(ref->count->strong == 0) {
|
||||||
|
ref->count->strong--;
|
||||||
|
if(ref->count->free_func) {
|
||||||
|
ref->count->free_func(ref->data);
|
||||||
|
}
|
||||||
|
free(ref->data);
|
||||||
|
}
|
||||||
|
if(ref->count->weak == 0) {
|
||||||
|
free(ref->count);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void libab_ref_weaken(libab_ref* ref) {
|
||||||
|
if(ref->strong) {
|
||||||
|
ref->count->strong--;
|
||||||
|
ref->strong = 0;
|
||||||
|
_libab_ref_changed(ref);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void libab_ref_free(libab_ref* ref) {
|
||||||
|
ref->count->strong -= ref->strong;
|
||||||
|
ref->count->weak--;
|
||||||
|
_libab_ref_changed(ref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void libab_ref_copy(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* to_return = NULL;
|
||||||
|
if(ref->count->strong > 0) {
|
||||||
|
to_return = ref->data;
|
||||||
|
}
|
||||||
|
return to_return;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user