blob: d7d1c5b891b6a6481995e3c0989192a408d2be87 [file] [log] [blame]
/* Copyright 2020 The Chromium OS Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
#ifndef LITHIUM_MACROLIB_H_
#define LITHIUM_MACROLIB_H_
/**
* Lithium Macrolib
* ================
* Common macros, for creating macros, and for usage in code. Common
* macros which may be defined by other headers (outside of Lithium)
* will be undefined first.
*/
/**
* Macro Construction Macros
* -------------------------
*/
/**
* Takes any amount of arguments and produces nothing.
*/
#undef EMPTY
#define EMPTY(...)
/**
* Takes no arguments and produces a comma.
*/
#undef COMMA
#define COMMA() ,
/**
* Takes no arguments and produces a semicolon.
*/
#undef SEMICOLON
#define SEMICOLON() ;
/**
* Expand and stringify a token.
*/
#undef STRINGIFY
#define STRINGIFY(token) #token
/**
* Expand and concatenate two tokens.
*/
#undef CONCAT2
#define CONCAT2(t1, t2) _LI_CONCAT2(t1, t2)
#define _LI_CONCAT2(t1, t2) t1##t2
/**
* Expand, stringify, and place a comma at the end of a token.
*/
#define STRINGIFY_C(token) #token,
/**
* Expand and place a comma at the end of a token.
*/
#define PASTE_C(token) token,
/**
* Preprocessor Lists (``PPLIST``)
* -------------------------------
* Preprocessor lists are an effective way to manage data lists using
* the preprocessor. The standard way to define a list is to define
* macro of one argument ``M``, and apply a macro ``M`` to each list
* element. For example::
*
* #define SENSORS_PPLIST(M) \
* M(ACCEL_SENSOR) \
* M(GYRO_SENSOR) \
* M(TEMP_SENSOR)
*/
/**
* Convert a ``PPLIST`` to a stringified and comma-separated
* list. Example usage::
*
* const char *const sensor_pretty_print[] =
* PPLIST_STRINGIFY(SENSORS_PPLIST);
*/
#define PPLIST_STRINGIFY(pplist) \
{ \
pplist(STRINGIFY_C) \
}
/**
* Convert a ``PPLIST`` to a comma-separated list. Example usage::
*
* enum sensor_type PPLIST_PASTE(SENSORS_PPLIST);
*/
#define PPLIST_PASTE(pplist) \
{ \
pplist(PASTE_C) \
}
/**
* Take advantage of division by zero to indicate a failure condition.
*
* :param value: The value to return.
* :param condition: The condition to assert at compile time.
* :return: The value passed as ``value``.
*
* If usage is guaranteed to be inside of a function, a braced group
* is recommended instead.
*/
#define STATIC_ASSERT_INLINE(value, condition) ((value) / !!(condition))
/**
* Get the number of elements in an array.
*
* :param arr: An array.
* :return: The number of elements in the array.
*
* For type safety, this function will cause a division-by-zero
* compile-time check failure if a pointer is passed instead of an
* array.
*/
#define ARRAY_SIZE(arr) \
STATIC_ASSERT_INLINE(sizeof(arr) / sizeof((arr)[0]), \
!__builtin_types_compatible_p(typeof(arr), \
typeof(&(arr)[0])))
/**
* Attributes
* ==========
* These are common attributes to be used on a function.
*/
/**
* Allow a static function to go unused.
*/
#undef __maybe_unused
#define __maybe_unused __attribute__((unused))
/**
* Run this function before ``main`` runs.
*/
#undef __constructor
#define __constructor __attribute__((constructor))
/**
* Run this function after ``main`` runs.
*/
#undef __destructor
#define __destructor __attribute__((destructor))
/**
* Discard this function at link time.
*/
#undef __discard
#define __discard __attribute__((section("/DISCARD/")))
/**
* This function does not return.
*/
#undef __noreturn
#define __noreturn __attribute__((noreturn))
/**
* Report an error message if this function is used.
*
* :param msg: The message to show as a compiler error.
*
* Due to limitations with Clang, this is equivalent to
* :c:macro:`__discard` on Clang.
*/
#undef __error_if_used
#if defined(__GNUC__) && !defined(__clang__)
#define __error_if_used(msg) __attribute__((error(msg)))
#else
#define __error_if_used(msg) __discard
#endif
/* Make __auto_type available in C++ */
#if defined(__cplusplus) && !defined(__auto_type)
#define __auto_type auto
#endif
#endif /* LITHIUM_MACROLIB_H_ */