aboutsummaryrefslogtreecommitdiffstats
path: root/Alc
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2018-01-11 06:32:45 -0800
committerChris Robinson <[email protected]>2018-01-11 06:32:45 -0800
commitf3c9bc114cb1d136fce4e790d6d2721430eb30dc (patch)
tree97d518d92f07360056ec28f090844f0bacc3ce59 /Alc
parentff231b42ff82349d935861e7afcfd4e7a7917471 (diff)
Move the polymorphic/inheritance macros to a separate header
Diffstat (limited to 'Alc')
-rw-r--r--Alc/polymorphism.h108
1 files changed, 108 insertions, 0 deletions
diff --git a/Alc/polymorphism.h b/Alc/polymorphism.h
new file mode 100644
index 00000000..b41ad64b
--- /dev/null
+++ b/Alc/polymorphism.h
@@ -0,0 +1,108 @@
+#ifndef POLYMORPHISM_H
+#define POLYMORPHISM_H
+
+/* Macros to declare inheriting types, and to (down-)cast and up-cast. */
+#define DERIVE_FROM_TYPE(t) t t##_parent
+#define STATIC_CAST(to, obj) (&(obj)->to##_parent)
+#ifdef __GNUC__
+#define STATIC_UPCAST(to, from, obj) __extension__({ \
+ static_assert(__builtin_types_compatible_p(from, __typeof(*(obj))), \
+ "Invalid upcast object from type"); \
+ (to*)((char*)(obj) - offsetof(to, from##_parent)); \
+})
+#else
+#define STATIC_UPCAST(to, from, obj) ((to*)((char*)(obj) - offsetof(to, from##_parent)))
+#endif
+
+/* Defines method forwards, which call the given parent's (T2's) implementation. */
+#define DECLARE_FORWARD(T1, T2, rettype, func) \
+rettype T1##_##func(T1 *obj) \
+{ return T2##_##func(STATIC_CAST(T2, obj)); }
+
+#define DECLARE_FORWARD1(T1, T2, rettype, func, argtype1) \
+rettype T1##_##func(T1 *obj, argtype1 a) \
+{ return T2##_##func(STATIC_CAST(T2, obj), a); }
+
+#define DECLARE_FORWARD2(T1, T2, rettype, func, argtype1, argtype2) \
+rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b) \
+{ return T2##_##func(STATIC_CAST(T2, obj), a, b); }
+
+#define DECLARE_FORWARD3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
+rettype T1##_##func(T1 *obj, argtype1 a, argtype2 b, argtype3 c) \
+{ return T2##_##func(STATIC_CAST(T2, obj), a, b, c); }
+
+/* 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) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj)); }
+
+#define DECLARE_THUNK1(T1, T2, rettype, func, argtype1) \
+static rettype T1##_##T2##_##func(T2 *obj, argtype1 a) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a); }
+
+#define DECLARE_THUNK2(T1, T2, rettype, func, argtype1, argtype2) \
+static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b); }
+
+#define DECLARE_THUNK3(T1, T2, rettype, func, argtype1, argtype2, argtype3) \
+static rettype T1##_##T2##_##func(T2 *obj, argtype1 a, argtype2 b, argtype3 c) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c); }
+
+#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) \
+{ return T1##_##func(STATIC_UPCAST(T1, T2, obj), a, b, c, d); }
+
+/* Defines the default functions used to (de)allocate a polymorphic object. */
+#define DECLARE_DEFAULT_ALLOCATORS(T) \
+static void* T##_New(size_t size) { return al_malloc(16, size); } \
+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 { \
+ _res = T##_New(sizeof(T)); \
+ if(_res) \
+ { \
+ memset(_res, 0, sizeof(T)); \
+ T##_Construct(_res, EXTRACT_NEW_ARGS
+/* Allocate and construct an object, with no arguments. */
+#define NEW_OBJ0(_res, T) do { \
+ _res = T##_New(sizeof(T)); \
+ if(_res) \
+ { \
+ memset(_res, 0, sizeof(T)); \
+ 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. */
+#define SET_VTABLE2(T1, T2, obj) (STATIC_CAST(T2, obj)->vtbl = GET_VTABLE2(T1, T2))
+
+/* Helper to set an object's vtable for a type. */
+#define SET_VTABLE1(T1, obj) ((obj)->vtbl = &(T1##_vtable))
+
+#endif /* POLYMORPHISM_H */