/* CC0 (Public domain) - see LICENSE file for details */
#ifndef CCAN_COMPILER_H
#define CCAN_COMPILER_H
#include <hkl/ccan/ccan_config.h>

#ifndef COLD
#if HAVE_ATTRIBUTE_COLD
/**
 * COLD - a function is unlikely to be called.
 *
 * Used to mark an unlikely code path and optimize appropriately.
 * It is usually used on logging or error routines.
 *
 * Example:
 * static void COLD moan(const char *reason)
 * {
 *	fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno));
 * }
 */
#define COLD __attribute__((__cold__))
#else
#define COLD
#endif
#endif

#ifndef NORETURN
#if HAVE_ATTRIBUTE_NORETURN
/**
 * NORETURN - a function does not return
 *
 * Used to mark a function which exits; useful for suppressing warnings.
 *
 * Example:
 * static void NORETURN fail(const char *reason)
 * {
 *	fprintf(stderr, "Error: %s (%s)\n", reason, strerror(errno));
 *	exit(1);
 * }
 */
#define NORETURN __attribute__((__noreturn__))
#else
#define NORETURN
#endif
#endif

#ifndef PRINTF_FMT
#if HAVE_ATTRIBUTE_PRINTF
/**
 * PRINTF_FMT - a function takes printf-style arguments
 * @nfmt: the 1-based number of the function's format argument.
 * @narg: the 1-based number of the function's first variable argument.
 *
 * This allows the compiler to check your parameters as it does for printf().
 *
 * Example:
 * void PRINTF_FMT(2,3) my_printf(const char *prefix, const char *fmt, ...);
 */
#define PRINTF_FMT(nfmt, narg) \
	__attribute__((format(__printf__, nfmt, narg)))
#else
#define PRINTF_FMT(nfmt, narg)
#endif
#endif

#ifndef CONST_FUNCTION
#if HAVE_ATTRIBUTE_CONST
/**
 * CONST_FUNCTION - a function's return depends only on its argument
 *
 * This allows the compiler to assume that the function will return the exact
 * same value for the exact same arguments.  This implies that the function
 * must not use global variables, or dereference pointer arguments.
 */
#define CONST_FUNCTION __attribute__((__const__))
#else
#define CONST_FUNCTION
#endif

#ifndef PURE_FUNCTION
#if HAVE_ATTRIBUTE_PURE
/**
 * PURE_FUNCTION - a function is pure
 *
 * A pure function is one that has no side effects other than it's return value
 * and uses no inputs other than it's arguments and global variables.
 */
#define PURE_FUNCTION __attribute__((__pure__))
#else
#define PURE_FUNCTION
#endif
#endif
#endif

#if HAVE_ATTRIBUTE_UNUSED
#ifndef UNNEEDED
/**
 * UNNEEDED - a variable/function may not be needed
 *
 * This suppresses warnings about unused variables or functions, but tells
 * the compiler that if it is unused it need not emit it into the source code.
 *
 * Example:
 * // With some preprocessor options, this is unnecessary.
 * static UNNEEDED int counter;
 *
 * // With some preprocessor options, this is unnecessary.
 * static UNNEEDED void add_to_counter(int add)
 * {
 *	counter += add;
 * }
 */
#define UNNEEDED __attribute__((__unused__))
#endif

#ifndef NEEDED
#if HAVE_ATTRIBUTE_USED
/**
 * NEEDED - a variable/function is needed
 *
 * This suppresses warnings about unused variables or functions, but tells
 * the compiler that it must exist even if it (seems) unused.
 *
 * Example:
 *	// Even if this is unused, these are vital for debugging.
 *	static NEEDED int counter;
 *	static NEEDED void dump_counter(void)
 *	{
 *		printf("Counter is %i\n", counter);
 *	}
 */
#define NEEDED __attribute__((__used__))
#else
/* Before used, unused functions and vars were always emitted. */
#define NEEDED __attribute__((__unused__))
#endif
#endif

#ifndef UNUSED
/**
 * UNUSED - a parameter is unused
 *
 * Some compilers (eg. gcc with -W or -Wunused) warn about unused
 * function parameters.  This suppresses such warnings and indicates
 * to the reader that it's deliberate.
 *
 * Example:
 *	// This is used as a callback, so needs to have this prototype.
 *	static int some_callback(void *unused UNUSED)
 *	{
 *		return 0;
 *	}
 */
#define UNUSED __attribute__((__unused__))
#endif
#else
#ifndef UNNEEDED
#define UNNEEDED
#endif
#ifndef NEEDED
#define NEEDED
#endif
#ifndef UNUSED
#define UNUSED
#endif
#endif

