#ifndef MACROS_H
#define MACROS_H

/* several useful macros, mostly from glib.h */

#ifndef NULL
#  define NULL ((void *)0)
#endif

#ifndef FALSE
#  define FALSE (!1)
#endif

#ifndef TRUE
#  define TRUE (!FALSE)
#endif

#define N_ELEMENTS(arr) \
	(sizeof(arr) / sizeof((arr)[0]))

#define MEM_ALIGN(size) \
	(((size) + MEM_ALIGN_SIZE-1) & ~((size_t) MEM_ALIGN_SIZE-1))

#define PTR_OFFSET(ptr, offset) \
	((void *) (((uintptr_t) (ptr)) + ((size_t) (offset))))
#define CONST_PTR_OFFSET(ptr, offset) \
	((const void *) (((uintptr_t) (ptr)) + ((size_t) (offset))))

#define container_of(ptr, type, name) \
	(type *)((char *)(ptr) - offsetof(type, name) + \
		 COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(ptr, &((type *) 0)->name))

/* Don't use simply MIN/MAX, as they're often defined elsewhere in include
   files that are included after this file generating tons of warnings. */
#define I_MIN(a, b)  (((a) < (b)) ? (a) : (b))
#define I_MAX(a, b)  (((a) > (b)) ? (a) : (b))

/* make it easier to cast from/to pointers. assumes that
   sizeof(uintptr_t) == sizeof(void *) and they're both the largest datatypes
   that are allowed to be used. so, long long isn't safe with these. */
#define POINTER_CAST(i) \
	((void *) (((uintptr_t)NULL) + (i)))
#define POINTER_CAST_TO(p, type) \
	((type)(uintptr_t)(p))

/* Define VA_COPY() to do the right thing for copying va_list variables.
   config.h may have already defined VA_COPY as va_copy or __va_copy. */
#ifndef VA_COPY
#  if defined (__GNUC__) && defined (__PPC__) && \
      (defined (_CALL_SYSV) || defined (_WIN32))
#    define VA_COPY(ap1, ap2) (*(ap1) = *(ap2))
#  elif defined (VA_COPY_AS_ARRAY)
#    define VA_COPY(ap1, ap2) memmove ((ap1), (ap2), sizeof (va_list))
#  else /* va_list is a pointer */
#    define VA_COPY(ap1, ap2) ((ap1) = (ap2))
#  endif /* va_list is a pointer */
#endif

/* Provide convenience macros for handling structure
 * fields through their offsets.
 */
#define STRUCT_MEMBER_P(struct_p, struct_offset) \
	((void *) ((char *) (struct_p) + (long) (struct_offset)))
#define CONST_STRUCT_MEMBER_P(struct_p, struct_offset) \
	((const void *) ((const char *) (struct_p) + (long) (struct_offset)))

/* Provide simple macro statement wrappers:
   STMT_START { statements; } STMT_END;
   can be used as a single statement, as in
   if (x) STMT_START { ... } STMT_END; else ... */
#if !(defined (STMT_START) && defined (STMT_END))
#  define STMT_START do
#  define STMT_END while (0)
#endif

/* Provide macros to feature the GCC function attribute. */
#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4)
#  define ATTRS_DEFINED
#  define ATTR_FORMAT(format_idx, arg_idx) \
	__attribute__((format (printf, format_idx, arg_idx)))
#  define ATTR_FORMAT_ARG(arg_idx) \
	__attribute__((format_arg (arg_idx)))
#  define ATTR_SCANF(format_idx, arg_idx) \
	__attribute__((format (scanf, format_idx, arg_idx)))
#  define ATTR_STRFTIME(format_idx) \
	__attribute__((format (strftime, format_idx, 0)))
