aboutsummaryrefslogtreecommitdiffstats
path: root/Alc/polymorphism.h
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2019-04-07 23:39:04 +0200
committerSven Gothel <[email protected]>2019-04-07 23:39:04 +0200
commit73233ce69919fc19c53ce8663c5b8cc05227f07e (patch)
treef2b6ccc1a14d7c387f33398a44ea4511d7ecb212 /Alc/polymorphism.h
parent8efa4c7ba5ee8eb399d31a9884e45f743d4625ad (diff)
parent99a55c445211fea77af6ab61cbc6a6ec4fbdc9b9 (diff)
Merge branch 'v1.19' of git://repo.or.cz/openal-soft into v1.19v1.19
Diffstat (limited to 'Alc/polymorphism.h')
-rw-r--r--Alc/polymorphism.h105
1 files changed, 105 insertions, 0 deletions
diff --git a/Alc/polymorphism.h b/Alc/polymorphism.h
new file mode 100644
index 00000000..fa31fad2
--- /dev/null
+++ b/Alc/polymorphism.h
@@ -0,0 +1,105 @@
+#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))
+
+#endif /* POLYMORPHISM_H */