Skip to content

Instantly share code, notes, and snippets.

@andreafioraldi
Created October 7, 2020 12:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save andreafioraldi/baed370b44e64709d2c2ca948143c225 to your computer and use it in GitHub Desktop.
Save andreafioraldi/baed370b44e64709d2c2ca948143c225 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#define INHERITS(type) struct type _base;
#define BASE_CAST(ptr) (&(ptr)->_base)
#define VTABLE_INHERITS(type) struct type##_vtable _base;
#define VTABLE_INIT_BASE_VPTR(type) \
._base_vptr = (struct afl_object_vtable*)&type##_vtable_instance
#define VTABLE_OF(type, ptr) ((struct type##_vtable*)(((struct afl_object*)(ptr))->vptr))
#define VTABLE_SET(ptr, vtable) ((struct afl_object*)(ptr))->vptr = (struct afl_object_vtable*)&vtable
// #define INSTANCE_OF(type, ptr) ((ptr)->v == &type##_vtable_instance)
#define INSTANCE_OF(type, ptr) ({ \
struct afl_object_vtable* _v = (struct afl_object_vtable*)&type##_vtable_instance; \
while (_v) { \
if (_v == ((struct afl_object*)(ptr))->vptr) break; \
_v = _v->_base_vptr; \
} \
!!_v; \
})
#define DYN_CAST(type, ptr) (INSTANCE_OF(type, ptr) ? (struct type*)(ptr) : NULL)
/// class Object
typedef struct afl_object afl_object_t;
struct afl_object_vtable {
struct afl_object_vtable* _base_vptr;
void* (*_create_wrapper)(void*); // for bindings
/*
The deinit() method is optional.
It is invoked just before the destroy of the object.
*/
void (*deinit)(afl_object_t *);
};
struct afl_object_vtable afl_object_vtable_instance = {
._base_vptr = NULL,
.deinit = NULL
};
struct afl_object {
void* wrapper; // for bindings
struct afl_object_vtable *vptr;
};
/// virtual class A
typedef struct afl_A afl_A_t;
void afl_A_deinit__nonvirtual(afl_object_t* self);
struct afl_A_vtable {
VTABLE_INHERITS(afl_object)
void (*print)(afl_A_t*);
};
struct afl_A_vtable afl_A_vtable_instance = {
._base = {
VTABLE_INIT_BASE_VPTR(afl_object),
.deinit = &afl_A_deinit__nonvirtual
},
.print = NULL
};
struct afl_A {
INHERITS(afl_object)
int x;
};
static inline void afl_object_deinit(afl_object_t* self) {
if (VTABLE_OF(afl_object, self)->deinit)
VTABLE_OF(afl_object, self)->deinit(self);
}
// Protected init for virtual classes
void afl_A_init__protected(afl_A_t* self, int x) {
self->x = x;
VTABLE_SET(self, afl_A_vtable_instance);
}
// Wrap vtable methods
static inline void afl_A_print(afl_A_t* self) {
VTABLE_OF(afl_A, self)->print(self);
}
// For the nonvirtuals, maintain the original type of self (afl_object_t)
void afl_A_deinit__nonvirtual(afl_object_t* self) {
if (INSTANCE_OF(afl_A, self)) // do only for debug builds maybe
DYN_CAST(afl_A, self)->x = 0;
}
// For the wrappers, use the actual self type (afl_A_t)
static inline void afl_A_deinit(afl_A_t* self) {
afl_object_deinit(BASE_CAST(self));
}
/// class B
void afl_B_print__nonvirtual(afl_A_t* self);
typedef struct afl_B afl_B_t;
struct afl_A_vtable afl_B_vtable_instance = {
// afl_object_vtable
._base = {
VTABLE_INIT_BASE_VPTR(afl_A), // declare the parent vtable
.deinit = &afl_A_deinit__nonvirtual // reuse A deinit
},
.print = &afl_B_print__nonvirtual
};
struct afl_B {
INHERITS(afl_A)
};
// Protected init for virtual classes
void afl_B_init(afl_B_t* self, int x) {
// call super constructor
afl_A_init__protected(BASE_CAST(self), x);
VTABLE_SET(self, afl_B_vtable_instance);
}
void afl_B_print__nonvirtual(afl_A_t* self) {
if (INSTANCE_OF(afl_B, self))
printf("B: %d\n", self->x);
}
// Forward the wrapper
static inline void afl_B_print(afl_B_t* self) {
afl_A_print(BASE_CAST(self));
}
int main() {
afl_B_t b;
afl_B_init(&b, 1);
afl_A_t* downcast = (afl_A_t*)&b;
afl_A_print(downcast); // B: 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment