From patchwork Wed Jun 20 05:34:02 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alistair Popple X-Patchwork-Id: 931955 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 419YS11Vq1z9s4n for ; Wed, 20 Jun 2018 15:34:41 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from lists.ozlabs.org (lists.ozlabs.org [IPv6:2401:3900:2:1::3]) by lists.ozlabs.org (Postfix) with ESMTP id 419YS100hrzF0wb for ; Wed, 20 Jun 2018 15:34:41 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au X-Original-To: pdbg@lists.ozlabs.org Delivered-To: pdbg@lists.ozlabs.org Received: from ozlabs.org (ozlabs.org [IPv6:2401:3900:2:1::2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by lists.ozlabs.org (Postfix) with ESMTPS id 419YRY3c9pzF0wb for ; Wed, 20 Jun 2018 15:34:17 +1000 (AEST) Authentication-Results: lists.ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au Received: from authenticated.ozlabs.org (localhost [127.0.0.1]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPSA id 419YRY0w34z9s7F; Wed, 20 Jun 2018 15:34:17 +1000 (AEST) Authentication-Results: ozlabs.org; dmarc=none (p=none dis=none) header.from=popple.id.au From: Alistair Popple To: pdbg@lists.ozlabs.org Date: Wed, 20 Jun 2018 15:34:02 +1000 Message-Id: <20180620053409.14538-2-alistair@popple.id.au> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20180620053409.14538-1-alistair@popple.id.au> References: <20180620053409.14538-1-alistair@popple.id.au> Subject: [Pdbg] [PATCH 1/8] ccan: Add cppmagic X-BeenThere: pdbg@lists.ozlabs.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: "mailing list for https://github.com/open-power/pdbg development" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Errors-To: pdbg-bounces+incoming=patchwork.ozlabs.org@lists.ozlabs.org Sender: "Pdbg" A couple of arguably useful C preprocessor abuses. License is BSD-MIT. Signed-off-by: Alistair Popple --- ccan/cppmagic/LICENSE | 1 + ccan/cppmagic/_info | 30 ++++++++ ccan/cppmagic/cppmagic.h | 191 +++++++++++++++++++++++++++++++++++++++++++++++ ccan/cppmagic/test/run.c | 92 +++++++++++++++++++++++ 4 files changed, 314 insertions(+) create mode 120000 ccan/cppmagic/LICENSE create mode 100644 ccan/cppmagic/_info create mode 100644 ccan/cppmagic/cppmagic.h create mode 100644 ccan/cppmagic/test/run.c 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 +#include + +/** + * 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 + +#include +#include + +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) <> + +#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), "<>"); + CHECK1(CPPMAGIC_MAP(TESTMAP1, a, b), "<> , <>"); + CHECK1(CPPMAGIC_MAP(TESTMAP1, 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(); +}