drgn/libdrgn/pp.h
Omar Sandoval 87b7292aa5 Relicense drgn from GPLv3+ to LGPLv2.1+
drgn is currently licensed as GPLv3+. Part of the long term vision for
drgn is that other projects can use it as a library providing
programmatic interfaces for debugger functionality. A more permissive
license is better suited to this goal. We decided on LGPLv2.1+ as a good
balance between software freedom and permissiveness.

All contributors not employed by Meta were contacted via email and
consented to the license change. The only exception was the author of
commit c4fbf7e589 ("libdrgn: fix for compilation error"), who did not
respond. That commit reverted a single line of code to one originally
written by me in commit 640b1c011d ("libdrgn: embed DWARF index in
DWARF info cache").

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2022-11-01 17:05:16 -07:00

138 lines
4.5 KiB
C

// Copyright (c) Meta Platforms, Inc. and affiliates.
// SPDX-License-Identifier: LGPL-2.1-or-later
/**
* @file
*
* Preprocessor utilities.
*
* See @ref Preprocessor.
*/
#ifndef DRGN_PP_H
#define DRGN_PP_H
/**
* @ingroup Internals
*
* @defgroup Preprocessor Preprocessor
*
* Preprocessor metaprogramming
*
* This provides several macros that can be used for preprocessor
* metaprogramming. It is inspired by the [Boost Preprocessing
* library](https://www.boost.org/doc/libs/release/libs/preprocessor/doc/index.html).
*
* @{
*/
/**
* Get the number of variadic arguments.
*
* ```
* PP_NARGS(a, b, c) // Expands to 3
* #define ARGS x, y
* PP_NARGS(ARGS) // Expands to 2
* PP_NARGS() // Expands to 1 (one empty argument, not no arguments)
* ```
*
* Note that standard C requires at least one argument for the "..." in a
* variadic macro, so an empty argument list is actually a single (empty)
* argument.
*
* @hideinitializer
*/
#define PP_NARGS(...) PP_NARGS_I(__VA_ARGS__, 64, 63, 62, 61, 60, 59, 58, 57, 56, 55, 54, 53, 52, 51, 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
/** @cond */
#define PP_NARGS_I(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, _61, _62, _63, _64, N, ...) N
/** @endcond */
/**
* Overload a macro based on the number of arguments.
*
* This expands to @p prefix concatenated with the number of arguments (as
* determined by @ref PP_NARGS()). Use it like so:
*
* ```
* #define DEFINE_ARRAY(...) PP_OVERLOAD(DEFINE_ARRAY_I, __VA_ARGS__)(__VA_ARGS__)
* #define DEFINE_ARRAY_I2(name, type) DEFINE_ARRAY_I3(a, b, DEFAULT_ARRAY_SIZE)
* #define DEFINE_ARRAY_I3(name, type, size) type name[size]
* #define DEFAULT_ARRAY_SIZE 5
*
* DEFINE_ARRAY(int, several); // Expands to int several[5];
* DEFINE_ARRAY(int, couple, 2); // Expands to int couple[2];
* ```
*
* @hideinitializer
*/
#define PP_OVERLOAD(prefix, ...) PP_OVERLOAD_CAT_I(prefix, PP_NARGS(__VA_ARGS__))
/** @cond */
#define PP_OVERLOAD_CAT_I(a, b) PP_OVERLOAD_CAT_II(a, b)
#define PP_OVERLOAD_CAT_II(a, b) a##b
/** @endcond */
/**
* Expand and concatenate arguments.
*
* This expands each argument and then joins them with the `##` operator.
* `PP_CAT` takes two arguments, `PP_CAT3` takes three, `PP_CAT4` takes four,
* etc.
*
* ```
* #define a foo
* #define b bar
* PP_CAT(a, b) // Expands to foobar
* ```
*
* Intermediate results are not expanded:
* ```
* #define HELLO oops
* PP_CAT3(HELL, O, WORLD) // Expands to HELLOWORLD, _not_ oopsWORLD
* ```
*
* All possible intermediate results must be valid preprocessing tokens:
* ```
* PP_CAT3(1e, +, 3) // Undefined because +3 is not a valid preprocessing token
* ```
*
* @hideinitializer
*/
#define PP_CAT(_0, _1) PP_CAT_I2(_0, _1)
#define PP_CAT3(_0, _1, _2) PP_CAT_I3(_0, _1, _2)
#define PP_CAT4(_0, _1, _2, _3) PP_CAT_I4(_0, _1, _2, _3)
#define PP_CAT5(_0, _1, _2, _3, _4) PP_CAT_I5(_0, _1, _2, _3, _4)
#define PP_CAT6(_0, _1, _2, _3, _4, _5) PP_CAT_I6(_0, _1, _2, _3, _4, _5)
#define PP_CAT7(_0, _1, _2, _3, _4, _5, _6) PP_CAT_I7(_0, _1, _2, _3, _4, _5, _6)
#define PP_CAT8(_0, _1, _2, _3, _4, _5, _6, _7) PP_CAT_I8(_0, _1, _2, _3, _4, _5, _6, _7)
/** @cond */
#define PP_CAT_I2(_0, _1) _0##_1
#define PP_CAT_I3(_0, _1, _2) _0##_1##_2
#define PP_CAT_I4(_0, _1, _2, _3) _0##_1##_2##_3
#define PP_CAT_I5(_0, _1, _2, _3, _4) _0##_1##_2##_3##_4
#define PP_CAT_I6(_0, _1, _2, _3, _4, _5) _0##_1##_2##_3##_4##_5
#define PP_CAT_I7(_0, _1, _2, _3, _4, _5, _6) _0##_1##_2##_3##_4##_5##_6
#define PP_CAT_I8(_0, _1, _2, _3, _4, _5, _6, _7) _0##_1##_2##_3##_4##_5##_6##_7
/** @endcond */
/**
* Create a unique name.
*
* This can be used to avoid name collisions and shadowing in macros that define
* local variables.
*
* ```
* #define SWAP(a, b) SWAP_I(a, b, PP_UNIQUE(tmp))
* #define SWAP_I(a, b, tmp) do { typeof(a) tmp = (a); (a) = (b); (b) = tmp; } while (0)
* ```
*
* @param[in] prefix Prefix for unique name. This makes the created name more
* recognizable in compiler diagnostics and debuggers. This is not expanded.
*
* @hideinitializer
*/
#define PP_UNIQUE(prefix) PP_CAT(prefix##__PP_UNIQUE_, __COUNTER__)
/** @} */
#endif /* DRGN_PP_H */