aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yt/misc/preprocessor.h
blob: 5b929a03b59b2839a8abe6ed2c281a32c4a3a1cf (plain) (blame)
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#pragma once

/*!
 * \file preprocessor.h
 * \brief Preprocessor metaprogramming macros
 */

#if !defined(_MSC_VER) && !defined(__GNUC__)
#   error Your compiler is not currently supported.
#endif

/*!
 * \defgroup yt_pp Preprocessor metaprogramming macros
 * \ingroup yt_commons
 *
 * This is collection of macro definitions for various metaprogramming tasks
 * with the preprocessor.
 *
 * \{
 *
 * \page yt_pp_sequences Sequences
 * Everything revolves around the concept of a \em sequence. A typical
 * sequence is encoded like <tt>(1)(2)(3)...</tt>. Internally this allows
 * to apply some macro to the every element in the sequence (see #PP_FOR_EACH).
 *
 * Note that sequences can be nested, i. e. <tt>((1)(2)(3))(a)(b)(c)</tt>
 *
 * \page yt_pp_examples Examples
 * Please refer to the unit test for an actual example of usage
 * (unittests/preprocessor_ut.cpp).
 *
 */

//! Concatenates two tokens.
#define PP_CONCAT(x, y)   PP_CONCAT_A(x, y)
//! \cond Implementation
#define PP_CONCAT_A(x, y) PP_CONCAT_B(x, y)
#define PP_CONCAT_B(x, y) x ## y
//! \endcond

//! Transforms token into the string forcing argument expansion.
#define PP_STRINGIZE(x)   PP_STRINGIZE_A(x)
//! \cond Implementation
#define PP_STRINGIZE_A(x) PP_STRINGIZE_B(x)
#define PP_STRINGIZE_B(x) #x
//! \endcond

//! \cond Implementation
#define PP_LEFT_PARENTHESIS (
#define PP_RIGHT_PARENTHESIS )
#define PP_COMMA() ,
#define PP_EMPTY()
//! \endcond

//! Removes the enclosing parens, if any.
#define PP_DEPAREN(...) PP_DEPAREN_A(PP_DEPAREN_C __VA_ARGS__)
//! \cond Implementation
#define PP_DEPAREN_C(...) PP_DEPAREN_C __VA_ARGS__
#define PP_DEPAREN_A(...) PP_DEPAREN_B(__VA_ARGS__)
#define PP_DEPAREN_B(...) PP_DEPAREN_D_ ## __VA_ARGS__
#define PP_DEPAREN_D_PP_DEPAREN_C
//! \endcond

//! Performs (non-lazy) conditional expansion.
/*!
 * \param cond Condition; should expands to either \c PP_TRUE or \c PP_FALSE.
 * \param _then Expansion result in case when \c cond holds.
 * \param _else Expansion result in case when \c cond does not hold.
 */
#define PP_IF(cond, _then, _else) PP_CONCAT(PP_IF_, cond)(_then, _else)
//! \cond Implementation
#define PP_IF_PP_TRUE(x, y) x
#define PP_IF_PP_FALSE(x, y) y
//! \endcond

//! Tests whether supplied argument can be treated as a sequence
//! (i. e. <tt>()()()...</tt>)
#define PP_IS_SEQUENCE(arg) PP_CONCAT(PP_IS_SEQUENCE_B_, PP_COUNT((PP_NIL PP_IS_SEQUENCE_A arg PP_NIL)))
//! \cond Implementation
#define PP_IS_SEQUENCE_A(_) PP_RIGHT_PARENTHESIS PP_LEFT_PARENTHESIS
#define PP_IS_SEQUENCE_B_1 PP_FALSE
#define PP_IS_SEQUENCE_B_2 PP_TRUE
//! \endcond

//! Computes the number of elements in the sequence.
#define PP_COUNT(...) PP_COUNT_IMPL(__VA_ARGS__)

//! Removes first \c n elements from the sequence.
#define PP_KILL(seq, n) PP_KILL_IMPL(seq, n)

//! Extracts the head of the sequence.
/*! For example, \code PP_HEAD((0)(1)(2)(3)) == 0 \endcode
 */
#define PP_HEAD(...) PP_HEAD_IMPL(__VA_ARGS__)

//! Extracts the tail of the sequence.
/*! For example, \code PP_TAIL((0)(1)(2)(3)) == (1)(2)(3) \endcode
 */
#define PP_TAIL(...) PP_TAIL_IMPL(__VA_ARGS__)

//! Extracts the element with the specified index from the sequence.
/*! For example, \code PP_ELEMENT((0)(1)(2)(3), 1) == 1 \endcode
 */
#define PP_ELEMENT(seq, index) PP_ELEMENT_IMPL(seq, index)

//! Applies the macro to every member of the sequence.
/*! For example,
 * \code
 * #define MyFunctor(x) +x+
 * PP_FOR_EACH(MyFunctor, (0)(1)(2)(3)) == +0+ +1+ +2+ +3+
 * \encode
 */
#define PP_FOR_EACH(what, seq) PP_FOR_EACH_IMPL(what, seq)

//! Declares an anonymous variable.
#ifdef __COUNTER__
#define PP_ANONYMOUS_VARIABLE(str) PP_CONCAT(str, __COUNTER__)
#else
#define PP_ANONYMOUS_VARIABLE(str) PP_CONCAT(str, __LINE__)
#endif

//! Insert prefix based on presence of additional arguments.
#define PP_ONE_OR_NONE(a, ...) PP_THIRD(a, ## __VA_ARGS__, a)
#define PP_THIRD(a, b, ...) __VA_ARGS__

//! \cond Implementation
#define PREPROCESSOR_GEN_H_
#include "preprocessor-gen.h"
#undef PREPROCESSOR_GEN_H_
//! \endcond

/*! \} */