#ifndef    __SIMPLEST_DEFS_H__
#define    __SIMPLEST_DEFS_H__


#include <stddef.h>
#include <stdint.h>

#include "sparse.h"


/* FIXME [matteof 2017-06-16] The name of this type is wrong. */

/* BOOLINT intends to provide a type that can be stored in
   structs without worrying about alignment, and is compatible
   with C's rules, so that

      boolint foo = (1 != 0);
      foo && (...)

   work.
*/
typedef ptrdiff_t boolint;
#define FMTboolint "%td"

#if defined(__clang__)
#define __enum64
#define ENUM_AS_UINT64(e) uint64_t
#else
#define __enum64 __attribute__((mode(DI)))
#define ENUM_AS_UINT64(e) e
#endif

#define UNUSED(x) ((void)(x))
#define STATIC_ASSERT(truth)                                            \
    extern char                                                         \
    (*static_assert_test_array__(void))[sizeof(char[(2 * !!(truth)) - 1])]

// See
// https://gcc.gnu.org/onlinedocs/gcc-4.7.0/cpp/Stringification.html
// for an explanation of why the extra level of macro expansion might
// be needed.
//
#define STRINGIFY(x) #x
#define XSTRINGIFY(x) STRINGIFY(x)

#define SAME_TYPE(a, b) (__builtin_types_compatible_p(typeof(a), typeof(b)))

#define POINTER_IS_ARRAY(a) (!SAME_TYPE((a), &(a)[0]))

// Statically calculate size of array
// Provide compile error if
//  - a is not a pointer
//  - a is not an array (e.g. regular pointer, "array" function parameter)
// Casting to ssize_t is necessary because y and z in (x?y:z) need to be the
// same type and we need the -1 to get the compile error
//
// ({STATIC_ASSERT(POINTER_IS_ARRAY(a)); sizeof(a)/sizeof((a)[0]);})
// does not work because our STATIC_ASSERT is not smart enough to be nested
// (NELEM is often used inside STATIC_ASSERT)
//
// The type of X in char[X] should be ptrdiff_t, but we want to avoid forcing
// the gratuitous inclusion of <stddef.h>.  "long" is good enough for the
// purpose.
//
#define NELEM(a)                                                \
    (sizeof(char[POINTER_IS_ARRAY(a) ?                          \
                 (__force long)(sizeof(a) / sizeof((a)[0])) :   \
                 (long)-1]))

#endif // !__SIMPLEST_DEFS_H__
