#ifndef HEADER_Macros
#define HEADER_Macros
/*
htop - Macros.h
(C) 2020-2023 htop dev team
Released under the GNU GPLv2+, see the COPYING file
in the source distribution for its full text.
*/

#include <assert.h> // IWYU pragma: keep
#include <math.h>
#include <stdbool.h>
#include <string.h> // IWYU pragma: keep


#ifndef MINIMUM
#define MINIMUM(a, b)                  ((a) < (b) ? (a) : (b))
#endif

#ifndef MAXIMUM
#define MAXIMUM(a, b)                  ((a) > (b) ? (a) : (b))
#endif

#ifndef CLAMP
#define CLAMP(x, low, high)            (assert((low) <= (high)), ((x) > (high)) ? (high) : MAXIMUM(x, low))
#endif

#ifndef ARRAYSIZE
#define ARRAYSIZE(x)                   (sizeof(x) / sizeof((x)[0]))
#endif

#ifndef SPACESHIP_NUMBER
#define SPACESHIP_NUMBER(a, b)         (((a) > (b)) - ((a) < (b)))
#endif

#ifndef SPACESHIP_NULLSTR
#define SPACESHIP_NULLSTR(a, b)        strcmp((a) ? (a) : "", (b) ? (b) : "")
#endif

#ifndef SPACESHIP_DEFAULTSTR
#define SPACESHIP_DEFAULTSTR(a, b, s)  strcmp((a) ? (a) : (s), (b) ? (b) : (s))
#endif

#ifdef  __GNUC__  // defined by GCC and Clang

#define ATTR_FORMAT(type, index, check) __attribute__((format (type, index, check)))
#define ATTR_NORETURN                   __attribute__((noreturn))
#define ATTR_UNUSED                     __attribute__((unused))
#define ATTR_MALLOC                     __attribute__((malloc))

#else /* __GNUC__ */

#define ATTR_FORMAT(type, index, check)
#define ATTR_NORETURN
#define ATTR_UNUSED
#define ATTR_MALLOC

#endif /* __GNUC__ */

#ifdef HAVE_ATTR_NONNULL

#define ATTR_NONNULL                    __attribute__((nonnull))
#define ATTR_NONNULL_N(...)             __attribute__((nonnull(__VA_ARGS__)))

#else

#define ATTR_NONNULL
#define ATTR_NONNULL_N(...)

#endif /* HAVE_ATTR_NONNULL */

#ifdef HAVE_ATTR_RETNONNULL

#define ATTR_RETNONNULL                 __attribute__((returns_nonnull))

#else

#define ATTR_RETNONNULL

#endif /* HAVE_ATTR_RETNONNULL */

#ifdef HAVE_ATTR_ALLOC_SIZE

#define ATTR_ALLOC_SIZE1(a)             __attribute__((alloc_size (a)))
#define ATTR_ALLOC_SIZE2(a, b)          __attribute__((alloc_size (a, b)))

#else

#define ATTR_ALLOC_SIZE1(a)
#define ATTR_ALLOC_SIZE2(a, b)

#endif /* HAVE_ATTR_ALLOC_SIZE */

#ifdef HAVE_ATTR_ACCESS

#define ATTR_ACCESS2(mode, ref)         __attribute__((access (mode, ref)))
#define ATTR_ACCESS3(mode, ref, size)   __attribute__((access (mode, ref, size)))

#else

#define ATTR_ACCESS2(mode, ref)
#define ATTR_ACCESS3(mode, ref, size)

#endif /* HAVE_ATTR_ACCESS */

#define ATTR_ACCESS2_R(ref)              ATTR_ACCESS2(read_only, ref)
#define ATTR_ACCESS3_R(ref, size)        ATTR_ACCESS3(read_only, ref, size)

#define ATTR_ACCESS2_RW(ref)             ATTR_ACCESS2(read_write, ref)
#define ATTR_ACCESS3_RW(ref, size)       ATTR_ACCESS3(read_write, ref, size)

#define ATTR_ACCESS2_W(ref)              ATTR_ACCESS2(write_only, ref)
#define ATTR_ACCESS3_W(ref, size)        ATTR_ACCESS3(write_only, ref, size)

// ignore casts discarding const specifier, e.g.
//     const char []     ->  char * / void *
//     const char *[2]'  ->  char *const *
#if defined(__clang__)
#define IGNORE_WCASTQUAL_BEGIN  _Pragma("clang diagnostic push") \
                                _Pragma("clang diagnostic ignored \"-Wcast-qual\"")
#define IGNORE_WCASTQUAL_END    _Pragma("clang diagnostic pop")
#elif defined(__GNUC__)
#define IGNORE_WCASTQUAL_BEGIN  _Pragma("GCC diagnostic push") \
                                _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
#define IGNORE_WCASTQUAL_END    _Pragma("GCC diagnostic pop")
#else
#define IGNORE_WCASTQUAL_BEGIN
#define IGNORE_WCASTQUAL_END
#endif

/* Cheaper function for checking NaNs. Unlike the standard isnan(), this may
   throw an FP exception on a "signaling NaN".
   (ISO/IEC TS 18661-1 and the C23 standard stated that isnan() throws no
   exceptions even with a "signaling NaN") */
static inline bool isNaN(double x) {
   return !isgreaterequal(x, x);
}

/* Checks if x >= 0.0 but returns false if x is NaN. Because IEEE 754 considers
   -0.0 == 0.0, this function treats both zeros as nonnegative. */
static inline bool isNonnegative(double x) {
   return isgreaterequal(x, 0.0);
}

/* Checks if x > 0.0 but returns false if x is NaN. */
static inline bool isPositive(double x) {
   return isgreater(x, 0.0);
}

/* This subtraction is used by Linux / NetBSD / OpenBSD for calculation of CPU usage items. */
static inline unsigned long long saturatingSub(unsigned long long a, unsigned long long b) {
   return a > b ? a - b : 0;
}

#endif
