Browse Source

cppmagic: Logical operations

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>
David Gibson 10 years ago
parent
commit
f92c112c47
2 changed files with 64 additions and 1 deletions
  1. 45 0
      ccan/cppmagic/cppmagic.h
  2. 19 1
      ccan/cppmagic/test/run.c

+ 45 - 0
ccan/cppmagic/cppmagic.h

@@ -39,4 +39,49 @@
  */
  */
 #define CPPMAGIC_2ND(a_, b_, ...)	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__))
+
 #endif /* CCAN_CPPMAGIC_H */
 #endif /* CCAN_CPPMAGIC_H */

+ 19 - 1
ccan/cppmagic/test/run.c

@@ -17,7 +17,7 @@ static inline void check1(const char *orig, const char *expand,
 
 
 int main(void)
 int main(void)
 {
 {
-	plan_tests(7);
+	plan_tests(21);
 
 
 	CHECK1(CPPMAGIC_NOTHING(), "");
 	CHECK1(CPPMAGIC_NOTHING(), "");
 	CHECK1(CPPMAGIC_GLUE2(a, b), "ab");
 	CHECK1(CPPMAGIC_GLUE2(a, b), "ab");
@@ -29,6 +29,24 @@ int main(void)
 	CHECK1(CPPMAGIC_2ND(a, b), "b");
 	CHECK1(CPPMAGIC_2ND(a, b), "b");
 	CHECK1(CPPMAGIC_2ND(a, b, c), "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 */
 	/* This exits depending on whether all tests passed */
 	return exit_status();
 	return exit_status();
 }
 }