Skip to content

Instantly share code, notes, and snippets.

@andreafioraldi
Created October 10, 2020 18:14
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/ead77d3cda724377098c0ef4479e6d71 to your computer and use it in GitHub Desktop.
Save andreafioraldi/ead77d3cda724377098c0ef4479e6d71 to your computer and use it in GitHub Desktop.
#include <stdio.h>
#include <assert.h>
/* Macro magic, you don't have to understand, just believe. */
#define AFL_MAGIC_FIRST_(a, ...) a
#define AFL_MAGIC_SECOND_(a, b, ...) b
#define AFL_MAGIC_FIRST(...) AFL_MAGIC_FIRST_(__VA_ARGS__,)
#define AFL_MAGIC_SECOND(...) AFL_MAGIC_SECOND_(__VA_ARGS__,)
#define AFL_MAGIC_FIRST_SECOND(...) AFL_MAGIC_FIRST(__VA_ARGS__) AFL_MAGIC_SECOND(__VA_ARGS__)
#define AFL_MAGIC_IS_PROBE(...) AFL_MAGIC_SECOND(__VA_ARGS__, 0)
#define AFL_MAGIC_PROBE() ~, 1
#define AFL_MAGIC_CAT(a, b) a ## b
#define AFL_MAGIC_NOT(x) AFL_MAGIC_IS_PROBE(AFL_MAGIC_CAT(AFL_MAGIC__NOT_, x))
#define AFL_MAGIC__NOT_0 AFL_MAGIC_PROBE()
#define AFL_MAGIC_BOOL(x) AFL_MAGIC_NOT(AFL_MAGIC_NOT(x))
/* If else on macro constants */
#define AFL_MAGIC_IF_ELSE(condition) AFL_MAGIC__IF_ELSE(AFL_MAGIC_BOOL(condition))
#define AFL_MAGIC__IF_ELSE(condition) AFL_MAGIC_CAT(AFL_MAGIC__IF_, condition)
#define AFL_MAGIC__IF_1(...) __VA_ARGS__ AFL_MAGIC__IF_1_ELSE
#define AFL_MAGIC__IF_0(...) AFL_MAGIC__IF_0_ELSE
#define AFL_MAGIC__IF_1_ELSE(...)
#define AFL_MAGIC__IF_0_ELSE(...) __VA_ARGS__
#define AFL_MAGIC_HAS_ARGS(...) AFL_MAGIC_BOOL(AFL_MAGIC_FIRST(AFL_MAGIC__END_OF_ARGUMENTS_ __VA_ARGS__)())
#define AFL_MAGIC__END_OF_ARGUMENTS_() 0
#define AFL_MAGIC_EVAL0(...) __VA_ARGS__
#define AFL_MAGIC_EVAL1(...) AFL_MAGIC_EVAL0(AFL_MAGIC_EVAL0(AFL_MAGIC_EVAL0(__VA_ARGS__)))
#define AFL_MAGIC_EVAL2(...) AFL_MAGIC_EVAL1(AFL_MAGIC_EVAL1(AFL_MAGIC_EVAL1(__VA_ARGS__)))
#define AFL_MAGIC_EVAL3(...) AFL_MAGIC_EVAL2(AFL_MAGIC_EVAL2(AFL_MAGIC_EVAL2(__VA_ARGS__)))
#define AFL_MAGIC_EVAL4(...) AFL_MAGIC_EVAL3(AFL_MAGIC_EVAL3(AFL_MAGIC_EVAL3(__VA_ARGS__)))
#define AFL_MAGIC_EVAL(...) AFL_MAGIC_EVAL4(AFL_MAGIC_EVAL4(AFL_MAGIC_EVAL4(__VA_ARGS__)))
#define AFL_MAGIC_MAPEND(...)
#define AFL_MAGIC_MAPOUT
#define AFL_MAGIC_MAPCOMMA ,
#define AFL_MAGIC_MAPGET_END2() 0, AFL_MAGIC_MAPEND
#define AFL_MAGIC_MAPGET_END1(...) AFL_MAGIC_MAPGET_END2
#define AFL_MAGIC_MAPGET_END(...) AFL_MAGIC_MAPGET_END1
#define AFL_MAGIC_MAPNEXT0(test, next, ...) next AFL_MAGIC_MAPOUT
#define AFL_MAGIC_MAPNEXT1(test, next) AFL_MAGIC_MAPNEXT0(test, next, 0)
#define AFL_MAGIC_MAPNEXT(test, next) AFL_MAGIC_MAPNEXT1(AFL_MAGIC_MAPGET_END test, next)
#define AFL_MAGIC_MAP0(f, x, peek, ...) f(x) AFL_MAGIC_MAPNEXT(peek, AFL_MAGIC_MAP1)(f, peek, __VA_ARGS__)
#define AFL_MAGIC_MAP1(f, x, peek, ...) f(x) AFL_MAGIC_MAPNEXT(peek, AFL_MAGIC_MAP0)(f, peek, __VA_ARGS__)
#define AFL_MAGIC_DOUBLE_MAP0(f, x, y, peek, ...) f(x, y) AFL_MAGIC_MAPNEXT(peek, AFL_MAGIC_DOUBLE_MAP1)(f, peek, __VA_ARGS__)
#define AFL_MAGIC_DOUBLE_MAP1(f, x, y, peek, ...) f(x, y) AFL_MAGIC_MAPNEXT(peek, AFL_MAGIC_DOUBLE_MAP0)(f, peek, __VA_ARGS__)
#define AFL_MAGIC_MAPLIST_NEXT1(test, next) AFL_MAGIC_MAPNEXT0(test, AFL_MAGIC_MAPCOMMA next, 0)
#define AFL_MAGIC_MAPLIST_NEXT(test, next) AFL_MAGIC_MAPLIST_NEXT1(AFL_MAGIC_MAPGET_END test, next)
#define AFL_MAGIC_MAPLIST0(f, x, peek, ...) f(x) AFL_MAGIC_MAPLIST_NEXT(peek, AFL_MAGIC_MAPLIST1)(f, peek, __VA_ARGS__)
#define AFL_MAGIC_MAPLIST1(f, x, peek, ...) f(x) AFL_MAGIC_MAPLIST_NEXT(peek, AFL_MAGIC_MAPLIST0)(f, peek, __VA_ARGS__)
#define AFL_MAGIC_DOUBLE_MAPLIST0(f, x, y, peek, ...) \
f(x, y) AFL_MAGIC_MAPLIST_NEXT(peek, AFL_MAGIC_DOUBLE_MAPLIST1)(f, peek, __VA_ARGS__)
#define AFL_MAGIC_DOUBLE_MAPLIST1(f, x, y, peek, ...) \
f(x, y) AFL_MAGIC_MAPLIST_NEXT(peek, AFL_MAGIC_DOUBLE_MAPLIST0)(f, peek, __VA_ARGS__)
/**
* Applies the function macro `f` to each of the remaining parameters.
*/
#define AFL_MAGIC_MAP(f, ...) \
AFL_MAGIC_IF_ELSE(AFL_MAGIC_HAS_ARGS(__VA_ARGS__))( \
AFL_MAGIC_EVAL(AFL_MAGIC_MAP1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) \
)()
#define AFL_MAGIC_DOUBLE_MAP(f, ...) \
AFL_MAGIC_IF_ELSE(AFL_MAGIC_HAS_ARGS(__VA_ARGS__))( \
AFL_MAGIC_EVAL(AFL_MAGIC_DOUBLE_MAP1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) \
)()
/**
* Applies the function macro `f` to each of the remaining parameters and
* inserts commas between the results.
*/
#define AFL_MAGIC_MAPLIST(f, ...) \
AFL_MAGIC_IF_ELSE(AFL_MAGIC_HAS_ARGS(__VA_ARGS__))( \
AFL_MAGIC_EVAL(AFL_MAGIC_MAPLIST1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) \
)()
#define AFL_MAGIC_DOUBLE_MAPLIST(f, ...) \
AFL_MAGIC_IF_ELSE(AFL_MAGIC_HAS_ARGS(__VA_ARGS__))( \
AFL_MAGIC_EVAL(AFL_MAGIC_DOUBLE_MAPLIST1(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) \
)()
#define AFL_MAGIC_VA_COMMA(...) \
AFL_MAGIC_IF_ELSE(AFL_MAGIC_HAS_ARGS(__VA_ARGS__))( \
AFL_MAGIC_MAPCOMMA __VA_ARGS__ \
)()
/*
Class and vtable macros.
*/
#define AFL_END_STRUCT(...) __VA_ARGS__ };
#define AFL_CLASS_BEGIN(name, parent_type) \
struct name##__fields { \
\
struct parent_type##__fields; \
#define AFL_CLASS_END(name) }; \
\
struct name { \
\
struct name##_vtable* _vptr; \
struct name##__fields; \
\
}; \
typedef struct name name##_t;
#define AFL_VTABLE(name, parent_type, ...) \
struct name##_vtable; \
extern struct name##_vtable name##_vtable_instance; \
\
struct name##_vtable { \
\
struct parent_type##_vtable; \
\
__VA_ARGS__ \
\
AFL_END_STRUCT
#define AFL_LINK_BASE(type) \
._base_vptr = (struct afl_object_vtable*)&type##_vtable_instance
#define AFL_BIND_METHOD(type, name) .name = &type##_##name##__nonvirtual
#define AFL_VTABLE_FOR(name, parent_type) \
struct name##_vtable name##_vtable_instance = { \
\
AFL_LINK_BASE(parent_type), \
\
AFL_END_STRUCT
#define AFL_CLASS(name, parent_type, ...) \
AFL_CLASS_BEGIN(name, parent_type) \
__VA_ARGS__ \
AFL_CLASS_END(name) \
\
AFL_VTABLE(name, parent_type)
#define AFL_VTABLEOF(ptr) ((ptr)->_vptr)
#define AFL_VTABLE_SET(ptr, vtable) (ptr)->_vptr = &vtable
// #define AFL_INSTANCEOF(type, ptr) ((ptr)->v == &type##_vtable_instance)
#define AFL_INSTANCEOF(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 AFL_DYNCAST(type, ptr) (AFL_INSTANCEOF(type, ptr) ? (struct type*)(ptr) : NULL)
/*
Methods wrappers.
*/
#define AFL_END_METHOD(...) __VA_ARGS__ }
#define AFL_DECLARE_OVERRIDE(class_type, base_type, ret_type, name, ...) \
ret_type class_type##_##name##__nonvirtual(struct base_type* AFL_MAGIC_VA_COMMA( AFL_MAGIC_DOUBLE_MAPLIST(AFL_MAGIC_FIRST, __VA_ARGS__) )); \
\
static inline ret_type class_type##_##name(struct class_type* self AFL_MAGIC_VA_COMMA( AFL_MAGIC_DOUBLE_MAPLIST(AFL_MAGIC_FIRST_SECOND, __VA_ARGS__) )) { \
return base_type##_##name((struct base_type*)self AFL_MAGIC_VA_COMMA( AFL_MAGIC_DOUBLE_MAPLIST(AFL_MAGIC_SECOND, __VA_ARGS__) )); \
}
#define AFL_DEFINE_OVERRIDE(class_type, base_type, ret_type, name, ...) \
ret_type class_type##_##name##__nonvirtual(struct base_type* _self AFL_MAGIC_VA_COMMA( AFL_MAGIC_DOUBLE_MAPLIST(AFL_MAGIC_FIRST, __VA_ARGS__) )) { \
\
assert (_self); \
assert (AFL_INSTANCEOF(class_type, _self)); \
struct class_type* self = (struct class_type*)_self; \
\
AFL_END_METHOD
#define AFL_OVERRIDE(class_type, base_type, ret_type, name, ...) \
AFL_DECLARE_OVERRIDE(class_type, base_type, ret_type, name, __VA_ARGS__) \
AFL_DEFINE_OVERRIDE(class_type, base_type, ret_type, name, __VA_ARGS__)
#define AFL_DECLARE_VIRTUAL(class_type, ret_type, name, ...) \
static inline ret_type class_type##_##name(struct class_type* self AFL_MAGIC_VA_COMMA( AFL_MAGIC_DOUBLE_MAPLIST(AFL_MAGIC_FIRST_SECOND, __VA_ARGS__) )) { \
return AFL_VTABLEOF(self)->print(self AFL_MAGIC_VA_COMMA( AFL_MAGIC_DOUBLE_MAPLIST(AFL_MAGIC_SECOND, __VA_ARGS__) )); \
}
// TODO AFL_DECLARE_VIRTUAL_DEFAULT AFL_DEFINE_VIRTUAL_DEFAULT
#define AFL_DECLARE_INIT_MODIFIER_BEGIN(modifier, class_type, ...) \
void class_type##_init##modifier(struct class_type* self AFL_MAGIC_VA_COMMA( AFL_MAGIC_DOUBLE_MAPLIST(AFL_MAGIC_FIRST_SECOND, __VA_ARGS__) )) { \
#define AFL_DECLARE_INIT_BEGIN(class_type, ...) AFL_DECLARE_INIT_MODIFIER_BEGIN(, class_type, __VA_ARGS__)
#define AFL_DECLARE_INIT_END(class_type) \
AFL_VTABLE_SET(self, class_type##_vtable_instance); }
#define AFL_METHOD(class_type, name) class_type##_##name
/// 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;
struct afl_object__fields {
void* _wrapper; // for bindings
};
struct afl_object {
struct afl_object_vtable* _vptr;
struct afl_object__fields;
};
static inline void afl_object_deinit(afl_object_t* self) {
if (AFL_VTABLEOF(self)->deinit)
AFL_VTABLEOF(self)->deinit(self);
}
////////////////////////////////////////////////////////////////////////////////
/// virtual class A
AFL_CLASS(afl_A, afl_object,
int x;
)(
void (*print)(afl_A_t*);
)
AFL_DECLARE_VIRTUAL(afl_A, void, print)
AFL_DECLARE_INIT_MODIFIER_BEGIN(__protected, afl_A, int, x)
self->x = x;
AFL_DECLARE_INIT_END(afl_A)
AFL_OVERRIDE(afl_A, afl_object, void, deinit)(
self->x = 0;
)
// put in C file
AFL_VTABLE_FOR(afl_A, afl_object)(
AFL_BIND_METHOD(afl_A, deinit),
)
/// class B
AFL_CLASS(afl_B, afl_A)()
AFL_DECLARE_INIT_BEGIN(afl_B, int, x)
// call super constructor
afl_A_init__protected((afl_A_t*)self, x);
AFL_DECLARE_INIT_END(afl_B)
AFL_OVERRIDE(afl_B, afl_A, void, print)(
printf("B: %d\n", self->x);
)
// put in C file
AFL_VTABLE_FOR(afl_B, afl_A)(
AFL_BIND_METHOD(afl_A, deinit),
AFL_BIND_METHOD(afl_B, print),
)
int main() {
afl_B_t b;
afl_B_init(&b, 1);
afl_A_t* downcast = (afl_A_t*)&b;
afl_B_print(&b); // B: 1
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment