Commit 0ca50da9 authored by David Gibson's avatar David Gibson

cppmagic: Iteration

This implements macros which iterate across their arguments.  This is
implemented in terms of (kinda sorta) recursion.  In fact, they will stop
working with enough arguments, but the limit is large and can be easily
increased by changing the depth of the CPPMAGIC_EVAL() macro.

There are 3 iterators (for now):
  CPPMAGIC_MAP
    applies another macro to each of its remaining arguments - the results
    are comma separated, so they can be passed into another CPPMAGIC_MAP
    invocation.
  CPPMAGIC_2MAP
    does the same thing, but takes the arguments a pair at a time, using
    a supplied two-argument macro.
  CPPMAGIC_JOIN
    combines the arguments with a chosen delimiter (effectively replacing
the commas between the arguments with the delimiter)
same thing, but takes the arguments a pair at a time.
Signed-off-by: default avatarDavid Gibson <david@gibson.dropbear.id.au>
parent 7ddee86d
......@@ -133,4 +133,59 @@
#define CPPMAGIC_DEFER1(a_) a_ CPPMAGIC_NOTHING()
#define CPPMAGIC_DEFER2(a_) a_ CPPMAGIC_NOTHING CPPMAGIC_NOTHING()()
/**
* CPPMAGIC_MAP - iterate another macro across arguments
* @m: name of a one argument macro
*
* CPPMAGIC_MAP(@m, @a1, @a2, ... @an)
* expands to the expansion of @m(@a1) , @m(@a2) , ... , @m(@an)
*/
#define _CPPMAGIC_MAP_() _CPPMAGIC_MAP
#define _CPPMAGIC_MAP(m_, a_, ...) \
m_(a_) \
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
(, CPPMAGIC_DEFER2(_CPPMAGIC_MAP_)()(m_, __VA_ARGS__)) \
()
#define CPPMAGIC_MAP(m_, ...) \
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
(CPPMAGIC_EVAL(_CPPMAGIC_MAP(m_, __VA_ARGS__))) \
()
/**
* CPPMAGIC_2MAP - iterate another macro across pairs of arguments
* @m: name of a two argument macro
*
* CPPMAGIC_2MAP(@m, @a1, @b1, @a2, @b2, ..., @an, @bn)
* expands to the expansion of
* @m(@a1, @b1) , @m(@a2, @b2) , ... , @m(@an, @bn)
*/
#define _CPPMAGIC_2MAP_() _CPPMAGIC_2MAP
#define _CPPMAGIC_2MAP(m_, a_, b_, ...) \
m_(a_, b_) \
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
(, CPPMAGIC_DEFER2(_CPPMAGIC_2MAP_)()(m_, __VA_ARGS__)) \
()
#define CPPMAGIC_2MAP(m_, ...) \
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
(CPPMAGIC_EVAL(_CPPMAGIC_2MAP(m_, __VA_ARGS__))) \
()
/**
* CPPMAGIC_JOIN - separate arguments with given delimiter
* @d: delimiter
*
* CPPMAGIC_JOIN(@d, @a1, @a2, ..., @an)
* expands to the expansion of @a1 @d @a2 @d ... @d @an
*/
#define _CPPMAGIC_JOIN_() _CPPMAGIC_JOIN
#define _CPPMAGIC_JOIN(d_, a_, ...) \
a_ \
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
(d_ CPPMAGIC_DEFER2(_CPPMAGIC_JOIN_)()(d_, __VA_ARGS__)) \
()
#define CPPMAGIC_JOIN(d_, ...) \
CPPMAGIC_IFELSE(CPPMAGIC_NONEMPTY(__VA_ARGS__)) \
(CPPMAGIC_EVAL(_CPPMAGIC_JOIN(d_, __VA_ARGS__))) \
()
#endif /* CCAN_CPPMAGIC_H */
......@@ -18,9 +18,16 @@ static inline void check1(const char *orig, const char *expand,
#define TESTRECURSE() R CPPMAGIC_DEFER1(_TESTRECURSE)()()
#define _TESTRECURSE() TESTRECURSE
#define TESTMAP1(x) <<x>>
#define TESTMAP2(x) [[ x
#define TESTMAP3(x) x ]]
#define TEST2MAP(x, y) x ** y
int main(void)
{
plan_tests(27);
plan_tests(42);
CHECK1(CPPMAGIC_NOTHING(), "");
CHECK1(CPPMAGIC_GLUE2(a, b), "ab");
......@@ -58,6 +65,28 @@ int main(void)
CHECK1(CPPMAGIC_EVAL1(TESTRECURSE()), "R R R _TESTRECURSE ()()");
CHECK1(CPPMAGIC_EVAL2(TESTRECURSE()), "R R R R R _TESTRECURSE ()()");
CHECK1(CPPMAGIC_MAP(TESTMAP1), "");
CHECK1(CPPMAGIC_MAP(TESTMAP1, a), "<<a>>");
CHECK1(CPPMAGIC_MAP(TESTMAP1, a, b), "<<a>> , <<b>>");
CHECK1(CPPMAGIC_MAP(TESTMAP1, a, b, c), "<<a>> , <<b>> , <<c>>");
CHECK1(CPPMAGIC_2MAP(TEST2MAP), "");
CHECK1(CPPMAGIC_2MAP(TEST2MAP, a, 1), "a ** 1");
CHECK1(CPPMAGIC_2MAP(TEST2MAP, a, 1, b, 2), "a ** 1 , b ** 2");
CHECK1(CPPMAGIC_JOIN(;), "");
CHECK1(CPPMAGIC_JOIN(;, a), "a");
CHECK1(CPPMAGIC_JOIN(;, a, b), "a ; b");
CHECK1(CPPMAGIC_JOIN(;, a, b, c), "a ; b ; c");
/* Check chaining of MAPs */
CHECK1(CPPMAGIC_MAP(TESTMAP2, CPPMAGIC_MAP(TESTMAP3)), "");
CHECK1(CPPMAGIC_MAP(TESTMAP2, CPPMAGIC_MAP(TESTMAP3, a)), "[[ a ]]");
CHECK1(CPPMAGIC_MAP(TESTMAP2, CPPMAGIC_MAP(TESTMAP3, a, b)),
"[[ a ]] , [[ b ]]");
CHECK1(CPPMAGIC_MAP(TESTMAP2, CPPMAGIC_MAP(TESTMAP3, a, b, c)),
"[[ a ]] , [[ b ]] , [[ c ]]");
/* This exits depending on whether all tests passed */
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment