lib/sod.h (sod_sublassp): Fix function description.
[sod] / lib / sod.h
index 8945810..3ad4250 100644 (file)
--- a/lib/sod.h
+++ b/lib/sod.h
 
 /*----- Preliminary utilities ---------------------------------------------*/
 
+/* Various hacks for checking compiler versions. */
+#define SOD__GCC_P(maj, min)                                           \
+       (__GNUC__ > (maj) || (__GNUC__ == (maj) && __GNUC_MINOR__ >= (min)))
+
+#ifdef __GNUC__
+#  define SOD__EXTENSION __extension__
+#else
+#  define SOD__EXTENSION
+#endif
+
 /* --- @SOD__HAVE_VARARGS_MACROS@ --- *
  *
  * Use:                Defined if the compiler supports C99-style variadic macros.
@@ -49,7 +59,7 @@
 
 #  define SOD__HAVE_VARARGS_MACROS
 
-#elif __GNUC__ >= 3
+#elif SOD__GCC_P(3, 0)
    /* We're using GCC, which is trying to deny it but we don't believe it.
     * Unfortunately there's a fly in the ointment: if `-pedantic' -- or,
     * worse, `-pedantic-errors' -- is set, then GCC will warn about these
 /* We're going to want to make use of this ourselves. */
 SOD__VARARGS_MACROS_PREAMBLE
 
+/* --- @SOD__ALIGNOF@ --- *
+ *
+ * Arguments:  @type@ = a C type name, consisting of declaration specifiers
+ *                     and `*[QUALIFIERS]' declarator operators
+ *
+ * Returns:    A sufficient alignment for objects of the given @type@, as a
+ *             @size_t@.
+ */
+
+#if __STDC_VERSION__ >= 201112
+#  define SOD__ALIGNOF(type) _Alignof(type)
+#elif SOD__GCC_P(4, 7)
+#  define SOD__ALIGNOF(type) __extension__ _Alignof(type)
+#elif defined(__GNUC__)
+#  define SOD__ALIGNOF(type) __alignof__(type)
+#else
+#  define SOD__ALIGNOF(type)                                           \
+       offsetof(struct { char sod__x; type sod__y; }, sod__y)
+#endif
+
 /* --- @SOD__IGNORE@ --- *
  *
  * Arguments:  @var@ = some variable name
@@ -86,6 +116,35 @@ SOD__VARARGS_MACROS_PREAMBLE
 
 #define SOD__IGNORE(var) ((void)(var))
 
+/* --- @SOD__NORETURN@ --- *
+ *
+ * Use:                Marks functions which are not expected to return.
+ */
+
+#if SOD__GCC_P(2, 5)
+#  define SOD__NORETURN __attribute__((__noreturn__))
+#endif
+
+#ifndef SOD__NORETURN
+#  define SOD__NORETURN
+#endif
+
+/* --- @SOD__PARANOIA@ --- *
+ *
+ * Arguments:  @cond@ = a condition to check
+ *             @conseq@ = a thing to evaluate to if the check passes
+ *             @alt@ = a thing to do if the check fails
+ *
+ * Use:                Check to make sure something is good at runtime, unless
+ *             disabled.
+ */
+
+#if SOD_RECKLESS
+#  define SOD__PARANOIA(cond, conseq, alt) (conseq)
+#else
+#  define SOD__PARANOIA(cond, conseq, alt) ((cond) ? (conseq) : (alt))
+#endif
+
 /* --- @SOD__CAR@ --- *
  *
  * Arguments:  @...@ = a nonempty list of arguments
@@ -94,7 +153,7 @@ SOD__VARARGS_MACROS_PREAMBLE
  */
 
 #ifdef SOD__HAVE_VARARGS_MACROS
-#  define SOD__CAR(...) SOD__CARx(__VA_LIST__, _)
+#  define SOD__CAR(...) SOD__CARx(__VA_ARGS__, _)
 #  define SOD__CARx(a, ...) a
 #endif
 
@@ -261,7 +320,7 @@ struct sod_chain {
 
 /* --- @SOD_DECL@ --- *
  *
- * Arguments:  @cls@ = a class type name
+ * Arguments:  @cls_@ = a class type name
  *             @var@ = a variable name
  *             @keys@ = a @KWARGS(...)@ keyword argument sequence
  *
@@ -269,17 +328,36 @@ struct sod_chain {
  *             @cls@ with automatic lifetime.
  */
 
-#define SOD_DECL(cls, var, keys)                                       \
-  struct cls##__ilayout var##__layout;                                 \
-  cls *var = (cls *)sod_init(cls##__class, &var##__layout, keys)
+#define SOD_DECL(cls_, var, keys)                                      \
+  struct cls_##__ilayout var##__layout;                                        \
+  cls_ *var =                                                          \
+    SOD__PARANOIA(sizeof(var##__layout) == cls_##__class->cls.initsz,  \
+                 (cls_ *)sod_init(cls_##__class, &var##__layout, keys), \
+                 (sod__chksz_fail(cls_##__class, sizeof(var##__layout)), \
+                  (cls_ *)0))
 
 /*----- Functions provided ------------------------------------------------*/
 
+/* --- @sod__chksz_fail@ --- *
+ *
+ * Arguments:  @const SodClass *cls@ = class we were trying to instantiate
+ *             @size_t sz@ = size allocated
+ *
+ * Returns:    Doesn't.
+ *
+ * Use:                Reports instantiation failure caused by a mismatch between
+ *             the size allocated (@sz@) and the size required for an
+ *             instance of class @cls@.
+ */
+
+extern SOD__NORETURN
+  void sod__chksz_fail(const SodClass */*cls*/, size_t /*sz*/);
+
 /* --- @sod_subclassp@ --- *
  *
  * Arguments:  @const SodClass *sub, *super@ = pointers to two classes
  *
- * Returns:    Nonzero if @c@ is a subclass of @d@.
+ * Returns:    Nonzero if @sub@ is a subclass of @super@.
  */
 
 extern int sod_subclassp(const SodClass */*sub*/, const SodClass */*super*/);