From 6ef9936e248eef750a507a8ab6749f55d8e4a5d5 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Sun, 19 Aug 2018 08:28:17 +0200 Subject: [PATCH] Fix issue of recusrive definition of TUPLE using GLOBAL oplist: There was a recursive call of M_REDUCE2 that fails to expand properly on its second invocation Rewrite fully how global oplists are implemented: it performs a first pass to expand the oplists, and the a separate pass to define the functions. This enables to separate the pass, and use M_REDUCE2 in both. --- m-tuple.h | 158 ++++++++++++++++++++------------------------ tests/test-mtuple.c | 4 ++ 2 files changed, 74 insertions(+), 88 deletions(-) diff --git a/m-tuple.h b/m-tuple.h index 2c002510..a14ce847 100644 --- a/m-tuple.h +++ b/m-tuple.h @@ -30,43 +30,8 @@ /* Define the tuple type and functions. USAGE: TUPLE_DEF2(name, [(field1, type1[, oplist1]), (field2, type2[, oplist2]), ...] ) */ -#define TUPLE_DEF2(name, ...) \ - TUPLE_DEFINE_TYPE(name, __VA_ARGS__) \ - TUPLE_DEFINE_ENUM(name, __VA_ARGS__) \ - TUPLE_DEFINE_INIT(name, __VA_ARGS__) \ - TUPLE_DEFINE_INIT_SET(name, __VA_ARGS__) \ - TUPLE_DEFINE_INIT_SET2(name, __VA_ARGS__) \ - TUPLE_DEFINE_SET(name, __VA_ARGS__) \ - TUPLE_DEFINE_SET2(name, __VA_ARGS__) \ - TUPLE_DEFINE_CLEAR(name, __VA_ARGS__) \ - TUPLE_DEFINE_GETTER(name, __VA_ARGS__) \ - TUPLE_DEFINE_SETTER(name, __VA_ARGS__) \ - M_IF(TUPLE_ALL_CMP(__VA_ARGS__)) \ - (TUPLE_DEFINE_CMP(name, __VA_ARGS__),) \ - M_IF(TUPLE_ALL_CMP(__VA_ARGS__)) \ - (TUPLE_DEFINE_CMP_ORDER(name, __VA_ARGS__),) \ - TUPLE_DEFINE_CMP_FIELD(name, __VA_ARGS__) \ - M_IF(TUPLE_ALL_HASH(__VA_ARGS__)) \ - (TUPLE_DEFINE_HASH(name, __VA_ARGS__),) \ - M_IF(TUPLE_ALL_EQUAL(__VA_ARGS__)) \ - (TUPLE_DEFINE_EQUAL(name, __VA_ARGS__),) \ - M_IF(TUPLE_ALL_GET_STR(__VA_ARGS__)) \ - (TUPLE_DEFINE_GET_STR(name, __VA_ARGS__),) \ - M_IF(TUPLE_ALL_OUT_STR(__VA_ARGS__)) \ - (TUPLE_DEFINE_OUT_STR(name, __VA_ARGS__),) \ - M_IF(TUPLE_ALL_IN_STR(__VA_ARGS__)) \ - (TUPLE_DEFINE_IN_STR(name, __VA_ARGS__),) \ - M_IF(TUPLE_ALL_PARSE_STR(__VA_ARGS__)) \ - (TUPLE_DEFINE_PARSE_STR(name, __VA_ARGS__),) \ - M_IF(TUPLE_ALL_INIT_MOVE(__VA_ARGS__)) \ - (TUPLE_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \ - M_IF(TUPLE_ALL_MOVE(__VA_ARGS__)) \ - (TUPLE_DEFINE_MOVE(name, __VA_ARGS__),) \ - M_IF(TUPLE_ALL_SWAP(__VA_ARGS__)) \ - (TUPLE_DEFINE_SWAP(name, __VA_ARGS__),) \ - M_IF(TUPLE_ALL_CLEAN(__VA_ARGS__)) \ - (TUPLE_DEFINE_CLEAN(name, __VA_ARGS__),) - +#define TUPLE_DEF2(name, ...) \ + TUPLEI_DEF2_A( (name, TUPLEI_INJECT_GLOBAL(__VA_ARGS__)) ) /* Define the oplist of a tuple. USAGE: TUPLE_OPLIST(name[, oplist of the first type, ...]) */ @@ -104,62 +69,79 @@ namespace m_tuple { /********************************** INTERNAL ************************************/ +#define TUPLEI_INJECT_GLOBAL(...) \ + M_MAP_C(TUPLEI_INJECT_OPLIST_A, __VA_ARGS__) + +#define TUPLEI_INJECT_OPLIST_A( duo_or_trio ) \ + TUPLEI_INJECT_OPLIST_B duo_or_trio + +#define TUPLEI_INJECT_OPLIST_B( f, ... ) \ + M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)), (f, __VA_ARGS__) ) + +#define TUPLEI_DEF2_A(...) \ + TUPLEI_DEF2_B __VA_ARGS__ + +#define TUPLEI_DEF2_B(name, ...) \ + TUPLE_DEFINE_TYPE(name, __VA_ARGS__) \ + TUPLE_DEFINE_ENUM(name, __VA_ARGS__) \ + TUPLE_DEFINE_INIT(name, __VA_ARGS__) \ + TUPLE_DEFINE_INIT_SET(name, __VA_ARGS__) \ + TUPLE_DEFINE_INIT_SET2(name, __VA_ARGS__) \ + TUPLE_DEFINE_SET(name, __VA_ARGS__) \ + TUPLE_DEFINE_SET2(name, __VA_ARGS__) \ + TUPLE_DEFINE_CLEAR(name, __VA_ARGS__) \ + TUPLE_DEFINE_GETTER(name, __VA_ARGS__) \ + TUPLE_DEFINE_SETTER(name, __VA_ARGS__) \ + M_IF(TUPLE_ALL_CMP(__VA_ARGS__)) \ + (TUPLE_DEFINE_CMP(name, __VA_ARGS__),) \ + M_IF(TUPLE_ALL_CMP(__VA_ARGS__)) \ + (TUPLE_DEFINE_CMP_ORDER(name, __VA_ARGS__),) \ + TUPLE_DEFINE_CMP_FIELD(name, __VA_ARGS__) \ + M_IF(TUPLE_ALL_HASH(__VA_ARGS__)) \ + (TUPLE_DEFINE_HASH(name, __VA_ARGS__),) \ + M_IF(TUPLE_ALL_EQUAL(__VA_ARGS__)) \ + (TUPLE_DEFINE_EQUAL(name, __VA_ARGS__),) \ + M_IF(TUPLE_ALL_GET_STR(__VA_ARGS__)) \ + (TUPLE_DEFINE_GET_STR(name, __VA_ARGS__),) \ + M_IF(TUPLE_ALL_OUT_STR(__VA_ARGS__)) \ + (TUPLE_DEFINE_OUT_STR(name, __VA_ARGS__),) \ + M_IF(TUPLE_ALL_IN_STR(__VA_ARGS__)) \ + (TUPLE_DEFINE_IN_STR(name, __VA_ARGS__),) \ + M_IF(TUPLE_ALL_PARSE_STR(__VA_ARGS__)) \ + (TUPLE_DEFINE_PARSE_STR(name, __VA_ARGS__),) \ + M_IF(TUPLE_ALL_INIT_MOVE(__VA_ARGS__)) \ + (TUPLE_DEFINE_INIT_MOVE(name, __VA_ARGS__),) \ + M_IF(TUPLE_ALL_MOVE(__VA_ARGS__)) \ + (TUPLE_DEFINE_MOVE(name, __VA_ARGS__),) \ + M_IF(TUPLE_ALL_SWAP(__VA_ARGS__)) \ + (TUPLE_DEFINE_SWAP(name, __VA_ARGS__),) \ + M_IF(TUPLE_ALL_CLEAN(__VA_ARGS__)) \ + (TUPLE_DEFINE_CLEAN(name, __VA_ARGS__),) + #define TUPLE_ORDER_CONVERT(name, x) M_C(name, M_C(TUPLE_ORDER_CONVERT_, x)) #define TUPLE_ORDER_CONVERT_ASC(x) M_C3(_,x,_value) #define TUPLE_ORDER_CONVERT_DSC(x) M_C3(_,x,_value)*-1 /* Get the field name, the type, the oplist or the methods based on the tuple (field, type, oplist) */ -#define TUPLE_GET_FIELD2(f,t,o) f -#define TUPLE_GET_TYPE2(f,t,o) t -#define TUPLE_GET_OPLIST2(f,t,o) o -#define TUPLE_GET_INIT2(f,t,o) M_GET_INIT o -#define TUPLE_GET_INIT_SET2(f,t,o) M_GET_INIT_SET o -#define TUPLE_GET_INIT_MOVE2(f,t,o) M_GET_INIT_MOVE o -#define TUPLE_GET_MOVE2(f,t,o) M_GET_MOVE o -#define TUPLE_GET_SET2(f,t,o) M_GET_SET o -#define TUPLE_GET_CLEAR2(f,t,o) M_GET_CLEAR o -#define TUPLE_GET_CMP2(f,t,o) M_GET_CMP o -#define TUPLE_GET_HASH2(f,t,o) M_GET_HASH o -#define TUPLE_GET_EQUAL2(f,t,o) M_GET_EQUAL o -#define TUPLE_GET_STR2(f,t,o) M_GET_GET_STR o -#define TUPLE_GET_OUT_STR2(f,t,o) M_GET_OUT_STR o -#define TUPLE_GET_IN_STR2(f,t,o) M_GET_IN_STR o -#define TUPLE_GET_PARSE_STR2(f,t,o) M_GET_PARSE_STR o -#define TUPLE_GET_SWAP2(f,t,o) M_GET_SWAP o -#define TUPLE_GET_CLEAN2(f,t,o) M_GET_CLEAN o - -/* Transform (f,t) into (f,t,oplist) or (f,t,o) into (f,t,o). - USAGE: - TUPLEI_EVAL(GET_MACRO, tuple) - */ -#define TUPLEI_EVAL_FIELD(f, ...) \ - M_IF_NARGS_EQ1(__VA_ARGS__)( (f, __VA_ARGS__, M_GLOBAL_OPLIST_OR_DEF(__VA_ARGS__)), (f, __VA_ARGS__) ) -#define TUPLEI_EVAL2(f, a) f a -#define TUPLEI_EVAL(f, a) TUPLEI_EVAL2(f, TUPLEI_EVAL_FIELD a) - -/* Get the field name, the type, the oplist or the methods - based on the tuple (field, type, oplist) or the typle (field, type) - In the last case, it get the oplist from a global one or a default one. -*/ -#define TUPLE_GET_FIELD(...) TUPLEI_EVAL(TUPLE_GET_FIELD2, (__VA_ARGS__)) -#define TUPLE_GET_TYPE(...) TUPLEI_EVAL(TUPLE_GET_TYPE2, (__VA_ARGS__)) -#define TUPLE_GET_OPLIST(...) TUPLEI_EVAL(TUPLE_GET_OPLIST2, (__VA_ARGS__)) -#define TUPLE_GET_INIT(...) TUPLEI_EVAL(TUPLE_GET_INIT2, (__VA_ARGS__)) -#define TUPLE_GET_INIT_SET(...) TUPLEI_EVAL(TUPLE_GET_INIT_SET2,(__VA_ARGS__)) -#define TUPLE_GET_INIT_MOVE(...) TUPLEI_EVAL(TUPLE_GET_INIT_MOVE2,(__VA_ARGS__)) -#define TUPLE_GET_MOVE(...) TUPLEI_EVAL(TUPLE_GET_MOVE2,(__VA_ARGS__)) -#define TUPLE_GET_SET(...) TUPLEI_EVAL(TUPLE_GET_SET2,(__VA_ARGS__)) -#define TUPLE_GET_CLEAR(...) TUPLEI_EVAL(TUPLE_GET_CLEAR2,(__VA_ARGS__)) -#define TUPLE_GET_CMP(...) TUPLEI_EVAL(TUPLE_GET_CMP2,(__VA_ARGS__)) -#define TUPLE_GET_HASH(...) TUPLEI_EVAL(TUPLE_GET_HASH2,(__VA_ARGS__)) -#define TUPLE_GET_EQUAL(...) TUPLEI_EVAL(TUPLE_GET_EQUAL2,(__VA_ARGS__)) -#define TUPLE_GET_STR(...) TUPLEI_EVAL(TUPLE_GET_STR2,(__VA_ARGS__)) -#define TUPLE_GET_OUT_STR(...) TUPLEI_EVAL(TUPLE_GET_OUT_STR2,(__VA_ARGS__)) -#define TUPLE_GET_IN_STR(...) TUPLEI_EVAL(TUPLE_GET_IN_STR2,(__VA_ARGS__)) -#define TUPLE_GET_PARSE_STR(...) TUPLEI_EVAL(TUPLE_GET_PARSE_STR2,(__VA_ARGS__)) -#define TUPLE_GET_SWAP(...) TUPLEI_EVAL(TUPLE_GET_SWAP2,(__VA_ARGS__)) -#define TUPLE_GET_CLEAN(...) TUPLEI_EVAL(TUPLE_GET_CLEAN2,(__VA_ARGS__)) +#define TUPLE_GET_FIELD(f,t,o) f +#define TUPLE_GET_TYPE(f,t,o) t +#define TUPLE_GET_OPLIST(f,t,o) o +#define TUPLE_GET_INIT(f,t,o) M_GET_INIT o +#define TUPLE_GET_INIT_SET(f,t,o) M_GET_INIT_SET o +#define TUPLE_GET_INIT_MOVE(f,t,o) M_GET_INIT_MOVE o +#define TUPLE_GET_MOVE(f,t,o) M_GET_MOVE o +#define TUPLE_GET_SET(f,t,o) M_GET_SET o +#define TUPLE_GET_CLEAR(f,t,o) M_GET_CLEAR o +#define TUPLE_GET_CMP(f,t,o) M_GET_CMP o +#define TUPLE_GET_HASH(f,t,o) M_GET_HASH o +#define TUPLE_GET_EQUAL(f,t,o) M_GET_EQUAL o +#define TUPLE_GET_STR(f,t,o) M_GET_GET_STR o +#define TUPLE_GET_OUT_STR(f,t,o) M_GET_OUT_STR o +#define TUPLE_GET_IN_STR(f,t,o) M_GET_IN_STR o +#define TUPLE_GET_PARSE_STR(f,t,o) M_GET_PARSE_STR o +#define TUPLE_GET_SWAP(f,t,o) M_GET_SWAP o +#define TUPLE_GET_CLEAN(f,t,o) M_GET_CLEAN o #define TUPLE_DEFINE_TYPE(name, ...) \ typedef struct M_C(name, _s) { \ @@ -434,7 +416,7 @@ namespace m_tuple { #define TUPLE_TEST_METHOD2_P(method, f, t, op) \ M_TEST_METHOD_P(method, op) #define TUPLE_TEST_METHOD_P(method, trio) \ - M_APPLY(TUPLE_TEST_METHOD2_P, method, TUPLEI_EVAL(M_OPFLAT, trio)) + M_APPLY(TUPLE_TEST_METHOD2_P, method, M_OPFLAT trio) #define TUPLE_ALL_CMP(...) \ M_REDUCE2(TUPLE_TEST_METHOD_P, M_AND, CMP, __VA_ARGS__) diff --git a/tests/test-mtuple.c b/tests/test-mtuple.c index 22f1b16b..43932eff 100644 --- a/tests/test-mtuple.c +++ b/tests/test-mtuple.c @@ -61,6 +61,10 @@ TUPLE_DEF2(rtuple, (name, string_t)) #define M_OPL_rtuple_t() TUPLE_OPLIST(rtuple, M_OPL_pair_str_t(), STRING_OPLIST) +TUPLE_DEF2(rtuple2, (name, string_t), (value, int)) +#define M_OPL_rtuple2_t() TUPLE_OPLIST(rtuple2, STRING_OPLIST, M_DEFAULT_OPLIST) + +TUPLE_DEF2(rtuple3, (name, string_t), (ituple2, rtuple2_t), (ituple, rtuple_t) ) static void check_swap(void) {