cppmagic: Logical operations
authorDavid Gibson <david@gibson.dropbear.id.au>
Tue, 26 Jan 2016 09:52:32 +0000 (20:52 +1100)
committerDavid Gibson <david@gibson.dropbear.id.au>
Wed, 3 Feb 2016 22:44:13 +0000 (09:44 +1100)
In order to implement fancier things, we need to represent truth values in
cpp.  We use '0' and '1' strings, like in C, but we need ways to get these
values from other conditions.

CPPMAGIC_ISZERO() and CPPMAGIC_NONZERO() test if the argument is '0' or
anything else (ISZERO doubles as a logical not).

CPPMAGIC_ISEMPTY() and CPPMAGIC_NON_EMPTY() expand to 0 or 1 depending on
whether they have any arguments at all or not.

Signed-off-by: David Gibson <david@gibson.dropbear.id.au>
ccan/cppmagic/cppmagic.h
ccan/cppmagic/test/run.c

index f29e0ec6cee39b39114f3849dadce50d00a2f6e3..c4454e776392f4edff78ff8289d432ce4e09ddf4 100644 (file)
  */
 #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__))
+
 #endif /* CCAN_CPPMAGIC_H */
index 0ed830d8d0f7faead3c9ec9153911abcd0da1d26..fb2bfb9f95450d0354385843be722c462c25a9a2 100644 (file)
@@ -17,7 +17,7 @@ static inline void check1(const char *orig, const char *expand,
 
 int main(void)
 {
-       plan_tests(7);
+       plan_tests(21);
 
        CHECK1(CPPMAGIC_NOTHING(), "");
        CHECK1(CPPMAGIC_GLUE2(a, b), "ab");
@@ -29,6 +29,24 @@ int main(void)
        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");
+       
        /* This exits depending on whether all tests passed */
        return exit_status();
 }