2018-01-11 06:32:45 -08:00
|
|
|
#ifndef POLYMORPHISM_H
|
|
|
|
#define POLYMORPHISM_H
|
|
|
|
|
|
|
|
/* Defines method forwards, which call the given parent's (T2's) implementation. */
|
|
|
|
#define DECLARE_FORWARD(T1, T2, rettype, func) \
|
|
|
|
rettype T1##_##func(T1 *obj) \
|
2018-12-27 14:27:35 -08:00
|
|
|
{ return T2##_##func(static_cast<T2*>(obj)); }
|
2018-01-11 06:32:45 -08:00
|
|
|
|
|
|
|
#define DECLARE_FORWARD1(T1, T2, rettype, func, argtype1) \
|
|
|
|
rettype T1##_##func(T1 *obj, argtype1 a) \
|
2018-12-27 14:27:35 -08:00
|
|
|
{ return T2##_##func(static_cast<T2*>(obj), a); }
|
2018-01-11 06:32:45 -08:00
|
|
|
|
|
|
|
#define DECLARE_FORWARD2(T1, T2, rettype, func, argtype1, argtype2) \
|
|
|
|
rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b) \
|
2018-12-27 14:27:35 -08:00
|
|
|
{ return T2##_##func(static_cast<T2*>(obj), a, b); }
|
2018-01-11 06:32:45 -08:00
|
|
|
|
|
|
|
#define DECLARE_FORWARD3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
|
|
|
|
rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b, argtype3 c) \
|
2018-12-27 14:27:35 -08:00
|
|
|
{ return T2##_##func(static_cast<T2*>(obj), a, b, c); }
|
2018-01-11 06:32:45 -08:00
|
|
|
|
|
|
|
/* Defines method thunks, functions that call to the child's method. */
|
|
|
|
#define DECLARE_THUNK(T1, T2, rettype, func) \
|
|
|
|
static rettype T1##_##T2##_##func(T2 *obj) \
|
2018-12-27 14:27:35 -08:00
|
|
|
{ return T1##_##func(static_cast<T1*>(obj)); }
|
2018-01-11 06:32:45 -08:00
|
|
|
|
|
|
|
#define DECLARE_THUNK1(T1, T2, rettype, func, argtype1) \
|
|
|
|
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a) \
|
2018-12-27 14:27:35 -08:00
|
|
|
{ return T1##_##func(static_cast<T1*>(obj), a); }
|
2018-01-11 06:32:45 -08:00
|
|
|
|
|
|
|
#define DECLARE_THUNK2(T1, T2, rettype, func, argtype1, argtype2) \
|
|
|
|
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b) \
|
2018-12-27 14:27:35 -08:00
|
|
|
{ return T1##_##func(static_cast<T1*>(obj), a, b); }
|
2018-01-11 06:32:45 -08:00
|
|
|
|
|
|
|
#define DECLARE_THUNK3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
|
|
|
|
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \
|
2018-12-27 14:27:35 -08:00
|
|
|
{ return T1##_##func(static_cast<T1*>(obj), a, b, c); }
|
2018-01-11 06:32:45 -08:00
|
|
|
|
|
|
|
#define DECLARE_THUNK4(T1, T2, rettype, func, argtype1, argtype2, argtype3, argtype4) \
|
|
|
|
static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c, argtype4 d) \
|
2018-12-27 14:27:35 -08:00
|
|
|
{ return T1##_##func(static_cast<T1*>(obj), a, b, c, d); }
|
2018-01-11 06:32:45 -08:00
|
|
|
|
|
|
|
/* Defines the default functions used to (de)allocate a polymorphic object. */
|
|
|
|
#define DECLARE_DEFAULT_ALLOCATORS(T) \
|
2018-11-02 18:48:08 -07:00
|
|
|
static void* T##_New(size_t size) { return al_calloc(16, size); } \
|
2018-01-11 06:32:45 -08:00
|
|
|
static void T##_Delete(void *ptr) { al_free(ptr); }
|
|
|
|
|
|
|
|
|
|
|
|
/* Helper to extract an argument list for virtual method calls. */
|
|
|
|
#define EXTRACT_VCALL_ARGS(...) __VA_ARGS__))
|
|
|
|
|
|
|
|
/* Call a "virtual" method on an object, with arguments. */
|
|
|
|
#define V(obj, func) ((obj)->vtbl->func((obj), EXTRACT_VCALL_ARGS
|
|
|
|
/* Call a "virtual" method on an object, with no arguments. */
|
|
|
|
#define V0(obj, func) ((obj)->vtbl->func((obj) EXTRACT_VCALL_ARGS
|
|
|
|
|
|
|
|
|
|
|
|
/* Helper to extract an argument list for NEW_OBJ calls. */
|
|
|
|
#define EXTRACT_NEW_ARGS(...) __VA_ARGS__); \
|
|
|
|
} \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
/* Allocate and construct an object, with arguments. */
|
|
|
|
#define NEW_OBJ(_res, T) do { \
|
2018-10-28 17:42:20 -07:00
|
|
|
_res = (T*)T##_New(sizeof(T)); \
|
2018-01-11 06:32:45 -08:00
|
|
|
if(_res) \
|
|
|
|
{ \
|
|
|
|
T##_Construct(_res, EXTRACT_NEW_ARGS
|
|
|
|
/* Allocate and construct an object, with no arguments. */
|
|
|
|
#define NEW_OBJ0(_res, T) do { \
|
2018-10-28 17:42:20 -07:00
|
|
|
_res = (T*)T##_New(sizeof(T)); \
|
2018-01-11 06:32:45 -08:00
|
|
|
if(_res) \
|
|
|
|
{ \
|
|
|
|
T##_Construct(_res EXTRACT_NEW_ARGS
|
|
|
|
|
|
|
|
/* Destructs and deallocate an object. */
|
|
|
|
#define DELETE_OBJ(obj) do { \
|
|
|
|
if((obj) != NULL) \
|
|
|
|
{ \
|
|
|
|
V0((obj),Destruct)(); \
|
|
|
|
V0((obj),Delete)(); \
|
|
|
|
} \
|
|
|
|
} while(0)
|
|
|
|
|
|
|
|
|
|
|
|
/* Helper to get a type's vtable thunk for a child type. */
|
|
|
|
#define GET_VTABLE2(T1, T2) (&(T1##_##T2##_vtable))
|
|
|
|
/* Helper to set an object's vtable thunk for a child type. Used when constructing an object. */
|
2018-12-27 14:27:35 -08:00
|
|
|
#define SET_VTABLE2(T1, T2, obj) (static_cast<T2*>(obj)->vtbl = GET_VTABLE2(T1, T2))
|
2018-01-11 06:32:45 -08:00
|
|
|
|
|
|
|
#endif /* POLYMORPHISM_H */
|