diff options
author | Alistair Popple <alistair@popple.id.au> | 2018-06-20 15:34:02 +1000 |
---|---|---|
committer | Alistair Popple <alistair@popple.id.au> | 2018-06-25 15:57:55 +1000 |
commit | 4accccb16827eb30442a6a5f7b620037d61e6b56 (patch) | |
tree | cdd584def6869b53562e7156c64d583480ea1fc1 /ccan | |
parent | b05d6eb6d66fd4cc4914ab1e6edc006177803fa5 (diff) | |
download | pdbg-4accccb16827eb30442a6a5f7b620037d61e6b56.tar.gz pdbg-4accccb16827eb30442a6a5f7b620037d61e6b56.zip |
ccan: Add cppmagic
A couple of arguably useful C preprocessor abuses. License is BSD-MIT.
Signed-off-by: Alistair Popple <alistair@popple.id.au>
Diffstat (limited to 'ccan')
l--------- | ccan/cppmagic/LICENSE | 1 | ||||
-rw-r--r-- | ccan/cppmagic/_info | 30 | ||||
-rw-r--r-- | ccan/cppmagic/cppmagic.h | 191 | ||||
-rw-r--r-- | ccan/cppmagic/test/run.c | 92 |
4 files changed, 314 insertions, 0 deletions
diff --git a/ccan/cppmagic/LICENSE b/ccan/cppmagic/LICENSE new file mode 120000 index 0000000..2354d12 --- /dev/null +++ b/ccan/cppmagic/LICENSE @@ -0,0 +1 @@ +../../licenses/BSD-MIT
\ No newline at end of file diff --git a/ccan/cppmagic/_info b/ccan/cppmagic/_info new file mode 100644 index 0000000..aad394b --- /dev/null +++ b/ccan/cppmagic/_info @@ -0,0 +1,30 @@ +#include "config.h" +#include <stdio.h> +#include <string.h> + +/** + * cppmagic - Abuse of the C preprocessor + * + * This contains a bunch of fancy macro techniques such as + * preprocessor-time evaluated conditionals and (quasi) recursion and + * iteration. + * + * It's based on these articles: + * - http://jhnet.co.uk/articles/cpp_magic + * - https://github.com/pfultz2/Cloak/wiki/C-Preprocessor-tricks,-tips,-and-idioms + * and code from the Boost C++ library. + * + * License: BSD-MIT + */ +int main(int argc, char *argv[]) +{ + /* Expect exactly one argument */ + if (argc != 2) + return 1; + + if (strcmp(argv[1], "depends") == 0) { + return 0; + } + + return 1; +} diff --git a/ccan/cppmagic/cppmagic.h b/ccan/cppmagic/cppmagic.h new file mode 100644 index 0000000..f1f6868 --- /dev/null +++ b/ccan/cppmagic/cppmagic.h @@ -0,0 +1,191 @@ +/* MIT (BSD) license - see LICENSE file for details */ +#ifndef CCAN_CPPMAGIC_H +#define CCAN_CPPMAGIC_H + +/** + * CPPMAGIC_NOTHING - expands to nothing + */ +#define CPPMAGIC_NOTHING() + +/** + * CPPMAGIC_STRINGIFY - convert arguments to a string literal + */ +#define _CPPMAGIC_STRINGIFY(...) #__VA_ARGS__ +#define CPPMAGIC_STRINGIFY(...) _CPPMAGIC_STRINGIFY(__VA_ARGS__) + +/** + * CPPMAGIC_GLUE2 - glue arguments together + * + * CPPMAGIC_GLUE2(@a_, @b_) + * expands to the expansion of @a_ followed immediately + * (combining tokens) by the expansion of @b_ + */ +#define _CPPMAGIC_GLUE2(a_, b_) a_##b_ +#define CPPMAGIC_GLUE2(a_, b_) _CPPMAGIC_GLUE2(a_, b_) + +/** + * CPPMAGIC_1ST - return 1st argument + * + * CPPMAGIC_1ST(@a_, ...) + * expands to the expansion of @a_ + */ +#define CPPMAGIC_1ST(a_, ...) a_ + +/** + * CPPMAGIC_2ND - return 2nd argument + * + * CPPMAGIC_2ST(@a_, @b_, ...) + * expands to the expansion of @b_ + */ +#define CPPMAGIC_2ND(a_, b_, ...) b_ + +/** + * CPPMAGIC_ISZERO - is argument '0' + * + * CPPMAGIC_ISZERO(@a) + * expands to '1' if @a is '0', otherwise expands to '0'. + */ +#define _CPPMAGIC_ISPROBE(...) CPPMAGIC_2ND(__VA_ARGS__, 0) +#define _CPPMAGIC_PROBE() $, 1 +#define _CPPMAGIC_ISZERO_0 _CPPMAGIC_PROBE() +#define CPPMAGIC_ISZERO(a_) \ + _CPPMAGIC_ISPROBE(CPPMAGIC_GLUE2(_CPPMAGIC_ISZERO_, a_)) + +/** + * CPPMAGIC_NONZERO - is argument not '0' + * + * CPPMAGIC_NONZERO(@a) + * expands to '0' if @a is '0', otherwise expands to '1'. + */ +#define CPPMAGIC_NONZERO(a_) CPPMAGIC_ISZERO(CPPMAGIC_ISZERO(a_)) + +/** + * CPPMAGIC_NONEMPTY - does the macro have any arguments? + * + * CPPMAGIC_NONEMPTY() + * expands to '0' + * CPPMAGIC_NONEMPTY(@a) + * CPPMAGIC_NONEMPTY(@a, ...) + * expand to '1' + */ +#define _CPPMAGIC_EOA() 0 +#define CPPMAGIC_NONEMPTY(...) \ + CPPMAGIC_NONZERO(CPPMAGIC_1ST(_CPPMAGIC_EOA __VA_ARGS__)()) + +/** + * CPPMAGIC_ISEMPTY - does the macro have no arguments? + * + * CPPMAGIC_ISEMPTY() + * expands to '1' + * CPPMAGIC_ISEMPTY(@a) + * CPPMAGIC_ISEMPTY(@a, ...) + * expand to '0' + */ +#define CPPMAGIC_ISEMPTY(...) \ + CPPMAGIC_ISZERO(CPPMAGIC_NONEMPTY(__VA_ARGS__)) + +/* + * CPPMAGIC_IFELSE - preprocessor conditional + * + * CPPMAGIC_IFELSE(@cond)(@if)(@else) + * expands to @else if @cond is '0', otherwise expands to @if + */ +#define _CPPMAGIC_IF_0(...) _CPPMAGIC_IF_0_ELSE +#define _CPPMAGIC_IF_1(...) __VA_ARGS__ _CPPMAGIC_IF_1_ELSE +#define _CPPMAGIC_IF_0_ELSE(...) __VA_ARGS__ +#define _CPPMAGIC_IF_1_ELSE(...) +#define _CPPMAGIC_IFELSE(cond_) CPPMAGIC_GLUE2(_CPPMAGIC_IF_, cond_) +#define CPPMAGIC_IFELSE(cond_) \ + _CPPMAGIC_IFELSE(CPPMAGIC_NONZERO(cond_)) + +/** + * CPPMAGIC_EVAL - force multiple expansion passes + * + * Forces macros in the arguments to be expanded repeatedly (up to + * 1024 times) even when CPP would usually stop expanding. + */ +#define CPPMAGIC_EVAL1(...) __VA_ARGS__ +#define CPPMAGIC_EVAL2(...) \ + CPPMAGIC_EVAL1(CPPMAGIC_EVAL1(__VA_ARGS__)) +#define CPPMAGIC_EVAL4(...) \ + CPPMAGIC_EVAL2(CPPMAGIC_EVAL2(__VA_ARGS__)) +#define CPPMAGIC_EVAL8(...) \ + CPPMAGIC_EVAL4(CPPMAGIC_EVAL4(__VA_ARGS__)) +#define CPPMAGIC_EVAL16(...) \ + CPPMAGIC_EVAL8(CPPMAGIC_EVAL8(__VA_ARGS__)) +#define CPPMAGIC_EVAL32(...) \ + CPPMAGIC_EVAL16(CPPMAGIC_EVAL16(__VA_ARGS__)) +#define CPPMAGIC_EVAL64(...) \ + CPPMAGIC_EVAL32(CPPMAGIC_EVAL32(__VA_ARGS__)) +#define CPPMAGIC_EVAL128(...) \ + CPPMAGIC_EVAL64(CPPMAGIC_EVAL64(__VA_ARGS__)) +#define CPPMAGIC_EVAL256(...) \ + CPPMAGIC_EVAL128(CPPMAGIC_EVAL128(__VA_ARGS__)) +#define CPPMAGIC_EVAL512(...) \ + CPPMAGIC_EVAL256(CPPMAGIC_EVAL256(__VA_ARGS__)) +#define CPPMAGIC_EVAL1024(...) \ + CPPMAGIC_EVAL512(CPPMAGIC_EVAL512(__VA_ARGS__)) +#define CPPMAGIC_EVAL(...) CPPMAGIC_EVAL1024(__VA_ARGS__) + +/** + * CPPMAGIC_DEFER1, CPPMAGIC_DEFER2 - defer expansion + */ +#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 */ diff --git a/ccan/cppmagic/test/run.c b/ccan/cppmagic/test/run.c new file mode 100644 index 0000000..7c0aa7f --- /dev/null +++ b/ccan/cppmagic/test/run.c @@ -0,0 +1,92 @@ +#include "config.h" + +#include <string.h> + +#include <ccan/cppmagic/cppmagic.h> +#include <ccan/tap/tap.h> + +static inline void check1(const char *orig, const char *expand, + const char *match) +{ + ok(strcmp(expand, match) == 0, + "%s => %s : %s", orig, expand, match); +} + +#define CHECK1(orig, match) \ + check1(#orig, CPPMAGIC_STRINGIFY(orig), match) + +#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(42); + + CHECK1(CPPMAGIC_NOTHING(), ""); + CHECK1(CPPMAGIC_GLUE2(a, b), "ab"); + + CHECK1(CPPMAGIC_1ST(a), "a"); + CHECK1(CPPMAGIC_1ST(a, b), "a"); + CHECK1(CPPMAGIC_1ST(a, b, c), "a"); + + CHECK1(CPPMAGIC_2ND(a, b), "b"); + CHECK1(CPPMAGIC_2ND(a, b, c), "b"); + + CHECK1(CPPMAGIC_ISZERO(0), "1"); + CHECK1(CPPMAGIC_ISZERO(1), "0"); + CHECK1(CPPMAGIC_ISZERO(123), "0"); + CHECK1(CPPMAGIC_ISZERO(abc), "0"); + + CHECK1(CPPMAGIC_NONZERO(0), "0"); + CHECK1(CPPMAGIC_NONZERO(1), "1"); + CHECK1(CPPMAGIC_NONZERO(123), "1"); + CHECK1(CPPMAGIC_NONZERO(abc), "1"); + + CHECK1(CPPMAGIC_NONEMPTY(), "0"); + CHECK1(CPPMAGIC_NONEMPTY(0), "1"); + CHECK1(CPPMAGIC_NONEMPTY(a, b, c), "1"); + + CHECK1(CPPMAGIC_ISEMPTY(), "1"); + CHECK1(CPPMAGIC_ISEMPTY(0), "0"); + CHECK1(CPPMAGIC_ISEMPTY(a, b, c), "0"); + + CHECK1(CPPMAGIC_IFELSE(0)(abc)(def), "def"); + CHECK1(CPPMAGIC_IFELSE(1)(abc)(def), "abc"); + CHECK1(CPPMAGIC_IFELSE(not zero)(abc)(def), "abc"); + + CHECK1(TESTRECURSE(), "R R _TESTRECURSE ()()"); + 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(); +} |