aboutsummaryrefslogtreecommitdiffhomepage
path: root/content/2024-04-24-fn-wrapper-macro-magic/wrap-v4.cc
diff options
context:
space:
mode:
Diffstat (limited to 'content/2024-04-24-fn-wrapper-macro-magic/wrap-v4.cc')
-rw-r--r--content/2024-04-24-fn-wrapper-macro-magic/wrap-v4.cc47
1 files changed, 47 insertions, 0 deletions
diff --git a/content/2024-04-24-fn-wrapper-macro-magic/wrap-v4.cc b/content/2024-04-24-fn-wrapper-macro-magic/wrap-v4.cc
new file mode 100644
index 0000000..ea5e41e
--- /dev/null
+++ b/content/2024-04-24-fn-wrapper-macro-magic/wrap-v4.cc
@@ -0,0 +1,47 @@
+// Get Nth argument.
+#define CPP_NTH(_0, _1, _2, _3, n, ...) n
+// Get number of arguments (uses gcc/clang extension for empty argument).
+#define CPP_ARGC(...) CPP_NTH(_0, ##__VA_ARGS__, 3, 2, 1, 0)
+
+// Utility to concatenate preprocessor tokens.
+#define CONCAT2(lhs, rhs) lhs##rhs
+#define CONCAT1(lhs, rhs) CONCAT2(lhs, rhs)
+
+#define ARGS0()
+#define ARGS1() a0
+#define ARGS2() a1, ARGS1()
+#define ARGS3() a2, ARGS2()
+
+// Invoke correct ARGSn macro depending on #arguments.
+#define ARGS(...) CONCAT1(ARGS, CPP_ARGC(__VA_ARGS__))()
+
+#define TYPEDARGS0()
+#define TYPEDARGS1(ty) ty a0
+#define TYPEDARGS2(ty, ...) ty a1, TYPEDARGS1(__VA_ARGS__)
+#define TYPEDARGS3(ty, ...) ty a2, TYPEDARGS2(__VA_ARGS__)
+
+// Invoke correct TYPEDARGSn macro depending on #arguments.
+#define TYPEDARGS(...) CONCAT1(TYPEDARGS, CPP_ARGC(__VA_ARGS__))(__VA_ARGS__)
+
+#define MOCK_WRAPPER_IMPL(ret, fn) \
+ /* do common work */ \
+ static ret wrap_##fn(...);
+
+// Utility to generate wrapper boilerplate.
+#define WRAP(ret, fn, ...) \
+ MOCK_WRAPPER_IMPL(ret, fn) \
+ \
+ extern "C" ret fn(TYPEDARGS(__VA_ARGS__)) { \
+ return wrap_##fn(ARGS(__VA_ARGS__)); \
+ }
+
+WRAP(int, foo, const char*)
+WRAP(int, bar, const char*, const char*)
+WRAP(int, baz, char, int, unsigned)
+
+// -- TESTS --------------------------------------------------------------------
+
+static_assert(CPP_ARGC() == 0);
+static_assert(CPP_ARGC(int) == 1);
+static_assert(CPP_ARGC(int, int) == 2);
+static_assert(CPP_ARGC(int, int, int) == 3);