/***********************************************************************************************************************************
General Macros

Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
Portions Copyright (c) 1994, Regents of the University of California
***********************************************************************************************************************************/
#ifndef COMMON_MACRO_H
#define COMMON_MACRO_H

/***********************************************************************************************************************************
Convert the parameter to a zero-terminated string

Useful for converting non-string types (e.g. int) to strings for inclusion in messages.
***********************************************************************************************************************************/
#define STRINGIFY_HELPER(param)                                     #param
#define STRINGIFY(param)                                            STRINGIFY_HELPER(param)

/***********************************************************************************************************************************
If param2 > param1 then assign it to param1

Useful for ensuring coverage in cases where compared values may be always ascending or descending.
***********************************************************************************************************************************/
#define MAX_ASSIGN(param1, param2)                                                                                                 \
    do                                                                                                                             \
    {                                                                                                                              \
        if (param2 > param1)                                                                                                       \
            param1 = param2;                                                                                                       \
    }                                                                                                                              \
    while (0)

/***********************************************************************************************************************************
If the "condition" (a compile-time-constant expression) evaluates to false then throw a compile error using the "message" (a string
literal).

gcc 4.6 and up supports _Static_assert(), but there are bizarre syntactic placement restrictions. Macros STATIC_ASSERT_STMT() and
STATIC_ASSERT_EXP() make it safe to use as a statement or in an expression, respectively.

Otherwise we fall back on a kluge that assumes the compiler will complain about a negative width for a struct bit-field. This will
not include a helpful error message, but it beats not getting an error at all. Note that when std=c99 it looks like gcc is using the
same kluge.

Adapted from PostgreSQL src/include/c.h.
***********************************************************************************************************************************/
#ifdef HAVE_STATIC_ASSERT

#define STATIC_ASSERT_STMT(condition, message)                                                                                     \
    do {_Static_assert(condition, message);} while (0)

#define STATIC_ASSERT_EXPR(condition, message)                                                                                     \
    ((void)({STATIC_ASSERT_STMT(condition, message); true;}))

#else

#define STATIC_ASSERT_STMT(condition, message)                                                                                     \
    ((void)sizeof(struct {int static_assert_failure : (condition) ? 1 : -1;}))

#define STATIC_ASSERT_EXPR(condition, message)                                                                                     \
    STATIC_ASSERT_STMT(condition, message)

#endif

/***********************************************************************************************************************************
Allows casting const-ness away from an expression, but doesn't allow changing the type. Enforcement of the latter currently only
works for gcc-like compilers.

Note that it is not safe to cast const-ness away if the result will ever be modified (it would be undefined behavior). Doing so can
cause compiler mis-optimizations or runtime crashes (by modifying read-only memory). It is only safe to use when the result will not
be modified, but API design or language restrictions prevent you from declaring that (e.g. because a function returns both const and
non-const variables).

Note that this only works in function scope, not for global variables (it would be nice, but not trivial, to improve that).

Adapted from PostgreSQL src/include/c.h.
***********************************************************************************************************************************/
#ifdef HAVE_BUILTIN_TYPES_COMPATIBLE_P
#define UNCONSTIFY(type, expression)                                                                                               \
    (STATIC_ASSERT_EXPR(__builtin_types_compatible_p(__typeof(expression), const type), "invalid cast"), (type)(expression))
#else
#define UNCONSTIFY(type, expression)                                                                                               \
    ((type)(expression))
#endif

/***********************************************************************************************************************************
Determine the alignment of a data type

This macro reduces to a constant so it is safe to use anywhere a constant is allowed, e.g. a switch statement case.
***********************************************************************************************************************************/
#define ALIGN_OF(type) ((size_t)&((struct {char c; type t;} *)0)->t)

/***********************************************************************************************************************************
Determine the byte offset required to align a type after an arbitrary number of bytes

This is useful for determining how to correctly align a type in a buffer that is being dynamically built up like a struct.
***********************************************************************************************************************************/
#define ALIGN_OFFSET(type, bytes) (ALIGN_OF(type) - ((bytes) % ALIGN_OF(type)))

/***********************************************************************************************************************************
Determine size of a type in a struct

Using sizeof() on a struct member requires additional syntax.
***********************************************************************************************************************************/
#define SIZE_OF_STRUCT_MEMBER(struct, member) sizeof(((struct){0}).member)

/***********************************************************************************************************************************
Determine the length of an array that can be determined at compile time

For this macro to work correctly the array must be declared like:

int intList[] = {0, 1};

It will not work for an array declared like:

int *intList;
***********************************************************************************************************************************/
#define LENGTH_OF(array) (sizeof(array) / sizeof((array)[0]))

#endif