#  define ATTR_UNUSED __attribute__((unused))
#  define ATTR_NORETURN __attribute__((noreturn))
#  define ATTR_CONST __attribute__((const))
#  define ATTR_PURE __attribute__((pure))
#else
#  define ATTR_FORMAT(format_idx, arg_idx)
#  define ATTR_FORMAT_ARG(arg_idx)
#  define ATTR_SCANF(format_idx, arg_idx)
#  define ATTR_STRFTIME(format_idx)
#  define ATTR_UNUSED
#  define ATTR_NORETURN
#  define ATTR_CONST
#  define ATTR_PURE
#endif
#ifdef HAVE_ATTR_NULL
#  define ATTR_NULL(...) __attribute__((null(__VA_ARGS__)))
#else
#  define ATTR_NULL(...)
#endif
#ifdef HAVE_ATTR_NOWARN_UNUSED_RESULT
#  define ATTR_NOWARN_UNUSED_RESULT __attribute__((nowarn_unused_result))
#else
#  define ATTR_NOWARN_UNUSED_RESULT
#endif
#if __GNUC__ > 2
#  define ATTR_MALLOC __attribute__((malloc))
#else
#  define ATTR_MALLOC
#endif
#if __GNUC__ > 3
/* GCC 4.0 and later */
#  define ATTR_WARN_UNUSED_RESULT __attribute__((warn_unused_result))
#  define ATTR_SENTINEL __attribute__((sentinel))
#else
#  define ATTR_WARN_UNUSED_RESULT
#  define ATTR_SENTINEL
#endif
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)
/* GCC 4.3 and later */
#  define ATTR_HOT __attribute__((hot))
#  define ATTR_COLD __attribute__((cold))
#else
#  define ATTR_HOT
#  define ATTR_COLD
#endif
#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 9)
/* GCC 4.9 and later */
#  define ATTR_RETURNS_NONNULL __attribute__((returns_nonnull))
#else
#  define ATTR_RETURNS_NONNULL
#endif
#ifdef HAVE_ATTR_DEPRECATED
#  define ATTR_DEPRECATED(str) __attribute__((deprecated(str)))
#else
#  define ATTR_DEPRECATED(str)
#endif

/* Macros to provide type safety for callback functions' context parameters.
   This is used like:

   // safe-api.h file:
   typedef void safe_callback_t(struct foo *foo);

   void safe_run(safe_callback_t *callback, void *context);
   #define safe_run((safe_callback_t *)callback, \
       TRUE ? context : CALLBACK_TYPECHECK(callback, void (*)(typeof(context))))

   // safe-api.c file:
   #undef safe_run
   void safe_run(safe_callback_t *callback, void *context)
   {
       callback(context);
   }

   // in caller code:
   static void callback(struct foo *foo);
   struct foo *foo = ...;
   safe_run(callback, foo);

   The first step is to create the callback function in a normal way. Type
   safety is added to it by creating a macro that overrides the function and
   checks the callback type safety using CALLBACK_TYPECHECK().

   The CALLBACK_TYPECHECK() macro works by giving a compiling failure if the
   provided callback function isn't compatible with the specified function
   type parameter. The function type parameter must use typeof(context) in
   place of the "void *context" parameter, but otherwise use exactly the same
   function type as what the callback is. The macro then casts the given
   callback function into the type with "void *context".
*/
#ifdef HAVE_TYPE_CHECKS
#  define CALLBACK_TYPECHECK(callback, type) \
	(COMPILE_ERROR_IF_TRUE(!__builtin_types_compatible_p( \
		typeof(&callback), type)) ? 1 : 0)
#else
#  define CALLBACK_TYPECHECK(callback, type) 0
#endif

#if (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0)) && \
	!defined(__cplusplus) && !defined(STATIC_CHECKER)
#  define COMPILE_ERROR_IF_TRUE(condition) \
	(sizeof(char[1 - 2 * ((condition) ? 1 : 0)]) > 0 ? FALSE : FALSE)
#else
#  define COMPILE_ERROR_IF_TRUE(condition) FALSE
#endif

#ifdef HAVE_TYPE_CHECKS
#  define COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(_a, _b) \
	COMPILE_ERROR_IF_TRUE( \
		!__builtin_types_compatible_p(typeof(_a), typeof(_b)))
#define COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE(_a1, _a2, _b) \
	COMPILE_ERROR_IF_TRUE( \
		!__builtin_types_compatible_p(typeof(_a1), typeof(_b)) && \
		!__builtin_types_compatible_p(typeof(_a2), typeof(_b)))
#  define TYPE_CHECKS(return_type, checks, func) \
	(FALSE ? (return_type)(checks) : (func))
#else
#  define COMPILE_ERROR_IF_TYPES_NOT_COMPATIBLE(_a, _b) 0
#  define COMPILE_ERROR_IF_TYPES2_NOT_COMPATIBLE(_a1, _a2, _b) 0
#  define TYPE_CHECKS(return_type, checks, func) (func)
#endif

