diff options
author | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-05-13 14:20:04 -0600 |
---|---|---|
committer | Luke T. Shumaker <lukeshu@lukeshu.com> | 2025-05-15 14:43:58 -0600 |
commit | b47070eef9384bf4463e8886902beb1d6b3f053a (patch) | |
tree | 6baf07e1620567927df203c945af2b45a226943e /libmisc/include | |
parent | a8c1de352ec10694b9b971bf111257ac5c9f0b71 (diff) |
libmisc: macro.h: Add LM_FOREACH_PARAM
Diffstat (limited to 'libmisc/include')
-rw-r--r-- | libmisc/include/libmisc/macro.h | 46 |
1 files changed, 46 insertions, 0 deletions
diff --git a/libmisc/include/libmisc/macro.h b/libmisc/include/libmisc/macro.h index d7f6243..a2d4264 100644 --- a/libmisc/include/libmisc/macro.h +++ b/libmisc/include/libmisc/macro.h @@ -64,6 +64,9 @@ #define LM_FIRST(a, ...) a #define LM_SECOND(a, b, ...) b +#define LM_FIRST_(...) LM_FIRST(__VA_ARGS__) +#define LM_SECOND_(...) LM_SECOND(__VA_ARGS__) + #define LM_EAT(...) #define LM_EXPAND(...) __VA_ARGS__ @@ -83,6 +86,25 @@ #define LM_IS_TUPLE(x) LM_IS_SENTINEL(_LM_IS_TUPLE x) #define _LM_IS_TUPLE(...) LM_SENTINEL() +/* For LM_IS_EMPTY_TUPLE: + * + * Given + * + * #define HELPER(...) B, __VA_OPT__(C,) D + * + * then evaluating the sequence of tokens `HELPER x , A` will give us a + * new sequence of tokens according to the following table: + * + * not a tuple : HELPER x , A + * tuple, nonempty: B , C , D , A + * tuple, empty : B , D , A + * + * Looking at this table, it is clear that we must look at the 2nd + * resulting comma-separated-value (argument), and set A=false, + * C=false, D=true (and B doesn't matter). + */ +#define LM_IS_EMPTY_TUPLE(x) LM_SECOND_(_LM_IS_EMPTY_TUPLE x, LM_F) +#define _LM_IS_EMPTY_TUPLE(...) bogus, __VA_OPT__(LM_F,) LM_T /* `tuples` is a sequence of `(tuple1)(tuple2)(tuple3)` */ #define _LM_TUPLES_COMMA(...) (__VA_ARGS__), @@ -105,6 +127,30 @@ #define _LM_DEFER2(macro) macro LM_EAT LM_EAT()() /** + * LM_FOREACH_PARAM(func, (fixedparams), params...) calls + * func(fixedparams..., param) for each param. + * + * BUG: LM_FOREACH_PARAM is limited to (16*2)-1=31 params. + */ +#define LM_FOREACH_PARAM(func, fixedparams, ...) _LM_EVAL(_LM_FOREACH_PARAM(func, fixedparams, __VA_ARGS__)) +#define _LM_FOREACH_PARAM(func, fixedparams, ...) _LM_FOREACH_PARAM_ITEM(func, fixedparams, __VA_ARGS__, ()) +#define _LM_FOREACH_PARAM_FIXEDPARAMS(fixedparams) _LM_FOREACH_PARAM_FIXEDPARAMS_inner fixedparams +#define _LM_FOREACH_PARAM_FIXEDPARAMS_inner(...) __VA_ARGS__ __VA_OPT__(,) +#define _LM_FOREACH_PARAM_ITEM(func, fixedparams, param, ...) \ + LM_IF(LM_IS_EMPTY_TUPLE(param))()( \ + _LM_DEFER2(func)(_LM_FOREACH_PARAM_FIXEDPARAMS(fixedparams) param) \ + _LM_DEFER2(_LM_FOREACH_PARAM_ITEM_indirect)()(func, fixedparams, __VA_ARGS__) \ + ) +#define _LM_FOREACH_PARAM_ITEM_indirect() _LM_FOREACH_PARAM_ITEM + +/** The same as LM_FOREACH_PARAM(), but callable from inside of LM_FOREACH_PARAM(). */ +#define LM_FOREACH_PARAM2(...) _LM_DEFER2(_LM_FOREACH_PARAM_ITEM_indirect)()(__VA_ARGS__, ()) + +/** The same as above, but evaluates the arguments first. */ +#define LM_FOREACH_PARAM_(...) LM_FOREACH_PARAM(__VA_ARGS__) +#define LM_FOREACH_PARAM2_(...) LM_FOREACH_PARAM2(__VA_ARGS__) + +/** * LM_FOREACH_TUPLE( (tup1) (tup2) (tup3), func, args...) calls * func(args..., tup...) for each tuple. * |