diff --git a/lang/func.c b/lang/func.c index 464accf..785d834 100644 --- a/lang/func.c +++ b/lang/func.c @@ -4,23 +4,17 @@ #include "bytecode.h" #include "error.h" #include "object.h" -#include +#include static struct object_class func_class; -struct func { - struct object obj; -}; - Object func_create(void) { - struct func *func = malloc(sizeof(struct func)); - abort_if(!func, "unable to allocate func"); - func->obj.class_data = &func_class; - func->obj.ref_count = 1; - return (Object)func; + Object obj = object_create(&func_class, 1); + abort_if(!obj, "unable to allocate func"); + return obj; } -static void func_cleanup(Object obj) { free(obj); } +static void func_cleanup(Object obj) { (void)obj; } static void func_call(VmState state, Object obj) { (void)obj; diff --git a/lang/number.c b/lang/number.c index f904f66..72fa887 100644 --- a/lang/number.c +++ b/lang/number.c @@ -3,30 +3,26 @@ #include "error.h" #include "object.h" -#include +#include static struct object_class num_class; struct number { - struct object obj; int value; }; Object number_create(int value) { - struct number *num = malloc(sizeof(struct number)); - abort_if(!num, "unable to allocate number"); - num->obj.class_data = &num_class; - num->obj.ref_count = 1; + Object obj = object_create(&num_class, sizeof(struct number)); + abort_if(!obj, "unable to allocate number"); + struct number *num = (struct number *)object_priv(obj, &num_class); num->value = value; - return (Object)num; + return obj; } -static void number_cleanup(Object obj) { free(obj); } +static void number_cleanup(Object obj) { (void)obj; } int number_value(Object obj) { - abort_if(obj->class_data != &num_class, - "number_value obj is not a number"); - struct number *num = (struct number *)obj; + struct number *num = (struct number *)object_priv(obj, &num_class); return num->value; } diff --git a/lang/object.c b/lang/object.c index 76ec3b9..027f1ad 100644 --- a/lang/object.c +++ b/lang/object.c @@ -3,9 +3,35 @@ #include "object.h" #include "error.h" +#include #include +#include #include +struct object { + struct object_class *class_data; + atomic_int ref_count; + char priv_data[]; +}; + +Object object_create(struct object_class *class, int priv_size) { + abort_if(priv_size < 1, "object_create: priv_size too small"); + size_t size = sizeof(struct object) + priv_size; + struct object *obj = calloc(size, 1); + abort_if( + obj == NULL, "object_create: not enough memory for an objects"); + obj->class_data = class; + obj->ref_count = 1; + return (Object)obj; +} + +char *object_priv(Object object, struct object_class *class) { + abort_if(object == NULL, "object_priv: no object"); + struct object *obj = (struct object *)object; + abort_if(obj->class_data != class, "object_priv: incompatible class"); + return object->priv_data; +} + void object_hold(Object obj) { abort_if(obj == NULL, "object_hold holding NULL"); atomic_fetch_add_explicit(&obj->ref_count, 1, memory_order_relaxed); @@ -19,6 +45,7 @@ if (count == 1) { // We were the last user of the object, clean it up obj->class_data->cleanup(obj); + free(obj); } *objptr = NULL; } diff --git a/lang/object.h b/lang/object.h index 05264db..2714f59 100644 --- a/lang/object.h +++ b/lang/object.h @@ -5,7 +5,6 @@ #define OBJECT_H #include "vm.h" -#include // Dispatchable object call struct object_call { @@ -20,13 +19,8 @@ *calls; // Points to array terminated by call with NULL name }; -// Object structure used by all classes -// Place this at the start of your private structure and cast accordingly -// Make sure to compile with -fno-strict-aliasing -struct object { - struct object_class *class_data; - atomic_int ref_count; -}; +Object object_create(struct object_class *class, int priv_size); +char *object_priv(Object object, struct object_class *class); // Adds a reference to an object void object_hold(Object obj);