#if __GNUC__ > 2
#  define unlikely(expr) (__builtin_expect((expr) ? 1 : 0, 0) != 0)
#  define likely(expr) (__builtin_expect((expr) ? 1 : 0, 1) != 0)
#else
#  define unlikely(expr) expr
#  define likely(expr) expr
#endif

#if defined(__clang__) && ((__clang_major__ > 4) || (__clang_major__ == 3 && __clang_minor__ >= 9))
#  define ATTR_UNSIGNED_WRAPS __attribute__((no_sanitize("integer")))
#else
#  define ATTR_UNSIGNED_WRAPS
#endif

/* Provide macros for error handling. */
#ifdef DISABLE_ASSERTS
#  define i_assert(expr)
#else
#  define i_assert(expr)			STMT_START{			\
     if (unlikely(!(expr)))						\
       i_panic("file %s: line %d (%s): assertion failed: (%s)",		\
		__FILE__,						\
		__LINE__,						\
		__func__,					\
		#expr);			}STMT_END
#endif

/* Convenience macro to test the versions of dovecot. */
#define DOVECOT_PREREQ(maj, min, micro) \
	((DOVECOT_VERSION_MAJOR << 24) + \
	 (DOVECOT_VERSION_MINOR << 16) + \
	 DOVECOT_VERSION_MICRO >= ((maj) << 24) + ((min) << 16) + (micro))

#ifdef __cplusplus
#  undef STATIC_ARRAY
#  define STATIC_ARRAY
#endif

/* Convenience wrappers for initializing a struct with zeros, although it can
   be used for replacing other memset()s also.

   // NOTE: This is the correct way to zero the whole array
   char arr[5]; i_zero(&arr);
   // This will give compiler error (or zero only the first element):
   char arr[5]; i_zero(arr);
*/
#define i_zero(p) \
	memset(p, 0 + COMPILE_ERROR_IF_TRUE(sizeof(p) > sizeof(void *)), sizeof(*(p)))
#define i_zero_safe(p) \
	safe_memset(p, 0 + COMPILE_ERROR_IF_TRUE(sizeof(p) > sizeof(void *)), sizeof(*(p)))

#define ST_CHANGED(st_a, st_b) \
	((st_a).st_mtime != (st_b).st_mtime || \
	 ST_MTIME_NSEC(st_a) != ST_MTIME_NSEC(st_b) || \
	 (st_a).st_size != (st_b).st_size || \
	 (st_a).st_ino != (st_b).st_ino)

#ifdef HAVE_UNDEFINED_SANITIZER
# define ATTR_NO_SANITIZE(x) __attribute__((no_sanitize((x))))
#else
# define ATTR_NO_SANITIZE(x)
#endif

/* gcc and clang do this differently, see
   https://gcc.gnu.org/onlinedocs/gcc-10.2.0/gcc/Common-Function-Attributes.html */
#ifdef HAVE_FSANITIZE_UNDEFINED
# ifdef __clang__
#  define ATTR_NO_SANITIZE_UNDEFINED ATTR_NO_SANITIZE("undefined")
# else
#  define ATTR_NO_SANITIZE_UNDEFINED __attribute__((no_sanitize_undefined))
# endif
#else
# define ATTR_NO_SANITIZE_UNDEFINED
#endif

#ifdef HAVE_FSANITIZE_INTEGER
# define ATTR_NO_SANITIZE_INTEGER ATTR_NO_SANITIZE("integer")
# define ATTR_NO_SANITIZE_IMPLICIT_CONVERSION ATTR_NO_SANITIZE("implicit-conversion")
#else
# define ATTR_NO_SANITIZE_INTEGER
# define ATTR_NO_SANITIZE_IMPLICIT_CONVERSION
#endif

/* negate enumeration flags in a way that avoids implicit conversion */
#ifndef STATIC_CHECKER
#  define ENUM_NEGATE(x) \
	((unsigned int)(~(x)) + COMPILE_ERROR_IF_TRUE(sizeof((x)) > sizeof(int) || (x) < 0 || (x) > INT_MAX))
#else
/* clang scan-build keeps complaining about x > 2147483647 case, so disable the
   sizeof check. */
#  define ENUM_NEGATE(x) ((unsigned int)(~(x)))
#endif

#endif
