From 3a53044198281bbacf5b6070bc57641b193d7f0c Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 20 Apr 2022 22:41:36 +0200 Subject: [PATCH] Add M_EMPLACE macros to enables generic generation of EMPLACE functions --- m-core.h | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/m-core.h b/m-core.h index 5e3a3f05..e9e17cc1 100644 --- a/m-core.h +++ b/m-core.h @@ -1251,6 +1251,17 @@ M_BEGIN_PROTECTED_CODE M_IF_EMPTY(arguments)(action if empty, action if not empty) */ #define M_IF_EMPTY(...) M_IF(M_EMPTY_P(__VA_ARGS__)) + +/* Concatene the two preprocessing token. + * Handle the case where the second argument is empty, in which case + * it returns the first token. + */ +#define M_C_EMPTY(a, b) M_CI_EMPTY(a, b) +#define M_CI_EMPTY(a, b) M_IF_EMPTY(b)(M_CI_EMPTY_B, M_CI_EMPTY_CAT)(a, b) +#define M_CI_EMPTY_B(a, b) a +#define M_CI_EMPTY_CAT(a, b) a ## b + + /* Return 1 if argument is "()" or "(x)" * Test if () or (x) can be transformed into a comma, * and that there is no (toplevel) comma @@ -3895,6 +3906,81 @@ m_core_parse2_enum (const char str[], const char **endptr) M_PAIR_2 d (M_PAIR_1 d, M_PAIR_1 a, M_PAIR_2 a) +/************************************************************/ +/******************* EMPLACE GENERATION ********************/ +/************************************************************/ + +/* Expand to the list of emplace type with their variable name + to use in the function declaration (start with a ,) */ +#define M_EMPLACE_LIST_TYPE_VAR(prefix, emplace_type) \ + M_IF(M_PARENTHESIS_P( emplace_type ))(M_EMPLACE_LIST_TYPE_VAR_MULTI, M_EMPLACE_LIST_TYPE_VAR_SINGLE)(prefix, emplace_type) +#define M_EMPLACE_LIST_TYPE_VAR_MULTI(prefix, emplace_type) \ + M_MAP3(M_EMPLACE_LIST_TYPE_VAR_MULTI_F, prefix, M_ID emplace_type) +#define M_EMPLACE_LIST_TYPE_VAR_MULTI_F(prefix, num, type) \ + , type M_C(prefix, num) +#define M_EMPLACE_LIST_TYPE_VAR_SINGLE(prefix, emplace_type) \ + , emplace_type prefix + + +/* Expand to the list of variable name based on the the declaration with + emplace type to use in the INIT_WITH call (start with a ,) */ +#define M_EMPLACE_LIST_VAR(prefix, emplace_type) \ + M_IF(M_PARENTHESIS_P( emplace_type ))(M_EMPLACE_LIST_VAR_MULTI, M_EMPLACE_LIST_VAR_SINGLE)(prefix, emplace_type) +#define M_EMPLACE_LIST_VAR_MULTI(prefix, emplace_type) \ + , M_MAP2_C( M_C, prefix, M_SEQ(1, M_NARGS emplace_type) ) +#define M_EMPLACE_LIST_VAR_SINGLE(prefix, emplace_type) \ + , prefix + + +/* Call either INIT_WITH with the prefixed arguments used for emplace + or with the user provided init_func */ +#define M_EMPLACE_CALL_FUNC(prefix, init_func, oplist, dest, emplace_type) \ + M_IF(M_KEYWORD_P(INIT_WITH, init_func)) \ + ( \ + /* If INIT_FUNC==INIT_WITH, classic use of INIT_WITH operator */ \ + M_CALL_INIT_WITH(oplist, dest M_EMPLACE_LIST_VAR(prefix, emplace_type) ) \ + , \ + /* Use the user provided init_func instead (with API transformation) */ \ + M_APPLY_API(init_func, oplist, dest M_EMPLACE_LIST_VAR(prefix, emplace_type) ) \ + ) + +/* Generate one or several definitions for the EMPLACE methods + using the operator EMPLACE_TYPE to get the suitable user types + and the user provided macro to expand the function definition. + The user provided macro prototype is + macro(name, name_t, function_name, oplist, init_func, exp_emplace_type) + It is suitable for container with a single type of data within. + */ +#define M_EMPLACE_QUEUE_DEF(name, name_t, function_name, oplist, macro) \ + M_IF(M_TEST_METHOD_ALTER_P(EMPLACE_TYPE, oplist)) \ + (M_EMPLACE_QUEUE_DEF_EXPAND, M_EAT) \ + (name, name_t, function_name, oplist, macro, M_GET_EMPLACE_TYPE oplist) +/* One EMPLACE_TYPE operator is defined ==> Perform the emplace function expansion. + If the emplace type starts with parenthesis, it is only one with multiple args */ +#define M_EMPLACE_QUEUE_DEF_EXPAND(name, name_t, function_name, oplist, macro, emplace_type) \ + M_IF(M_PARENTHESIS_P(emplace_type)) \ + (M_EMPLACE_QUEUE_DEF_SINGLE_EXPAND, M_EMPLACE_QUEUE_DEF_EXPAND_P2) \ + (name, name_t, function_name, oplist, macro, emplace_type) +/* Test if it starts with LIST, in which case, multiple emplace methods have to be defined */ +#define M_EMPLACE_QUEUE_DEF_EXPAND_P2(name, name_t, function_name, oplist, macro, emplace_type) \ + M_IF(M_KEYWORD_P(LIST, emplace_type)) \ + (M_EMPLACE_QUEUE_DEF_LIST_EXPAND, M_EMPLACE_QUEUE_DEF_SINGLE_EXPAND) \ + (name, name_t, function_name, oplist, macro, emplace_type) +/* Define & expand multiple emplace methods */ +#define M_EMPLACE_QUEUE_DEF_LIST_EXPAND(name, name_t, function_name, oplist, macro, emplace_type) \ + M_MAP2(M_EMPLACE_QUEUE_DEF_SUFFIX, (name, name_t, function_name, oplist, macro), M_KEYWORD_TO_VA_ARGS(LIST, emplace_type)) +/* Let the arguments be expanded before calling the definition macro */ +#define M_EMPLACE_QUEUE_DEF_SUFFIX(trio, list) M_EMPLACE_QUEUE_DEF_SUFFIX2(M_ID trio, M_ID list) +/* Let the arguments be expanded before calling the definition macro */ +#define M_EMPLACE_QUEUE_DEF_SUFFIX2(...) M_EMPLACE_QUEUE_DEF_SUFFIX3(__VA_ARGS__) +/* Everything is now proprely expanded. Just call the original macro (with a properly expanded emplace type) */ +#define M_EMPLACE_QUEUE_DEF_SUFFIX3(name, name_t, function_name, oplist, macro, sup_suffix, init_func, ...) \ + macro(name, name_t, M_C_EMPTY(function_name, sup_suffix), oplist, init_func, (__VA_ARGS__) ) +/* Define & expand one emplace method by using the definition macro */ +#define M_EMPLACE_QUEUE_DEF_SINGLE_EXPAND(name, name_t, function_name, oplist, macro, emplace_type) \ + macro(name, name_t, function_name, oplist, INIT_WITH, emplace_type) + + /************************************************************/ /******************* Exponential Backoff ********************/ /************************************************************/