summaryrefslogtreecommitdiffhomepage
path: root/src/vcall.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/vcall.h')
-rw-r--r--src/vcall.h98
1 files changed, 87 insertions, 11 deletions
diff --git a/src/vcall.h b/src/vcall.h
index caee70a..778ba09 100644
--- a/src/vcall.h
+++ b/src/vcall.h
@@ -35,32 +35,108 @@
#define VCALLCONV
#endif
+// black magic argument list maker thingmy, similar to the PPMAGIC_MAP thing,
+// but slightly different, so we get to have all this nonsense twice. not sorry
+
+// note: arg numbering is counting down instead of up because it's easier to
+// treat the vararg macros like a stack, and doesn't actually matter otherwise
+// also note: I just did 16. that should be enough
+#define _VCALL_ARG00()
+#define _VCALL_ARG01(t) typeof(t) a1
+#define _VCALL_ARG02(t1, t2) typeof(t1) a2, typeof(t2) a1
+#define _VCALL_ARG03(t1, t2, t3) typeof(t1) a3, typeof(t2) a2, typeof(t3) a1
+#define _VCALL_ARG04(t1, t2, t3, t4) \
+ typeof(t1) a4, typeof(t2) a3, typeof(t3) a2, typeof(t4) a1
+#define _VCALL_ARG05(t, ...) typeof(t) a5, _VCALL_ARG04(__VA_ARGS__)
+#define _VCALL_ARG06(t, ...) typeof(t) a6, _VCALL_ARG05(__VA_ARGS__)
+#define _VCALL_ARG07(t, ...) typeof(t) a7, _VCALL_ARG06(__VA_ARGS__)
+#define _VCALL_ARG08(t, ...) typeof(t) a8, _VCALL_ARG07(__VA_ARGS__)
+#define _VCALL_ARG09(t, ...) typeof(t) a9, _VCALL_ARG08(__VA_ARGS__)
+#define _VCALL_ARG10(t, ...) typeof(t) a10, _VCALL_ARG09(__VA_ARGS__)
+#define _VCALL_ARG11(t, ...) typeof(t) a11, _VCALL_ARG10(__VA_ARGS__)
+#define _VCALL_ARG12(t, ...) typeof(t) a12, _VCALL_ARG11(__VA_ARGS__)
+#define _VCALL_ARG13(t, ...) typeof(t) a13, _VCALL_ARG12(__VA_ARGS__)
+#define _VCALL_ARG14(t, ...) typeof(t) a14, _VCALL_ARG14(__VA_ARGS__)
+#define _VCALL_ARG15(t, ...) typeof(t) a15, _VCALL_ARG15(__VA_ARGS__)
+#define _VCALL_ARG16(t, ...) typeof(t) a16, _VCALL_ARG16(__VA_ARGS__)
+
+#define _VCALL_ARG_N(x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, \
+ x11, x12, x13, x14, x15, x16, N, ...) \
+ _VCALL_ARG##N
+
+#define _VCALL_ARGLIST(...) \
+ _VCALL_ARG_N(__VA_ARGS__ __VA_OPT__(,) \
+ 16, 15, 14, 13, 12, 11, 10, 09, 08, 07, 06, 05, 04, 03, 02, 01, 00) \
+ (__VA_ARGS__)
+
+// aannd we need these as well...
+#define _VCALL_PASS00()
+#define _VCALL_PASS01() a1
+#define _VCALL_PASS02() a2, a1
+#define _VCALL_PASS03() a3, a2, a1
+#define _VCALL_PASS04() a4, a3, a2, a1
+#define _VCALL_PASS05() a5, _VCALL_PASS04()
+#define _VCALL_PASS06() a6, _VCALL_PASS05()
+#define _VCALL_PASS07() a7, _VCALL_PASS06()
+#define _VCALL_PASS08() a8, _VCALL_PASS07()
+#define _VCALL_PASS09() a9, _VCALL_PASS08()
+#define _VCALL_PASS10() a10, _VCALL_PASS09()
+#define _VCALL_PASS11() a11, _VCALL_PASS10()
+#define _VCALL_PASS12() a12, _VCALL_PASS11()
+#define _VCALL_PASS13() a13, _VCALL_PASS12()
+#define _VCALL_PASS14() a14, _VCALL_PASS13()
+#define _VCALL_PASS15() a15, _VCALL_PASS14()
+#define _VCALL_PASS16() a16, _VCALL_PASS15()
+#define _VCALL_PASS_N(x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, x11, \
+ x12, x13, x14, x15, x16, N, ...) \
+ _VCALL_PASS##N
+
+#define _VCALL_PASSARGS(...) \
+ _VCALL_PASS_N(__VA_ARGS__ __VA_OPT__(,) 16, 15, 14, 13, 12, 11, 10, 09, \
+ 08, 07, 06, 05, 04, 03, 02, 01, 00)()
+
+#define VFUNC(x, name) ((*(name##_func **)(x))[vtidx_##name])
+#define VCALL(x, name, ...) VFUNC(x, name)(x, ##__VA_ARGS__)
+
+// even more magic: return keyword only if not void
+#define _VCALL_RETKW_(x, n, ...) n
+#define _VCALL_RETKW(...) _VCALL_RETKW_(__VA_ARGS__, return,)
+#define _VCALL_RET_void() x, ,
+#define _VCALL_RET(t) _VCALL_RETKW(_VCALL_RET_##t())
+
+// I thought static inline was supposed to prevent unused warnings???
+#if defined(__GNUC__) || defined(__clang__)
+#define _VCALL_UNUSED __attribute__((unused))
+#else
+#define _VCALL_UNUSED
+#endif
+
#define _DECL_VFUNC_DYN(ret, conv, name, ...) \
- /* XXX: GCC extension, seems worthwhile vs having two macros for one thing.
- Replace with __VA_OPT__(,) whenever that gets fully standardised. */ \
- typedef ret (*conv name##_func)(void *this, ##__VA_ARGS__);
+ typedef typeof(ret) (*conv name##_func)(void * __VA_OPT__(,) __VA_ARGS__); \
+ static inline _VCALL_UNUSED typeof(ret) name(void *this __VA_OPT__(,) \
+ _VCALL_ARGLIST(__VA_ARGS__)) { \
+ _VCALL_RET(ret) VCALL(this, name __VA_OPT__(,) \
+ _VCALL_PASSARGS(__VA_ARGS__)); \
+ }
#define _DECL_VFUNC(ret, conv, name, idx, ...) \
enum { vtidx_##name = (idx) }; \
- _DECL_VFUNC_DYN(ret, conv, name, ##__VA_ARGS__)
+ _DECL_VFUNC_DYN(ret, conv, name __VA_OPT__(,) __VA_ARGS__)
/* Define a virtual function with a known index */
#define DECL_VFUNC(ret, name, idx, ...) \
- _DECL_VFUNC(ret, VCALLCONV, name, idx, ##__VA_ARGS__)
+ _DECL_VFUNC(ret, VCALLCONV, name, idx __VA_OPT__(,) __VA_ARGS__)
/* Define a virtual function with a known index, without thiscall convention */
#define DECL_VFUNC_CDECL(ret, name, idx, ...) \
- _DECL_VFUNC(ret, , name, idx, ##__VA_ARGS__)
+ _DECL_VFUNC(ret, , name, idx __VA_OPT__(,) __VA_ARGS__)
/* Define a virtual function with an index defined elsewhere */
#define DECL_VFUNC_DYN(ret, name, ...) \
- _DECL_VFUNC_DYN(ret, VCALLCONV, name, ##__VA_ARGS__)
+ _DECL_VFUNC_DYN(ret, VCALLCONV, name __VA_OPT__(,) __VA_ARGS__)
/* Define a virtual function with an index defined elsewhere, without thiscall */
#define DECL_VFUNC_CDECLDYN(ret, name, ...) \
- _DECL_VFUNC_DYN(ret, , name, ##__VA_ARGS__)
-
-#define VFUNC(x, name) ((*(name##_func **)(x))[vtidx_##name])
-#define VCALL(x, name, ...) VFUNC(x, name)(x, ##__VA_ARGS__)
+ _DECL_VFUNC_DYN(ret, , name __VA_OPT__(,) __VA_ARGS__)
#endif