#ifndef IS_COMPILE_CONSTANT
#if HAVE_BUILTIN_CONSTANT_P
/**
 * IS_COMPILE_CONSTANT - does the compiler know the value of this expression?
 * @expr: the expression to evaluate
 *
 * When an expression manipulation is complicated, it is usually better to
 * implement it in a function.  However, if the expression being manipulated is
 * known at compile time, it is better to have the compiler see the entire
 * expression so it can simply substitute the result.
 *
 * This can be done using the IS_COMPILE_CONSTANT() macro.
 *
 * Example:
 *	enum greek { ALPHA, BETA, GAMMA, DELTA, EPSILON };
 *
 *	// Out-of-line version.
 *	const char *greek_name(enum greek greek);
 *
 *	// Inline version.
 *	static inline const char *_greek_name(enum greek greek)
 *	{
 *		switch (greek) {
 *		case ALPHA: return "alpha";
 *		case BETA: return "beta";
 *		case GAMMA: return "gamma";
 *		case DELTA: return "delta";
 *		case EPSILON: return "epsilon";
 *		default: return "**INVALID**";
 *		}
 *	}
 *
 *	// Use inline if compiler knows answer.  Otherwise call function
 *	// to avoid copies of the same code everywhere.
 *	#define greek_name(g)						\
 *		 (IS_COMPILE_CONSTANT(greek) ? _greek_name(g) : greek_name(g))
 */
#define IS_COMPILE_CONSTANT(expr) __builtin_constant_p(expr)
#else
/* If we don't know, assume it's not. */
#define IS_COMPILE_CONSTANT(expr) 0
#endif
#endif

#ifndef WARN_UNUSED_RESULT
#if HAVE_WARN_UNUSED_RESULT
/**
 * WARN_UNUSED_RESULT - warn if a function return value is unused.
 *
 * Used to mark a function where it is extremely unlikely that the caller
 * can ignore the result, eg realloc().
 *
 * Example:
 * // buf param may be freed by this; need return value!
 * static char *WARN_UNUSED_RESULT enlarge(char *buf, unsigned *size)
 * {
 *	return realloc(buf, (*size) *= 2);
 * }
 */
#define WARN_UNUSED_RESULT __attribute__((__warn_unused_result__))
#else
#define WARN_UNUSED_RESULT
#endif
#endif


#if HAVE_ATTRIBUTE_DEPRECATED
/**
 * WARN_DEPRECATED - warn that a function/type/variable is deprecated when used.
 *
 * Used to mark a function, type or variable should not be used.
 *
 * Example:
 * WARN_DEPRECATED char *oldfunc(char *buf);
 */
#define WARN_DEPRECATED __attribute__((__deprecated__))
#else
#define WARN_DEPRECATED
#endif


#if HAVE_ATTRIBUTE_NONNULL
/**
 * NO_NULL_ARGS - specify that no arguments to this function can be NULL.
 *
 * The compiler will warn if any pointer args are NULL.
 *
 * Example:
 * NO_NULL_ARGS char *my_copy(char *buf);
 */
#define NO_NULL_ARGS __attribute__((__nonnull__))

/**
 * NON_NULL_ARGS - specify that some arguments to this function can't be NULL.
 * @...: 1-based argument numbers for which args can't be NULL.
 *
 * The compiler will warn if any of the specified pointer args are NULL.
 *
 * Example:
 * char *my_copy2(char *buf, char *maybenull) NON_NULL_ARGS(1);
 */
#define NON_NULL_ARGS(...) __attribute__((__nonnull__(__VA_ARGS__)))
#else
#define NO_NULL_ARGS
#define NON_NULL_ARGS(...)
#endif

#if HAVE_ATTRIBUTE_RETURNS_NONNULL
/**
 * RETURNS_NONNULL - specify that this function cannot return NULL.
 *
 * Mainly an optimization opportunity, but can also suppress warnings.
 *
 * Example:
 * RETURNS_NONNULL char *my_copy(char *buf);
 */
#define RETURNS_NONNULL __attribute__((__returns_nonnull__))
#else
#define RETURNS_NONNULL
#endif

#if HAVE_ATTRIBUTE_SENTINEL
/**
 * LAST_ARG_NULL - specify the last argument of a variadic function must be NULL.
 *
 * The compiler will warn if the last argument isn't NULL.
 *
 * Example:
 * char *join_string(char *buf, ...) LAST_ARG_NULL;
 */
#define LAST_ARG_NULL __attribute__((__sentinel__))
#else
#define LAST_ARG_NULL
#endif

#if HAVE_BUILTIN_CPU_SUPPORTS
/**
 * cpu_supports - test if current CPU supports the named feature.
 *
 * This takes a literal string, and currently only works on glibc platforms.
 *
 * Example:
 * if (cpu_supports("mmx"))
 *	printf("MMX support engaged!\n");
 */
#define cpu_supports(x) __builtin_cpu_supports(x)
#else
#define cpu_supports(x) 0
#endif /* HAVE_BUILTIN_CPU_SUPPORTS */

#endif /* CCAN_COMPILER_H */
