diff options
author | Johannes Stoelp <johannes.stoelp@gmail.com> | 2024-04-24 01:07:55 +0200 |
---|---|---|
committer | Johannes Stoelp <johannes.stoelp@gmail.com> | 2024-04-24 01:07:55 +0200 |
commit | aa3f6e0a8109ab4cc759b23c9feccff9cee4e876 (patch) | |
tree | f31e5f8541fbc02fe00a1fe2bbd030d444dd4c75 /content/2024-04-24-fn-wrapper-macro-magic/wrap-v4.cc | |
parent | bc6907e58ba86da8c30a29c98b998832c4b260d3 (diff) | |
download | blog-aa3f6e0a8109ab4cc759b23c9feccff9cee4e876.tar.gz blog-aa3f6e0a8109ab4cc759b23c9feccff9cee4e876.zip |
fn-wrapper: initial version of macro magic
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.cc | 47 |
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); |