From 7b2376b72e12e233606cb1524ab822a48b23ee70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=AD=20Bol=C3=ADvar?= Date: Wed, 26 Feb 2020 20:48:05 -0800 Subject: [PATCH] util.h: add MACRO_MAP_CAT() and MACRO_MAP_CAT_N() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is like MACRO_MAP(), but it pastes the results together into a single token. The result is kind of a fold of the ## operator. I wasn't able to figure out a way to implement this using any of the existing macros, so there's some more copy/pasting of handler macros for different numbers of arguments. Signed-off-by: Martí Bolívar --- include/sys/util.h | 58 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/include/sys/util.h b/include/sys/util.h index 0bfe4ec6249..acec541fa98 100644 --- a/include/sys/util.h +++ b/include/sys/util.h @@ -830,6 +830,64 @@ u8_t u8_to_dec(char *buf, u8_t buflen, u8_t value); #define MACRO_MAP_13(macro, a, ...) macro(a)MACRO_MAP_12(macro, __VA_ARGS__,) #define MACRO_MAP_14(macro, a, ...) macro(a)MACRO_MAP_13(macro, __VA_ARGS__,) #define MACRO_MAP_15(macro, a, ...) macro(a)MACRO_MAP_14(macro, __VA_ARGS__,) + +/** + * @brief Mapping macro that pastes results together + * + * Like @ref MACRO_MAP(), but pastes the results together into a + * single token by repeated application of @ref UTIL_CAT(). + * + * For example, with this macro FOO: + * + * #define FOO(x) item_##x##_ + * + * MACRO_MAP_CAT(FOO, a, b, c) expands to the token: + * + * item_a_item_b_item_c_ + * + * @param ... Macro to expand on each argument, followed by its + * arguments. (The macro should take exactly one argument.) + * @return The results of expanding the macro on each argument, all pasted + * together + */ +#define MACRO_MAP_CAT(...) MACRO_MAP_CAT_(__VA_ARGS__) +#define MACRO_MAP_CAT_(...) \ + /* To make sure it works also for 2 arguments in total */ \ + MACRO_MAP_CAT_N(NUM_VA_ARGS_LESS_1(__VA_ARGS__), __VA_ARGS__) + +/** + * @brief Mapping macro that pastes a fixed number of results together + * + * Similar to @ref MACRO_MAP_CAT(), but expects a fixed number of + * arguments. If more arguments are given than are expected, the rest + * are ignored. + * + * @param N Number of arguments to map + * @param ... Macro to expand on each argument, followed by its + * arguments. (The macro should take exactly one argument.) + * @return The results of expanding the macro on each argument, all pasted + * together + */ +#define MACRO_MAP_CAT_N(N, ...) MACRO_MAP_CAT_N_(N, __VA_ARGS__) +#define MACRO_MAP_CAT_N_(N, ...) UTIL_CAT(MACRO_MC_, N)(__VA_ARGS__,) + +#define MACRO_MC_0(...) +#define MACRO_MC_1(m, a, ...) m(a) +#define MACRO_MC_2(m, a, ...) UTIL_CAT(m(a), MACRO_MC_1(m, __VA_ARGS__,)) +#define MACRO_MC_3(m, a, ...) UTIL_CAT(m(a), MACRO_MC_2(m, __VA_ARGS__,)) +#define MACRO_MC_4(m, a, ...) UTIL_CAT(m(a), MACRO_MC_3(m, __VA_ARGS__,)) +#define MACRO_MC_5(m, a, ...) UTIL_CAT(m(a), MACRO_MC_4(m, __VA_ARGS__,)) +#define MACRO_MC_6(m, a, ...) UTIL_CAT(m(a), MACRO_MC_5(m, __VA_ARGS__,)) +#define MACRO_MC_7(m, a, ...) UTIL_CAT(m(a), MACRO_MC_6(m, __VA_ARGS__,)) +#define MACRO_MC_8(m, a, ...) UTIL_CAT(m(a), MACRO_MC_7(m, __VA_ARGS__,)) +#define MACRO_MC_9(m, a, ...) UTIL_CAT(m(a), MACRO_MC_8(m, __VA_ARGS__,)) +#define MACRO_MC_10(m, a, ...) UTIL_CAT(m(a), MACRO_MC_9(m, __VA_ARGS__,)) +#define MACRO_MC_11(m, a, ...) UTIL_CAT(m(a), MACRO_MC_10(m, __VA_ARGS__,)) +#define MACRO_MC_12(m, a, ...) UTIL_CAT(m(a), MACRO_MC_11(m, __VA_ARGS__,)) +#define MACRO_MC_13(m, a, ...) UTIL_CAT(m(a), MACRO_MC_12(m, __VA_ARGS__,)) +#define MACRO_MC_14(m, a, ...) UTIL_CAT(m(a), MACRO_MC_13(m, __VA_ARGS__,)) +#define MACRO_MC_15(m, a, ...) UTIL_CAT(m(a), MACRO_MC_14(m, __VA_ARGS__,)) + /* * The following provides variadic preprocessor macro support to * help eliminate multiple, repetitive function/macro calls. This