]> git.ozlabs.org Git - ccan/blobdiff - ccan/cast/cast.h
cast: new limited cast package inspired by Jan Engelhardt's libhx.
[ccan] / ccan / cast / cast.h
diff --git a/ccan/cast/cast.h b/ccan/cast/cast.h
new file mode 100644 (file)
index 0000000..f3bb445
--- /dev/null
@@ -0,0 +1,131 @@
+#ifndef CCAN_CAST_H
+#define CCAN_CAST_H
+#include "config.h"
+#include <ccan/build_assert/build_assert.h>
+
+/**
+ * cast_signed - cast a (const) char * to/from (const) signed/unsigned char *.
+ * @type: some char * variant.
+ * @expr: expression (of some char * variant) to cast.
+ *
+ * Some libraries insist on an unsigned char in various places; cast_signed
+ * makes sure (with suitable compiler) that the expression you are casting
+ * only differs in signed/unsigned, not in type or const-ness.
+ */
+#define cast_signed(type, expr)                                                \
+       ((type)(expr)                                                   \
+        + EXPR_BUILD_ASSERT(cast_sign_compatible(type, (expr))))
+
+/**
+ * cast_const - remove a const qualifier from a pointer.
+ * @type: some pointer type.
+ * @expr: expression to cast.
+ *
+ * This ensures that you are only removing the const qualifier from an
+ * expression.  The expression must otherwise match @type.
+ *
+ * If @type is a pointer to a pointer, you must use cast_const2 (etc).
+ *
+ * Example:
+ *     // Dumb open-coded strstr variant.
+ *     static char *find_needle(const char *haystack)
+ *     {
+ *             size_t i;
+ *             for (i = 0; i < strlen(haystack); i++)
+ *             if (memcmp("needle", haystack+i, strlen("needle")) == 0)
+ *                     return cast_const(char *, haystack+i);
+ *             return NULL;
+ *     }
+ */
+#define cast_const(type, expr)                                 \
+       ((type)(expr)                                           \
+        + EXPR_BUILD_ASSERT(cast_const_compat1((expr), type)))
+
+/**
+ * cast_const2 - remove a const qualifier from a pointer to a pointer.
+ * @type: some pointer to pointer type.
+ * @expr: expression to cast.
+ *
+ * This ensures that you are only removing the const qualifier from an
+ * expression.  The expression must otherwise match @type.
+ */
+#define cast_const2(type, expr)                                        \
+       ((type)(expr)                                           \
+        + EXPR_BUILD_ASSERT(cast_const_compat2((expr), type)))
+
+/**
+ * cast_const3 - remove a const from a pointer to a pointer to a pointer..
+ * @type: some pointer to pointer to pointer type.
+ * @expr: expression to cast.
+ *
+ * This ensures that you are only removing the const qualifier from an
+ * expression.  The expression must otherwise match @type.
+ */
+#define cast_const3(type, expr)                                        \
+       ((type)(expr)                                           \
+        + EXPR_BUILD_ASSERT(cast_const_compat3((expr), type)))
+
+
+/**
+ * cast_static - explicit mimic of implicit cast.
+ * @type: some type.
+ * @expr: expression to cast.
+ *
+ * This ensures that the cast is not to or from a pointer: it can only be
+ * an implicit cast, such as a pointer to a similar const pointer, or between
+ * integral types.
+ */
+#if HAVE_COMPOUND_LITERALS
+#define cast_static(type, expr)                        \
+       ((struct { type x; }){(expr)}.x)
+#else
+#define cast_static(type, expr)                        \
+       ((type)(expr))
+#endif
+
+/* Herein lies the gcc magic to evoke compile errors. */
+#if HAVE_BUILTIN_CHOOSE_EXPR && HAVE_BUILTIN_TYPES_COMPATIBLE_P && HAVE_TYPEOF
+#define cast_sign_compatible(t, e) \
+  __builtin_choose_expr(                                               \
+         __builtin_types_compatible_p(__typeof__(t), char *) ||        \
+         __builtin_types_compatible_p(__typeof__(t), signed char *) || \
+         __builtin_types_compatible_p(__typeof__(t), unsigned char *), \
+         /* if type is not const qualified */                          \
+         __builtin_types_compatible_p(__typeof__(e), char *) ||        \
+         __builtin_types_compatible_p(__typeof__(e), signed char *) || \
+         __builtin_types_compatible_p(__typeof__(e), unsigned char *), \
+         /* and if it is... */                                         \
+         __builtin_types_compatible_p(__typeof__(e), const char *) ||  \
+         __builtin_types_compatible_p(__typeof__(e), const signed char *) || \
+         __builtin_types_compatible_p(__typeof__(e), const unsigned char *) ||\
+         __builtin_types_compatible_p(__typeof__(e), char *) ||        \
+         __builtin_types_compatible_p(__typeof__(e), signed char *) || \
+         __builtin_types_compatible_p(__typeof__(e), unsigned char *)  \
+         )
+
+#define cast_const_strip1(expr)                        \
+       __typeof__(*(struct { int z; __typeof__(expr) x; }){0}.x)
+#define cast_const_strip2(expr) \
+       __typeof__(**(struct { int z; __typeof__(expr) x; }){0}.x)
+#define cast_const_strip3(expr) \
+       __typeof__(***(struct { int z; __typeof__(expr) x; }){0}.x)
+#define cast_const_compat1(expr, type)                                 \
+       __builtin_types_compatible_p(cast_const_strip1(expr),           \
+                                    cast_const_strip1(type))
+#define cast_const_compat2(expr, type)                                 \
+       __builtin_types_compatible_p(cast_const_strip2(expr),           \
+                                    cast_const_strip2(type))
+#define cast_const_compat3(expr, type)                                 \
+       __builtin_types_compatible_p(cast_const_strip3(expr),           \
+                                    cast_const_strip3(type))
+#else
+#define cast_sign_compatible(type, expr)               \
+       (sizeof(*(type)0) == 1 && sizeof(*(expr)) == 1)
+#define cast_const_compat1(expr, type)         \
+       (sizeof(*(expr)) == sizeof(*(type)0))
+#define cast_const_compat2(expr, type)         \
+       (sizeof(**(expr)) == sizeof(**(type)0))
+#define cast_const_compat3(expr, type)                 \
+       (sizeof(***(expr)) == sizeof(***(type)0))
+#endif
+#endif /* CCAN_CAST_H */