From 85ea92d83bcb2fd0f5641c57d4ba22a58fcce9d9 Mon Sep 17 00:00:00 2001 From: Patrick Pelissier Date: Wed, 11 May 2022 21:30:29 +0200 Subject: [PATCH] Review of m-core.h * Add control of MSVC preprocessor * Add comments * Remove useless evaluation pass * Rewrite some evaluation pass to be faster. --- m-core.h | 239 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 139 insertions(+), 100 deletions(-) diff --git a/m-core.h b/m-core.h index c84a7331..59e827ae 100644 --- a/m-core.h +++ b/m-core.h @@ -209,6 +209,11 @@ # define M_ADDRESS_SANITIZER 1 #endif +/* For visual C++, we need a standard compliant C99/C++11 */ +#if defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL +# error Miss option '/Zc:preprocessor' to enable a standard-compliant C99/C++11 preprocessor. +#endif + /* * Do not create the following symbols that are defined in GLIBC malloc.h * M_MXFAST @@ -345,7 +350,7 @@ M_BEGIN_PROTECTED_CODE /* Terminate the compilation of the current unit with an error message. - The error is classified as error + The error parameter is a C token which classifies the error with an optional message detailling the error. Either use C11 to get a proper message, or at least a good hint in C99. error shall be a C name, msg a string. @@ -353,7 +358,8 @@ M_BEGIN_PROTECTED_CODE a garbage of error due to incorrect code generation in the methods expansion. NOTE: Some implementation claims to be C11 (default mode) but fails - to deliver a working assert.h with static_assert. + to deliver a working assert.h with static_assert so we test for the + explicity precense of the macro static_assert. */ #if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && defined(static_assert)) || defined(__cplusplus) # define M_STATIC_FAILURE(error, msg) static_assert(false, #error ": " msg); @@ -363,7 +369,7 @@ M_BEGIN_PROTECTED_CODE /* Test at compile time if the given condition is true. - The error is classified as error + The error parameter is a C token which classifies the error with an optional message detailling the error. NOTE: Use bitfield to be compatible with most compilers (so that it properly displays 'error' on the command line @@ -388,7 +394,8 @@ M_BEGIN_PROTECTED_CODE /****************** Preprocessing Times Macro ******************/ /***************************************************************/ -/* Maximum number of argument which can be handled by this header. +/* Maximum number of argument which can be at least handled + by the macros of this header. Can be increased for future release of this header. */ #define M_MAX_NB_ARGUMENT 52 @@ -570,11 +577,10 @@ M_BEGIN_PROTECTED_CODE #define M_DEC_52 51 -/* Add two integers. +/* Add two integers with both integers from [0 to M_MAX_NB_ARGUMENT[ Generated by: for i in $(seq 0 52) ; do printf "#define M_ADDI_%d(n) " $i ; for j in $(seq 1 $i) ; do printf "M_INC(";done ; printf "n" ; for j in $(seq 1 $i) ; do printf ")" ;done ; printf "\n" ; done */ -#define M_ADD(x,y) M_ADDI(M_C(M_ADDI_, y), x) -#define M_ADDI(f,n) f(n) +#define M_ADD(x,y) M_C(M_ADDI_, y)(x) #define M_ADDI_0(n) n #define M_ADDI_1(n) M_INC(n) #define M_ADDI_2(n) M_INC(M_INC(n)) @@ -630,11 +636,10 @@ M_BEGIN_PROTECTED_CODE #define M_ADDI_52(n) M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(M_INC(n)))))))))))))))))))))))))))))))))))))))))))))))))))) -/* Substract two integers. +/* Substract two integers with both integers from [0 to M_MAX_NB_ARGUMENT[ Generated by: for i in $(seq 0 52) ; do printf "#define M_SUBI_%d(n) " $i ; for j in $(seq 1 $i) ; do printf "M_DEC(";done ; printf "n" ; for j in $(seq 1 $i) ; do printf ")" ;done ; printf "\n" ; done */ -#define M_SUB(x,y) M_SUBI(M_C(M_SUBI_, y), x) -#define M_SUBI(f,n) f(n) +#define M_SUB(x,y) M_C(M_SUBI_, y)(x) #define M_SUBI_0(n) n #define M_SUBI_1(n) M_DEC(n) #define M_SUBI_2(n) M_DEC(M_DEC(n)) @@ -690,7 +695,7 @@ M_BEGIN_PROTECTED_CODE #define M_SUBI_52(n) M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(M_DEC(n)))))))))))))))))))))))))))))))))))))))))))))))))))) -/* NOTEQUAL(val1,val2) with val from [0 to 52[ +/* NOTEQUAL(val1,val2) with val from [0 to M_MAX_NB_ARGUMENT[ Return 1 or 0 if val1=val2 */ #define M_NOTEQUAL_0_0 0 @@ -748,8 +753,7 @@ M_BEGIN_PROTECTED_CODE #define M_NOTEQUAL_52_52 0 #define M_NOTEQUAL(x,y) M_BOOL(M_C4(M_NOTEQUAL_, x, _, y)) - -/* EQUAL(val1,val2) +/* EQUAL(val1,val2) with val from [0 to M_MAX_NB_ARGUMENT[ Return 1 if val1=val2 or 0 Example: M_EQUAL(1,2) --> 0 */ @@ -773,11 +777,15 @@ M_BEGIN_PROTECTED_CODE /* Return the nth argument of a VA_ARGS. + - M_RET_ARG lets the VA_ARGS been evaluated, and returns the argument. + - M_RETI_ARG returns the argument. + - M_RET_ARG takes n as argument, evaluate the arguments, and returns the 'n' argument. + NOTE: A comma is added at the end in M_RET_ARG in order to avoid error if the number of + argument is exactly (in which case, otherwise the __VA_ARGS__ will be non existent). Generated by: for i in $(seq 1 53 ) ; do printf "#define M_RETI_ARG%d(" $i; for j in $(seq 1 $i) ; do printf "_%d, " $j ; done ; printf "...) _%d\n#define M_RET_ARG%d(...) M_RETI_ARG%d(__VA_ARGS__,)\n\n" $i $i $i ; done */ -#define M_RETI_ARG(f, ...) f(__VA_ARGS__) -#define M_RET_ARG(n, ...) M_RETI_ARG(M_C(M_RET_ARG, n), __VA_ARGS__) +#define M_RET_ARG(n, ...) M_C(M_RET_ARG, n)(__VA_ARGS__) #define M_RETI_ARG1(_1, ...) _1 #define M_RET_ARG1(...) M_RETI_ARG1(__VA_ARGS__,) @@ -1008,8 +1016,16 @@ M_BEGIN_PROTECTED_CODE #define M_RET_ARG76(...) M_RETI_ARG76(__VA_ARGS__,) +/* Return the value of the "arglist" associated to the given index (zero based). + An "arglist" is a VA_ARGS between parenthesis. + EXAMPLE: M_GET_AT((f_0,f_1,f_2),1) returns f_1 + */ +#define M_GET_AT(arglist, index) M_RET_ARG(M_INC(index), M_GETI_AT_ID arglist) +#define M_GETI_AT_ID(...) __VA_ARGS__ + + /* For a pair of argument (arg0, arg1), return either the first or the second. - NOTE: Needed in case where M_RET_ARGn cannot be used */ + NOTE: Needed in case where M_RET_ARG cannot be used */ #define M_PAIR_1(a,b) a #define M_PAIR_2(a,b) b @@ -1018,9 +1034,7 @@ M_BEGIN_PROTECTED_CODE Generated by: for i in $(seq 0 52) ; do printf "#define M_SKIPI_%d(" $i ; for j in $(seq 1 $i) ; do printf "_%d, " $j ; done ; printf "...) __VA_ARGS__\n"; done */ -#define M_SKIP_ARGS(n, ...) M_SKIPI_APPLY(M_C(M_SKIPI_, n), __VA_ARGS__) -#define M_SKIPI_APPLY(f, ...) f(__VA_ARGS__) - +#define M_SKIP_ARGS(n, ...) M_C(M_SKIPI_, n)(__VA_ARGS__) #define M_SKIPI_0(...) __VA_ARGS__ #define M_SKIPI_1(_1, ...) __VA_ARGS__ #define M_SKIPI_2(_1, _2, ...) __VA_ARGS__ @@ -1079,9 +1093,7 @@ M_BEGIN_PROTECTED_CODE /* Keep the nth first arguments of a VA_ARGS Generated by: for i in $(seq 0 52) ; do printf "#define M_KEEPI_%d(" $i ; for j in $(seq 1 $i) ; do printf "_%d, " $j ; done ; printf "...) " ; for j in $(seq 1 $(($i - 1))) ; do printf "_%d, " $j; done ; if test "$i" -ne 0 ; then printf "_$i" ; fi ; printf "\n" ; done */ -#define M_KEEP_ARGS(n, ...) M_KEEPI_APPLY(M_C(M_KEEPI_, n), __VA_ARGS__) -#define M_KEEPI_APPLY(f, ...) f(__VA_ARGS__) - +#define M_KEEP_ARGS(n, ...) M_C(M_KEEPI_, n)(__VA_ARGS__) #define M_KEEPI_0(...) #define M_KEEPI_1(_1, ...) _1 #define M_KEEPI_2(_1, _2, ...) _1, _2 @@ -1138,8 +1150,7 @@ M_BEGIN_PROTECTED_CODE /* Keep the medium characters of a sequence */ -#define M_MID_ARGS(first, len, ...) M_MIDI_APPLY(M_KEEP_ARGS,len, M_SKIP_ARGS(first, __VA_ARGS__)) -#define M_MIDI_APPLY(f, ...) f (__VA_ARGS__) +#define M_MID_ARGS(first, len, ...) M_KEEP_ARGS(len, M_SKIP_ARGS(first, __VA_ARGS__)) /* Revert the VA_ARGS given as parameter @@ -1202,31 +1213,31 @@ M_BEGIN_PROTECTED_CODE #define M_REVERSE_52(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,_51,_52) _52,_51,_50,_49,_48,_47,_46,_45,_44,_43,_42,_41,_40,_39,_38,_37,_36,_35,_34,_33,_32,_31,_30,_29,_28,_27,_26,_25,_24,_23,_22,_21,_20,_19,_18,_17,_16,_15,_14,_13,_12,_11,_10,_9,_8,_7,_6,_5,_4,_3,_2,_1 -/* Return the value of the "arglist" associated to the given index (zero based). - EXAMPLE: M_GET_AT((f_0,f_1,f_2),1) returns f_1 - */ -#define M_GET_AT(arglist, index) M_GETI_AT0(M_C(M_RET_ARG, M_INC(index)), arglist) -#define M_GETI_AT0(func, arglist) func ( M_ID arglist , ERROR_INDEX_OUT_OF_BOUND ) - - /* Convert an integer or a symbol into 0 (if 0) or 1 (if not 0). + NOTE: It shall exactly the C-preprocessing token '0'. 1 if symbol unknown */ #define M_TOBOOLI_0 1, 0, #define M_BOOL(x) M_RET_ARG2(M_C(M_TOBOOLI_, x), 1, useless) /* M_IF Macro : Perform an IF test at preprocessing time. - The condition is assumed to be true if unkown. - USAGE - M_IF(condition)(Block if true, Block if false) - Example: M_IF(0)(true_action, false_action) --> false_action */ + The condition is assumed to be true if unknown. + USAGE: + M_IF(condition)(Block if true, Block if false) + Example: + M_IF(0)(true_action, false_action) --> false_action + NOTE: true_action and false_action can recursively contain M_IF + but not 'condition'. + */ #define M_IFI_0(true_c, ...) __VA_ARGS__ #define M_IFI_1(true_c, ...) true_c #define M_IF(c) M_C(M_IFI_, M_BOOL(c)) -/* Return 1 if there is a comma inside the VA_ARGS. - 0 otherwise. */ +/* Return 1 if there is a comma inside the VA_ARGS, 0 otherwise. + NOTE: this is one of the lowest level check performed + (all other high level checks depend on it). +*/ #if defined(__clang__) && defined(_MSC_VER) // CLANG on windows has a non compliant preprocessor (but not the one for Linux / Mac). Workaround for it (with minor issue) #define M_COMMA_P(...) M_RET_ARG76(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, useless) @@ -1237,6 +1248,7 @@ M_BEGIN_PROTECTED_CODE /* Return 1 if the argument is empty (aka ''), 0 otherwise. + This is quite hard to detect properly. Handle: EMPTY_P(), EMPTY_P(x), EMPTY_P(()) and EMPTY_P(,) and EMPTY_P(f) with #define f() 2,3 */ #define M_EMPTYI_DETECT(...) , #define M_EMPTYI_P_C1(...) M_COMMA_P(M_EMPTYI_DETECT __VA_ARGS__ () ) @@ -1254,7 +1266,7 @@ M_BEGIN_PROTECTED_CODE /* Concatene the two preprocessing token. * Handle the case where the second argument is empty, in which case - * it returns the first token. + * it returns the first token without concatenation. */ #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) @@ -1263,16 +1275,16 @@ M_BEGIN_PROTECTED_CODE /* Return 1 if argument is "()" or "(x)" - * Test if () or (x) can be transformed into a comma, - * and that there is no (toplevel) comma - * and that there is nothing beyond the parenthesis. + * Test if () or (x) can be transformed into a comma (primary check for parenthesis), + * and that there is no (toplevel) comma (remove false positive) + * and that there is nothing beyond the parenthesis (remove false positive) + * A simple check could only contain M_PARENTHESISI_DETECT1, but there will be false positives. */ #define M_PARENTHESISI_DETECT1(...) , -#define M_PARENTHESISI_DETECT2(...) #define M_PARENTHESIS_P(...) \ M_AND3(M_COMMA_P(M_PARENTHESISI_DETECT1 __VA_ARGS__), \ M_INV(M_COMMA_P(__VA_ARGS__)), \ - M_EMPTY_P(M_PARENTHESISI_DETECT2 __VA_ARGS__)) + M_EMPTY_P(M_EAT __VA_ARGS__)) /* Return 1 if argument type or variable or function is the keyword. @@ -1282,7 +1294,12 @@ M_BEGIN_PROTECTED_CODE It cannot start with a special character */ #define M_KEYWORD_P(refFunc, testedFunc) \ M_COMMA_P(M_C4(M_PATTERN_, refFunc, _, testedFunc)) -/* The different special recognized patterns: */ + +/* The different special patterns recognized by M_KEYWORD_P + * Each recognized keyword shall define a macro like this: + * M_PATTERN_ ## keyword ## _ ## keyword + * And this macro shall expands to the comma separator. + */ #define M_PATTERN_and_and , #define M_PATTERN_or_or , #define M_PATTERN_sum_sum , @@ -1318,11 +1335,19 @@ M_BEGIN_PROTECTED_CODE #define M_PATTERN_INIT_WITH_INIT_WITH , #define M_PATTERN____ , + /* Extract the VA ARGS of a keyword function like. Transform 'LIST( a, b, c)' into 'a, b, c' for keyword=LIST It shall start with KEYWORD (M_KEYWORD_P shall return 1). */ #define M_KEYWORD_TO_VA_ARGS(keyword, list) M_C4(M_EAT_KEYWORD_, keyword, _, list) + +/* The different special patterns recognized by M_KEYWORD_TO_VA_ARGS + * Each recognized keyword shall define a macro function like this: + * M_EAT_KEYWORD_ ## keyword ## _ ## keyword (...) + * And this macro shall expands to __VA_ARGS__ + * CONSTRAINT: Theses keywords shall be a sub-list of the keywords supported by M_KEYWORD_P + */ #define M_EAT_KEYWORD_MAP_MAP(...) __VA_ARGS__ #define M_EAT_KEYWORD_LIST_LIST(...) __VA_ARGS__ #define M_EAT_KEYWORD_SEQ_SEQ(...) __VA_ARGS__ @@ -1348,8 +1373,7 @@ M_BEGIN_PROTECTED_CODE forcing the pre-processor to expand the given macro a lot of times. NOTE: There can be only one EVAL macro per complete macro-evaluation pass. As such the given macro cannot contain M_EVAL itself, - limiting a lot the usefullness of this macro. - Moreover, it is quite slow. + NOTE: Using recursivity impacts compilation time performance. */ #define M_EVAL(...) M_EVAL1(M_EVAL1(M_EVAL1(__VA_ARGS__))) #define M_EVAL1(...) M_EVAL2(M_EVAL2(M_EVAL2(__VA_ARGS__))) @@ -1358,20 +1382,27 @@ M_BEGIN_PROTECTED_CODE #define M_EVAL4(...) M_EVAL0(M_EVAL0(M_EVAL0(__VA_ARGS__))) #define M_EVAL0(...) __VA_ARGS__ + /* Apply Macro : - It allows that a won't be evaluated until all arguments of 'a' have been already evaluated */ + * It delays the expansion of the macro function 'a' until the VA_ARGS itself is evaluated. + * It is needed when the evaluation process changes the numbers of arguments. + * For example, when merging 2 arglists using "M_OPFLAT M_MERGE_ARGLIST" + */ #define M_APPLY(a, ...) a (__VA_ARGS__) -/* MAP: apply the given macro to all arguments. - It is a non recursive version that is much faster than the recursive one. - Example: - M_MAP(f,a, b, c) ==> f(a) f(b) f(c) */ -/* Generated by: - for i in $(seq 1 52) ; do printf "#define M_MAP_%d(f" $i ; for j in $(seq 1 $i) ; do printf ", _%d" $j ; done ; printf ") " ; for j in $(seq 1 $i) ; do printf "f(_%d) " $j ; done ; printf "\n"; done -*/ -#define M_MAP(f, ...) M_MAPI(M_C(M_MAP_, M_NARGS(__VA_ARGS__)), f, __VA_ARGS__) -#define M_MAPI(F,...) F (__VA_ARGS__) +/* MAP: apply the given macro to all arguments. + NOTE: Perform a first step evalution so that the given VA_ARGS is fullu evaluated + and expanded before further preprocessing. This helps if the argument given to M_MAP + perform a construction of the VA_ARGS as its argument. + NOTE: It is a non recursive version that is much faster than the recursive one. + Example: + M_MAP(f,a, b, c) ==> f(a) f(b) f(c) + Generated by: + for i in $(seq 1 52) ; do printf "#define M_MAPI_%d(f" $i ; for j in $(seq 1 $i) ; do printf ", _%d" $j ; done ; printf ") " ; for j in $(seq 1 $i) ; do printf "f(_%d) " $j ; done ; printf "\n"; done +*/ +#define M_MAP(...) M_MAP_0(__VA_ARGS__) +#define M_MAP_0(f, ...) M_C(M_MAP_, M_NARGS(__VA_ARGS__))(f, __VA_ARGS__) #define M_MAP_1(f, _1) f(_1) #define M_MAP_2(f, _1, _2) f(_1) f(_2) #define M_MAP_3(f, _1, _2, _3) f(_1) f(_2) f(_3) @@ -1428,9 +1459,8 @@ M_BEGIN_PROTECTED_CODE /* Map a macro to all given arguments with one additional fixed data (non recursive version) */ /* Example: M_MAP2(f, data, a, b, c) ==> f(data,a) f(data,b) f(data,c) */ -#define M_MAP2(f, d, ...) M_MAP2I(M_C(M_MAP2I_, M_NARGS(__VA_ARGS__)), f, d, __VA_ARGS__) -#define M_MAP2I(F,...) F (__VA_ARGS__) - +#define M_MAP2(...) M_MAP2I_0(__VA_ARGS__) +#define M_MAP2I_0(f, d, ...) M_C(M_MAP2I_, M_NARGS(__VA_ARGS__))(f, d, __VA_ARGS__) #define M_MAP2I_1(f, d, _1) f(d, _1) #define M_MAP2I_2(f, d, _1, _2) f(d, _1) f(d, _2) #define M_MAP2I_3(f, d, _1, _2, _3) f(d, _1) f(d, _2) f(d, _3) @@ -1484,16 +1514,15 @@ M_BEGIN_PROTECTED_CODE #define M_MAP2I_51(f, d, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51) f(d, _1) f(d, _2) f(d, _3) f(d, _4) f(d, _5) f(d, _6) f(d, _7) f(d, _8) f(d, _9) f(d, _10) f(d, _11) f(d, _12) f(d, _13) f(d, _14) f(d, _15) f(d, _16) f(d, _17) f(d, _18) f(d, _19) f(d, _20) f(d, _21) f(d, _22) f(d, _23) f(d, _24) f(d, _25) f(d, _26) f(d, _27) f(d, _28) f(d, _29) f(d, _30) f(d, _31) f(d, _32) f(d, _33) f(d, _34) f(d, _35) f(d, _36) f(d, _37) f(d, _38) f(d, _39) f(d, _40) f(d, _41) f(d, _42) f(d, _43) f(d, _44) f(d, _45) f(d, _46) f(d, _47) f(d, _48) f(d, _49) f(d, _50) f(d, _51) #define M_MAP2I_52(f, d, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52) f(d, _1) f(d, _2) f(d, _3) f(d, _4) f(d, _5) f(d, _6) f(d, _7) f(d, _8) f(d, _9) f(d, _10) f(d, _11) f(d, _12) f(d, _13) f(d, _14) f(d, _15) f(d, _16) f(d, _17) f(d, _18) f(d, _19) f(d, _20) f(d, _21) f(d, _22) f(d, _23) f(d, _24) f(d, _25) f(d, _26) f(d, _27) f(d, _28) f(d, _29) f(d, _30) f(d, _31) f(d, _32) f(d, _33) f(d, _34) f(d, _35) f(d, _36) f(d, _37) f(d, _38) f(d, _39) f(d, _40) f(d, _41) f(d, _42) f(d, _43) f(d, _44) f(d, _45) f(d, _46) f(d, _47) f(d, _48) f(d, _49) f(d, _50) f(d, _51) f(d, _52) -/* Duplicate for GET_METHOD as it may be called in context where a M_MAP2 is in progress (for oplist). +/* Duplicate of M_MAP2 for GET_METHOD as it may be called in context where a M_MAP2 is in progress (for oplist). NOTE: Increase number of arguments to 76 due to the number of available methods. + NOTE: Don't perform another step of evaluation (not needed in the usage context) NOTE: Rewrite with another approach much more verbose but also much faster for the compiler. This kind of approach seems ugly, but is in fact the fast one. Generated by the following command: for i in $(seq 1 52) ; do printf "#define M_MAP2B_%d(f, d" $i ; for j in $(seq 1 $i) ; do printf ", _%d" $j ; done ; printf ") " ; for j in $(seq 1 $i) ; do printf "f(d, _%d) " $j ; done ; printf "\n"; done */ -#define M_MAP2B(f, d, ...) M_MAP2BI(M_C(M_MAP2B_, M_NARGS(__VA_ARGS__)), f, d, __VA_ARGS__) -#define M_MAP2BI(F,...) F (__VA_ARGS__) - +#define M_MAP2B(f, d, ...) M_C(M_MAP2B_, M_NARGS(__VA_ARGS__))(f, d, __VA_ARGS__) #define M_MAP2B_1(f, d, _1) f(d, _1) #define M_MAP2B_2(f, d, _1, _2) f(d, _1) f(d, _2) #define M_MAP2B_3(f, d, _1, _2, _3) f(d, _1) f(d, _2) f(d, _3) @@ -1570,14 +1599,15 @@ M_BEGIN_PROTECTED_CODE #define M_MAP2B_74(f, d, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74) f(d, _1) f(d, _2) f(d, _3) f(d, _4) f(d, _5) f(d, _6) f(d, _7) f(d, _8) f(d, _9) f(d, _10) f(d, _11) f(d, _12) f(d, _13) f(d, _14) f(d, _15) f(d, _16) f(d, _17) f(d, _18) f(d, _19) f(d, _20) f(d, _21) f(d, _22) f(d, _23) f(d, _24) f(d, _25) f(d, _26) f(d, _27) f(d, _28) f(d, _29) f(d, _30) f(d, _31) f(d, _32) f(d, _33) f(d, _34) f(d, _35) f(d, _36) f(d, _37) f(d, _38) f(d, _39) f(d, _40) f(d, _41) f(d, _42) f(d, _43) f(d, _44) f(d, _45) f(d, _46) f(d, _47) f(d, _48) f(d, _49) f(d, _50) f(d, _51) f(d, _52) f(d, _53) f(d, _54) f(d, _55) f(d, _56) f(d, _57) f(d, _58) f(d, _59) f(d, _60) f(d, _61) f(d, _62) f(d, _63) f(d, _64) f(d, _65) f(d, _66) f(d, _67) f(d, _68) f(d, _69) f(d, _70) f(d, _71) f(d, _72) f(d, _73) f(d, _74) #define M_MAP2B_75(f, d, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, _65, _66, _67, _68, _69, _70, _71, _72, _73, _74, _75) f(d, _1) f(d, _2) f(d, _3) f(d, _4) f(d, _5) f(d, _6) f(d, _7) f(d, _8) f(d, _9) f(d, _10) f(d, _11) f(d, _12) f(d, _13) f(d, _14) f(d, _15) f(d, _16) f(d, _17) f(d, _18) f(d, _19) f(d, _20) f(d, _21) f(d, _22) f(d, _23) f(d, _24) f(d, _25) f(d, _26) f(d, _27) f(d, _28) f(d, _29) f(d, _30) f(d, _31) f(d, _32) f(d, _33) f(d, _34) f(d, _35) f(d, _36) f(d, _37) f(d, _38) f(d, _39) f(d, _40) f(d, _41) f(d, _42) f(d, _43) f(d, _44) f(d, _45) f(d, _46) f(d, _47) f(d, _48) f(d, _49) f(d, _50) f(d, _51) f(d, _52) f(d, _53) f(d, _54) f(d, _55) f(d, _56) f(d, _57) f(d, _58) f(d, _59) f(d, _60) f(d, _61) f(d, _62) f(d, _63) f(d, _64) f(d, _65) f(d, _66) f(d, _67) f(d, _68) f(d, _69) f(d, _70) f(d, _71) f(d, _72) f(d, _73) f(d, _74) f(d, _75) -/* Map a macro to all given arguments with two additional fixed data (non recursive version): - one of the parameter is given and one numerical which is the argument number. */ -/* Example: M_MAP3(f, data, a, b, c) ==> f(data,1,a) f(data,2,b) f(data,3,c) */ -#define M_MAP3(f, d, ...) M_MAP3I(M_C(M_MAP3I_, M_NARGS(__VA_ARGS__)), f, d, __VA_ARGS__) -#define M_MAP3I(F,...) F (__VA_ARGS__) -/* Generated by the following command: +/* Map a macro to all given arguments with two additional fixed data (non recursive version): + one of the parameter is given and one numerical which is the argument number. + Example: + M_MAP3(f, data, a, b, c) ==> f(data,1,a) f(data,2,b) f(data,3,c) + Generated by the following command: for i in $(seq 1 52) ; do printf "#define M_MAP3I_%d(f, d" $i ; for j in $(seq 1 $i) ; do printf ", _%d" $j ; done ; printf ") " ; for j in $(seq 1 $i) ; do printf "f(d, %d, _%d) " $j $j ; done ; printf "\n"; done */ +#define M_MAP3(...) M_MAP3I_0(__VA_ARGS__) +#define M_MAP3I_0(f, d, ...) M_C(M_MAP3I_, M_NARGS(__VA_ARGS__))(f, d, __VA_ARGS__) #define M_MAP3I_1(f, d, _1) f(d, 1, _1) #define M_MAP3I_2(f, d, _1, _2) f(d, 1, _1) f(d, 2, _2) #define M_MAP3I_3(f, d, _1, _2, _3) f(d, 1, _1) f(d, 2, _2) f(d, 3, _3) @@ -1633,7 +1663,7 @@ M_BEGIN_PROTECTED_CODE -/* Map a macro to all given pair of arguments (Using recursivity) */ +/* Map a macro to all given pair of arguments (Using recursivity) (OBSOLETE) */ /* Example: M_MAP_PAIR(f, a, b, c, d) ==> f(a,b) f(c,d) */ #define M_MAP_PAIR_L0_INDIRECT() M_MAP_PAIR_L0 #define M_MAP_PAIR_L0(f, ...) M_IF_NARGS_EQ2(__VA_ARGS__)( f(__VA_ARGS__) , M_MAP_PAIR_L1(f, __VA_ARGS__)) @@ -1642,13 +1672,14 @@ M_BEGIN_PROTECTED_CODE /* Map a macro to all given arguments and reduce all theses computation - with another reduce macro */ -/* Example: M_REDUCE(f, g, a, b, c) ==> g( f(a), g( f(b), f(c)) */ -/* Generated by: - for i in $(seq 1 52) ; do printf "#define M_REDUCEI1_%d(f, g" $i ; for j in $(seq 1 $i) ; do printf ", _%d" $j ; done ; printf ") "; for j in $(seq 1 $(( $i - 1 )) ) ; do printf "g(f(_%d), " $j; done ; printf "f(_%d" $i; for j in $(seq 1 $i); do printf ")"; done ; printf "\n"; done + with another reduce macro. + Example: + M_REDUCE(f, g, a, b, c) ==> g( f(a), g( f(b), f(c)) + Generated by: + for i in $(seq 1 52) ; do printf "#define M_REDUCEI1_%d(f, g" $i ; for j in $(seq 1 $i) ; do printf ", _%d" $j ; done ; printf ") "; for j in $(seq 1 $(( $i - 1 )) ) ; do printf "g(f(_%d), " $j; done ; printf "f(_%d" $i; for j in $(seq 1 $i); do printf ")"; done ; printf "\n"; done */ -#define M_REDUCE(f, g, ...) M_REDUCEI1_0(M_C(M_REDUCEI1_, M_NARGS(__VA_ARGS__)), f, g, __VA_ARGS__) -#define M_REDUCEI1_0(F, ...) F(__VA_ARGS__) +#define M_REDUCE(...) M_REDUCEI1_0(__VA_ARGS__) +#define M_REDUCEI1_0(f, g, ...) M_C(M_REDUCEI1_, M_NARGS(__VA_ARGS__))(f, g, __VA_ARGS__) #define M_REDUCEI1_1(f, g, _1) f(_1) #define M_REDUCEI1_2(f, g, _1, _2) g(f(_1), f(_2)) #define M_REDUCEI1_3(f, g, _1, _2, _3) g(f(_1), g(f(_2), f(_3))) @@ -1705,12 +1736,13 @@ M_BEGIN_PROTECTED_CODE /* Map a macro to all given arguments and reduce all theses computation with another reduce macro with an argument: - M_REDUCE2(f, g, data, a, b, c) ==> g( f(data,a), g( f(data, b), f(data, c))) + Example: + M_REDUCE2(f, g, data, a, b, c) ==> g( f(data,a), g( f(data, b), f(data, c))) Generated by: - for i in $(seq 1 52) ; do printf "#define M_REDUCEI2_%d(f,g,d," $i ; for j in $(seq 1 $(($i - 1))) ; do printf "_%d, " $j ; done ; printf "_%d) " $i ; for j in $(seq 1 $(($i - 1))) ; do printf "g(f(d, _%d), " $j ; done ; printf "f(d, _%d)" $i ; for j in $(seq 1 $(( $i - 1 ))); do printf ")" ; done ; printf "\n" ; done + for i in $(seq 1 52) ; do printf "#define M_REDUCEI2_%d(f,g,d," $i ; for j in $(seq 1 $(($i - 1))) ; do printf "_%d, " $j ; done ; printf "_%d) " $i ; for j in $(seq 1 $(($i - 1))) ; do printf "g(f(d, _%d), " $j ; done ; printf "f(d, _%d)" $i ; for j in $(seq 1 $(( $i - 1 ))); do printf ")" ; done ; printf "\n" ; done */ -#define M_REDUCE2(f, g, d, ...) M_REDUCEI2_0(M_C(M_REDUCEI2_, M_NARGS(__VA_ARGS__)), f, g, d, __VA_ARGS__) -#define M_REDUCEI2_0(F, ...) F(__VA_ARGS__) +#define M_REDUCE2(...) M_REDUCEI2_0(__VA_ARGS__) +#define M_REDUCEI2_0(f, g, d, ...) M_C(M_REDUCEI2_, M_NARGS(__VA_ARGS__))(f, g, d, __VA_ARGS__) #define M_REDUCEI2_1(f,g,d,_1) f(d, _1) #define M_REDUCEI2_2(f,g,d,_1, _2) g(f(d, _1), f(d, _2)) #define M_REDUCEI2_3(f,g,d,_1, _2, _3) g(f(d, _1), g(f(d, _2), f(d, _3))) @@ -1767,12 +1799,13 @@ M_BEGIN_PROTECTED_CODE /* Map a macro to all given arguments and reduce all theses computation with another reduce macro with an argument and a counter: - M_REDUCE3(f, g, data, a, b, c) ==> g( f(data,1,a), g( f(data, 2, b), f(data, 3, c))) + Example: + M_REDUCE3(f, g, data, a, b, c) ==> g( f(data,1,a), g( f(data, 2, b), f(data, 3, c))) Generated by: - for i in $(seq 1 52) ; do printf "#define M_REDUCEI3_%d(f,g,d," $i ; for j in $(seq 1 $(($i - 1))) ; do printf "_%d, " $j ; done ; printf "_%d) " $i ; for j in $(seq 1 $(($i - 1))) ; do printf "g(f(d, %d, _%d), " $j $j ; done ; printf "f(d, %d, _%d)" $i $i ; for j in $(seq 1 $(( $i - 1 ))); do printf ")" ; done ; printf "\n" ; done + for i in $(seq 1 52) ; do printf "#define M_REDUCEI3_%d(f,g,d," $i ; for j in $(seq 1 $(($i - 1))) ; do printf "_%d, " $j ; done ; printf "_%d) " $i ; for j in $(seq 1 $(($i - 1))) ; do printf "g(f(d, %d, _%d), " $j $j ; done ; printf "f(d, %d, _%d)" $i $i ; for j in $(seq 1 $(( $i - 1 ))); do printf ")" ; done ; printf "\n" ; done */ -#define M_REDUCE3(f, g, d, ...) M_REDUCEI3_0(M_C(M_REDUCEI3_, M_NARGS(__VA_ARGS__)), f, g, d, __VA_ARGS__) -#define M_REDUCEI3_0(F, ...) F(__VA_ARGS__) +#define M_REDUCE3(...) M_REDUCEI3_0(__VA_ARGS__) +#define M_REDUCEI3_0(f, g, d, ...) M_C(M_REDUCEI3_, M_NARGS(__VA_ARGS__))(f, g, d, __VA_ARGS__) #define M_REDUCEI3_1(f,g,d,_1) f(d, 1, _1) #define M_REDUCEI3_2(f,g,d,_1, _2) g(f(d, 1, _1), f(d, 2, _2)) #define M_REDUCEI3_3(f,g,d,_1, _2, _3) g(f(d, 1, _1), g(f(d, 2, _2), f(d, 3, _3))) @@ -1844,11 +1877,11 @@ M_BEGIN_PROTECTED_CODE -/* Sequence of numerical */ -/* Example: - M_SEQ(init,end)==>init, init+1, ...end - M_MAP(f, M_SEQ(init, end)) ==> f(init) f(init+1) .... f(end) - M_MAP2(f, d, M_SEQ(init, end)) +/* Sequence of numerical + Example: + M_SEQ(init,end)==>init, init+1, ...end + M_MAP(f, M_SEQ(init, end)) ==> f(init) f(init+1) .... f(end) + M_MAP2(f, d, M_SEQ(init, end)) */ #define M_SEQ(init, end) M_MID_ARGS(init, M_INC(M_SUB(end, init)), 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52) @@ -1880,7 +1913,7 @@ M_BEGIN_PROTECTED_CODE /* Return the HEAD element of a VA_ARGS */ #define M_HEAD(x, ...) x -/* Return the HEAD element of the tail of a VA_ARGS */ +/* Return the second HEAD element of a VA_ARGS */ #define M_HEAD_2(x, y, ...) y /* Return the tail sublist of the VA_ARGS (removing the HEAD) */ @@ -1899,12 +1932,13 @@ M_BEGIN_PROTECTED_CODE #define M_CAT_ARGLIST(a, b) \ M_IF_EMPTY(a)(b, M_IF_EMPTY(b)(a,( M_REMOVE_PARENTHESIS (a) , M_REMOVE_PARENTHESIS (b)))) + /* Merge two arglists 'a' and 'b' (a1, a2, a3) and (b1, b2, b3) ==> ( (a1, b1) , (b1, b2), (a3, b3) ) They shall be non empty and of the same size. (internal macro) Generated by: - for i in $(seq 52) ; do printf "#define M_MERGE_ARGLIST_%d_%d(" $i $i ; for j in $(seq 1 $i) ; do printf "a%d, " $j ; done ; for j in $(seq 1 $i) ; do printf "b%d" $j ; if test $i != $j ; then printf ", " ; fi ; done ; printf ") " ; for j in $(seq 1 $i) ; do printf "(a%d, b%d) " $j $j ; if (test $i != $j ) ; then printf ", " ; fi ; done ; printf "\n" ; done + for i in $(seq 52) ; do printf "#define M_MERGE_ARGLIST_%d_%d(" $i $i ; for j in $(seq 1 $i) ; do printf "a%d, " $j ; done ; for j in $(seq 1 $i) ; do printf "b%d" $j ; if test $i != $j ; then printf ", " ; fi ; done ; printf ") " ; for j in $(seq 1 $i) ; do printf "(a%d, b%d) " $j $j ; if (test $i != $j ) ; then printf ", " ; fi ; done ; printf "\n" ; done */ #define M_MERGE_ARGLIST(a, b) ( M_APPLY( M_C4(M_MERGE_ARGLIST_, M_NARGS a, _, M_NARGS b), M_MERGE_ARGLIST_ID a, M_MERGE_ARGLIST_ID b) ) #define M_MERGE_ARGLIST_ID(...) __VA_ARGS__ @@ -1970,7 +2004,10 @@ M_BEGIN_PROTECTED_CODE #define M_REMOVE_PARENTHESIS_3(...) __VA_ARGS__ -/* Return the input (delay evaluation) */ +/* Return the input (delay evaluation). + WARNING: Cannot be used by internal macros as it may appear in such cases + in recursive context, preventing expansion. Only top level macros can use it. + */ #define M_ID(...) __VA_ARGS__ @@ -2011,15 +2048,17 @@ M_BEGIN_PROTECTED_CODE #define M_IF_FUNCOBJ(a) M_IF(M_FUNCOBJ_IS_NOT_DEFINED)( ,a) -/* Helper macro to redefine a function with a default values: - Give the number of expected arguments, the value list of the +/* Helper macro to redefine a function with a default value: + + Give the number of expected arguments, the value list of the default argument, and the arguments. It will complete the arguments with the value of the default argument to complete up to 'expected' arguments. USAGE: - M_DEFAULT_ARGS(expected_num_of_args, (list_of_default_values), given_arguments...) + M_DEFAULT_ARGS(expected_num_of_args, (list_of_default_values), given_arguments...) Example: - #define f(...) f(M_DEFAULT_ARGS(4, (0, 1, NULL), __VA_ARGS__)) + extern int f(int x, int y = 0, int z = 1, const char *p = NULL); + ==> + #define f(...) f(M_DEFAULT_ARGS(4, (0, 1, NULL), __VA_ARGS__)) */ #define M_DEFAULTI_ARGS2(numArgs, numExpected, value, ...) \ __VA_ARGS__ \ @@ -2883,7 +2922,7 @@ static inline size_t m_core_cstr_hash(const char str[]) /* From an oplist - an unorded list of methods : like "INIT(mpz_init),CLEAR(mpz_clear),SET(mpz_set)" - Return the given method in the oplist or the default method. - Example: + Example: M_GET_METHOD(INIT, my_default, INIT(mpz_init),CLEAR(mpz_clear),SET(mpz_set)) --> mpz_init M_GET_METHOD(INIT, my_default, CLEAR(mpz_clear),SET(mpz_set)) --> my_default */ #define M_GET_METHOD(method, method_default, ...) \ @@ -3168,7 +3207,7 @@ static inline size_t m_core_cstr_hash(const char str[]) /* Define the no default function that generates a compiler error - if the method is expanded. + if the method is expanded. */ #define M_NO_DEFAULT(...) \ M_STATIC_FAILURE(M_LIB_MISSING_METHOD, \ @@ -3225,7 +3264,7 @@ static inline size_t m_core_cstr_hash(const char str[]) - inst is a number which is incremented for each use of this macro within the named container. - type is the type to test - - oplist of the oplist to test to. + - oplist of the oplist to test to. */ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L #define M_CHECK_COMPATIBLE_OPLIST(name, inst, type, oplist) \ @@ -4208,7 +4247,7 @@ typedef struct m_serial_write_interface_s { m_serial_return_code_t (*write_boolean)(m_serial_write_t,const bool data); m_serial_return_code_t (*write_integer)(m_serial_write_t,const long long data, const size_t size_of_type); m_serial_return_code_t (*write_float)(m_serial_write_t, const long double data, const size_t size_of_type); - m_serial_return_code_t (*write_string)(m_serial_write_t,const char data[], size_t len); + m_serial_return_code_t (*write_string)(m_serial_write_t,const char data[], size_t len); m_serial_return_code_t (*write_array_start)(m_serial_local_t, m_serial_write_t, const size_t number_of_elements); m_serial_return_code_t (*write_array_next)(m_serial_local_t, m_serial_write_t); m_serial_return_code_t (*write_array_end)(m_serial_local_t, m_serial_write_t);