From aa3f6e0a8109ab4cc759b23c9feccff9cee4e876 Mon Sep 17 00:00:00 2001 From: Johannes Stoelp Date: Wed, 24 Apr 2024 01:07:55 +0200 Subject: fn-wrapper: initial version of macro magic --- .../2024-04-24-fn-wrapper-macro-magic/wrap-v4.cc | 47 ++++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 content/2024-04-24-fn-wrapper-macro-magic/wrap-v4.cc (limited to 'content/2024-04-24-fn-wrapper-macro-magic/wrap-v4.cc') 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); -- cgit v1.2.3