chiark / gitweb /
@@@ fltfmt mess
[mLib] / utils / macros.h
index dba22a7a9d07ce2e9f442eaa25c205568a042b8e..bc836296e2ca50322286176b570924d222862615 100644 (file)
 #  define STATIC_ASSERT(cond, msg) static_assert(!!(cond), msg)
 #else
 #  define STATIC_ASSERT(cond, msg)                                     \
-       IGNORABLE extern char static_assert_failed[2*!!(cond) - 1]
+       IGNORABLE extern char static_assert_failed[1 - 2*!(cond)]
 #endif
 
+/* --- @CHECK_TYPE@ ---
+ *
+ * Arguments:  @expty@ = expected type of @x@
+ *             @expty x@ = some object
+ *
+ * Returns:    Integer zero.
+ *
+ * Use:                Cause a compile-time failure unless the type of @x@ is
+ *             assignment-compatible with @expty@.
+ */
+
+#define CHECK_TYPE(expty, x) (!sizeof(*(expty *)0 = (x)))
+
+/* --- @CONVERT_CAREFULLY@ ---
+ *
+ * Arguments:  @newty@ = new type for the result
+ *             @expty@ = expected type of @x@
+ *             @expty x@ = some object
+ *
+ * Returns:    @x@, but coerced to type @newty@.
+ *
+ * Use:                Like @(newty)x@, except that it checks at compile-time that
+ *             @x@ is at least assignment-compatible with type @expty@
+ *             before trying.
+ */
+
+#define CONVERT_CAREFULLY(newty, expty, x)                             \
+       (CHECK_TYPE(expty, x) + (/*unconst unvolatile*/ newty)(x))
+
+/* --- @UNCONST@, @UNVOLATILE@, @UNQUALIFY@ --- *
+ *
+ * Arguments:  @type@ = a type name
+ *             @type *p@ = a pointer
+ *
+ * Returns:    @p@, but without @const@, @volatile@ or both qualifiers.
+ *
+ * Use:                Strips qualifiers from pointer types.
+ *
+ *             The @UNCONST@ macro strips @const@.  It checks that @p@
+ *             has type `pointer to @type@ or @const type@'; if not, a
+ *             compile-time error results.  Otherwise, it returns the value
+ *             of @p@, converted to `pointer to (non-constant) @type@'.  It
+ *             will not silently strip a @volatile@ qualifier.
+ *
+ *             The @UNVOLATILE@ macro is similar, except that it strips
+ *             @volatile@ instead of @const@.  The @UNQUALIFY@ macro strips
+ *             both qualifiers.
+ */
+
+#define UNCONST(type, p) CONVERT_CAREFULLY(type *, const type *, p)
+#define UNVOLATILE(type, p) CONVERT_CAREFULLY(type *, volatile type *, p)
+#define UNQUALIFY(type, p)                                             \
+       CONVERT_CAREFULLY(type *, const volatile type *, p)
+
 /* --- @COMMA@ --- *
  *
  * Arguments:  ---
 #if GCC_VERSION_P(2, 7) || CLANG_VERSION_P(0, 0)
 #  define LAUNDER(x)                                                   \
        ({ __typeof__(x) _y; __asm__("" : "=g"(_y) : "0"(x)); _y; })
+#  define ADMIRE(x)                                                    \
+       ({ __asm__("" : : "g"(x)); })
+#  define ADMIRE_BUF(p, sz)                                            \
+       ({ __asm__("" : : "g"(p), "g"(sz)); })
 #  define RELAX do __asm__ __volatile__("" ::: "memory"); while (0)
 #endif
 
 #  define LAUNDER(x) (x)
 #endif
 
+/* --- @ADMIRE@, @ADMIRE_BUF@ --- *
+ *
+ * Arguments:  @x@ = some scalar expression
+ *             @const void *p@, @size_t sz@ = a pointer and length
+ *
+ * Returns:    ---
+ *
+ * Use:                Ensures that the compiler generates code to compute @x@ or
+ *             the contents of the buffer at @p@.
+ */
+
+#ifndef ADMIRE
+#  define ADMIRE(x) ((void)(x))
+#endif
+#ifndef ADMIRE_BUF
+#  define ADMIRE_BUF(p, sz) ((void)(p), (void)(sz))
+#endif
+
 /* --- @RELAX@ --- *
  *
  * Arguments:  ---