← Back to davo.co
aboutsummaryrefslogtreecommitdiffstats
path: root/swap.c
diff options
context:
space:
mode:
Diffstat (limited to 'swap.c')
-rw-r--r--swap.c144
1 files changed, 144 insertions, 0 deletions
diff --git a/swap.c b/swap.c
new file mode 100644
index 0000000..1f006d7
--- /dev/null
+++ b/swap.c
@@ -0,0 +1,144 @@
+#include "c23-fallback.h"
+#include <stdio.h>
+
+#define static_assert_compatible(A, B, REASON) \
+ static_assert(_Generic((typeof(A)*)nullptr, \
+ typeof(B)*: true, \
+ default: false), \
+ "expected compatible types: " REASON ", have " #A " and " #B "")
+
+#ifndef __GNUC__
+#define SWAP(X, Y) \
+ do { \
+ /* These two variables have the role of function \
+ parameters. They ensure to evaluate the \
+ expression X and Y once, since these could be \
+ complicated lvalue expressions with evaluated \
+ subexpressions that have side effects. */ \
+ auto const swap_p1 = &(X); \
+ auto const swap_p2 = &(Y); \
+ static_assert_compatible(*swap_p1, *swap_p2, \
+ "to exchange values, '" \
+ #X "' and '" #Y \
+ "' must have compatible types"); \
+ auto swap_tmp = *swap_p1; \
+ *swap_p1 = *swap_p2; \
+ *swap_p2 = swap_tmp; \
+ } while (false)
+#else
+#define SWAP(X, Y) \
+ /* This starts the compound expression construct. */ \
+ ({ \
+ /* These two variables have the role of function \
+ parameters. They ensure to evaluate the \
+ expression X and Y once, since these could be \
+ complicated lvalue expressions with evaluated \
+ subexpressions that have side effects. */ \
+ auto const swap_p1 = &(X); \
+ auto const swap_p2 = &(Y); \
+ static_assert_compatible(*swap_p1, *swap_p2, \
+ "to exchange values, '" \
+ #X "' and '" #Y \
+ "' must have compatible types"); \
+ auto swap_tmp = *swap_p1; \
+ *swap_p1 = *swap_p2; \
+ *swap_p2 = swap_tmp; \
+ /* ensure that the type of the expression is void */ \
+ (void)0; \
+ })
+#endif
+
+
+#define isnegative(X) ((X) < 0)
+
+#define MAX_EQSIGN(X, Y) \
+ /* This starts the compound expression construct. */ \
+ ({ \
+ /* These two captures play the role of function \
+ parameters and read X and Y ... */ \
+ auto const max_x = (X); \
+ auto const max_y = (Y); \
+ /* now the body starts */ \
+ /* types need to have the same signedness */ \
+ (max_x < max_y) ? max_y : max_x; \
+ })
+
+#define MAX(X, Y) \
+ /* This starts the compound expression construct. */ \
+ ({ \
+ auto const max_x = (X); \
+ auto const max_y = (Y); \
+ /* now the body starts */ \
+ ((isnegative(max_x) && !isnegative(max_y)) \
+ ? max_y \
+ : ((isnegative(max_y) && !isnegative(max_x)) \
+ ? max_x \
+ : /* both have the same sign */ \
+ ((max_x < max_y) ? max_y : max_x))); \
+ })
+
+
+
+#define mincharacteristic(X, Y) ((issigned(X)<<2)|(issigned(Y)<<1)|1)
+
+#define minunsigned(X, Y) (_Generic(tozero(X)+tozero(Y), typeof(X): tozero(Y), default: tozero(X)))
+
+#define minreturn(X, Y) \
+ _Generic( \
+ (char(*)[mincharacteristic(X, Y)]){ 0 }, \
+ /* both signed, arithmetic conversion */ \
+ char(*)[4|2|1]: tozero(X)+tozero(Y), \
+ /* only one signed, use it */ \
+ char(*)[0|2|1]: tozero(Y), \
+ char(*)[4|0|1]: tozero(X), \
+ /* both unsigned, use narrower */ \
+ char(*)[0|0|1]: minunsigned(X, Y) \
+)
+
+#define MIN(X, Y) \
+ /* This starts the compound expression construct. */ \
+ ({ \
+ /* These two captures play the role of function \
+ parameters and read X and Y ... */ \
+ auto const min_x = (X); \
+ auto const min_y = (Y); \
+ /* now the body starts */ \
+ typedef typeof(minreturn(min_x, min_y)) min_type; \
+ ((isnegative(min_x) && !issigned(min_y)) \
+ ? (min_type)min_x \
+ : ((isnegative(min_y) && !issigned(min_x)) \
+ ? (min_type)min_y \
+ : ( \
+ /* both have the same signedness or are both positive */ \
+ (min_x < min_y) \
+ ? (min_type)min_x \
+ : (min_type)min_y))); \
+ })
+
+
+int main (int argc, char* argv[static argc + 1]) {
+ size_t i = argc;
+ size_t j = argc+1;
+ printf("%s, %s\n", argv[1], argv[2]);
+ // Works even with side effects, but don't do that
+ SWAP(argv[1+(i++)%2], argv[1+(j++)%2]); // don't do that
+ printf("%s, %s\n", argv[1], argv[2]);
+ // Works even with side effects, but don't do that
+ SWAP(argv[1+(i++)%2], argv[1+(j++)%2]); // don't do that
+ printf("%s, %s\n", argv[1], argv[2]);
+ printf("%d\t%d\t→\t%d\n", -1, -2, MIN(-1, -2));
+ printf("%d\t%ldl\t→\t%ldl\n", -2, -1L, MIN(-2, -1L));
+ printf("%d\t%d\t→\t%d\n", -1, 2, MIN(-1, 2));
+ printf("%d\t%ldl\t→\t%ldl\n", -1, 2L, MIN(-1, 2L));
+ printf("%d\t%uu\t→\t%d\n", -1, 2u, MIN(-1, 2u));
+ printf("%d\t%luul\t→\t%d\n", -1, 2UL, MIN(-1, 2UL));
+ printf("%uu\t%uu\t→\t%uu\n", -1u, -2u, MIN(-1u, -2u));
+ printf("%uu\t%luul\t→\t%uu\n", -1u, -2UL, MIN(-1u, -2UL));
+ static_assert_compatible(1, 0, "both int");
+ //static_assert_compatible(1, 0L, "both int");
+ //static_assert_compatible(1L, 0, "both int");
+ static_assert_compatible(1L, 0L, "both int");
+ enum A : unsigned long { A = -1UL, };
+ static_assert_compatible(A, 0UL, "both int");
+ static_assert_compatible(int[1], int[true], "both int");
+}