-
Notifications
You must be signed in to change notification settings - Fork 1
/
pp_iter.h
284 lines (227 loc) · 11.1 KB
/
pp_iter.h
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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
/**
* @file
*
* pp_iter.h
* Some useful c preprocessor extensions for dealing with variadic macros
*
* @author Cormac Cannon ([email protected])
*
* This is auto-generated code. The generator script and further background/usage info may be found here:
* https://github.com/cormacc/va_args_iterators
*
* Autogenerated on 24/06/2022 10:16
* - Script: pp_iterators.rb
* - Max argument count: 63
*
* I initially encountered the variadic macro counting logic in this post by Laurent Deniau:
* https://groups.google.com/forum/#!topic/comp.std.c/d-6Mj5Lko_s
* Refined by arpad. and zhangj to handle the no-argument case
*
* The (preferred) recursive implementations of PP_EACH, PP_EACH_IDX and PP_PAR_EACH_IDX are based on an excellent series of posts by Saad Ahmad
* http://saadahmad.ca/cc-preprocessor-metaprogramming-2/
*
* The non- (or semi-) recursive PP_EACH implementation is based on this blog post by Daniel Hardman:
* https://codecraft.co/2014/11/25/variadic-macros-tricks/
*
* The non-recursive PP_EACH_IDX and PP_PAR_EACH_IDX macro implementations extend the non-recursive PP_EACH implementation
* described in this (anonymous) blog post:
* http://ptspts.blogspot.ie/2013/11/how-to-apply-macro-to-all-arguments-of.html
*
* The MSVC macro expansion fix was lifted from the excellent fake function framework:
* https://github.com/meekrosoft/fff
*/
#ifndef PP_ITER_H
# define PP_ITER_H
# ifdef __cplusplus
extern "C" {
# endif
//Preprocessor features
#define PP_IS_GCC_EXTENDED (defined(__GNUC__) && !defined(__STRICT_ANSI__))
#define PP_IS_MSVC_EXPERIMENTAL (defined(_MSVC_TRADITIONAL) && !_MSVC_TRADITIONAL)
#define PP_IS_CONFORMANT (PP_IS_GCC_EXTENDED || PP_IS_MSVC_EXPERIMENTAL)
//Defer / evaluate macros
#ifndef DEFER
#define PP_NOP()
#define DEFER(...) __VA_ARGS__ PP_NOP()
#define DEFER2(...) __VA_ARGS__ DEFER(PP_NOP) ()
#define DEFER3(...) __VA_ARGS__ DEFER2(PP_NOP) ()
#define DEFER4(...) __VA_ARGS__ DEFER3(PP_NOP) ()
#define DEFER5(...) __VA_ARGS__ DEFER4(PP_NOP) ()
#define DEFER6(...) __VA_ARGS__ DEFER5(PP_NOP) ()
#endif //DEFER
#ifndef EVAL
#define EVAL(...) _EVAL_6(__VA_ARGS__)
#define _EVAL_1(...) __VA_ARGS__
#define _EVAL_2(...) _EVAL_1(_EVAL_1(__VA_ARGS__))
#define _EVAL_3(...) _EVAL_2(_EVAL_2(__VA_ARGS__))
#define _EVAL_4(...) _EVAL_3(_EVAL_3(__VA_ARGS__))
#define _EVAL_5(...) _EVAL_4(_EVAL_4(__VA_ARGS__))
#define _EVAL_6(...) _EVAL_5(_EVAL_5(__VA_ARGS__))
#endif //EVAL
#ifndef EVAL_
#define EVAL_(...) _EVAL__6(__VA_ARGS__)
#define _EVAL__1(...) __VA_ARGS__
#define _EVAL__2(...) _EVAL__1(_EVAL__1(__VA_ARGS__))
#define _EVAL__3(...) _EVAL__2(_EVAL__2(__VA_ARGS__))
#define _EVAL__4(...) _EVAL__3(_EVAL__3(__VA_ARGS__))
#define _EVAL__5(...) _EVAL__4(_EVAL__4(__VA_ARGS__))
#define _EVAL__6(...) _EVAL__5(_EVAL__5(__VA_ARGS__))
#endif //EVAL_
//Token concatenation (tuple-aware)
#ifndef PP_CAT
#define PP_CAT
// Defer the call to the CAT so that we get the updated parameters first
#define CAT(a, b) _CAT_EVAL ( _CAT_EXPAND_PARAMETERS(a, b) )
#define _CAT_EVAL(...) _CAT_HELPER __VA_ARGS__
// Find the result of testing whether a macro is enclosed or not
#define _CAT_EXPAND_PARAMETERS(a, b) (a, _CAT_PAREN_CHECK b, DEFAULT, b )
#define _CAT_PAREN_CHECK(...) EXPANDED, ENCLOSED, (__VA_ARGS__) ) EAT (
// Pattern match the result of testing if it is enclose or not
#define _CAT_HELPER(a, _, f, b) _CAT_HELPER_ ## f (a, b)
#define _CAT_HELPER_ENCLOSED(a, b) a b
#define _CAT_HELPER_DEFAULT(a, b) a ## b
#endif //PP_CAT
//Logical operations
#ifndef PP_LOGIC
#define PP_LOGIC
//Usage: IF(<condition>) (<then>, <else>)
#define IF(value) CAT(_IF_, value)
#define _IF_1(true, ...) true
#define _IF_0(true, ...) __VA_ARGS__
#define NOT(x) PP_MATCHER ( CAT(NOT_, x), 0 )
#define NOT_0 EXISTS(1)
//== Building blocks
//PP_MATCHER
#define PP_MATCHER(value, ...) IF ( _MATCH(_MATCH_FIND(value)) ) ( _MATCH_EXTRACT(value), __VA_ARGS__ )
#define _MATCH(x) CAT(__MATCH_, x)
#define __MATCH_EXISTS(...) 1
#define __MATCH_UNMATCHED 0
#define _MATCH_FIND(x) __MATCH_RESULT_EXTRACT ( __MATCH_RESULT_FIND(x) )
/**
* Extract 2nd element of a match result in the format:
* (IGNORED, EXISTS(DEFINED_VALUE)) or (IGNORED, UNMATCHED)
* This is appended to __MATCH_ to convert result to a boolean,
*/
#define __MATCH_RESULT_EXTRACT(x) __MATCH_RESULT_EXTRACT_HELPER x
#define __MATCH_RESULT_EXTRACT_HELPER(match, return_value) return_value
/**
* __MATCH_RESULT_FIND( EXISTS(bla) ) returns ( EXPANDED, EXISTS(bla) )
* __MATCH_RESULT_FIND( bla ) returns ( TEST_bla, UNMATCHED)
*/
#define __MATCH_RESULT_FIND(x) ( CAT(__MATCH_RESULT_EXPAND_, x), UNMATCHED )
#define __MATCH_RESULT_EXPAND_EXISTS(...) EXPANDED, EXISTS(__VA_ARGS__) ) EAT (
#define EAT(...)
//_MATCH_EXTRACT / __MATCH_EXTRACT_EXISTS
#define _MATCH_EXTRACT(value) CAT(__MATCH_EXTRACT_, value)
#define __MATCH_EXTRACT_EXISTS(...) __VA_ARGS__
#endif //PP_LOGIC
//Lists (HEAD, TAIL, ISEMPTY etc.)
#ifndef PP_LISTS
#define PP_LISTS
#define HEAD(FIRST, ...) FIRST
#define TAIL(FIRST, ...) __VA_ARGS__
#define TEST_LAST EXISTS(1)
#define NOT_EMPTY(...) NOT(IS_EMPTY(__VA_ARGS__))
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define IS_EMPTY(...) NOT(PP_NARG(__VA_ARGS__))
#else
#define IS_EMPTY(...) _ISEMPTY( /* test if there is just one argument, eventually an empty one */ HAS_COMMA(__VA_ARGS__), /* test if _TRIGGER_PARENTHESIS_ together with the argument adds a comma */ HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__), /* test if the argument together with a parenthesis adds a comma */ HAS_COMMA(__VA_ARGS__ (/*empty*/)), /* test if placing it between _TRIGGER_PARENTHESIS_ and the parenthesis adds a comma */ HAS_COMMA(_TRIGGER_PARENTHESIS_ __VA_ARGS__ (/*empty*/)) )
#define _ISEMPTY(_0, _1, _2, _3) HAS_COMMA(PASTE5(_IS_EMPTY_CASE_, _0, _1, _2, _3))
#define HAS_COMMA(...) PP_ARG_N(__VA_ARGS__, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)
#define _TRIGGER_PARENTHESIS_(...) ,
#define PASTE5(_0, _1, _2, _3, _4) _0 ## _1 ## _2 ## _3 ## _4
#define _IS_EMPTY_CASE_0001 ,
#endif
#endif //PP_LISTS
//Tuples
#ifndef PP_TUPLES
#define PP_TUPLES
#define PAREN(...) ( __VA_ARGS__ )
#define DEPAREN(...) DEPAREN_ __VA_ARGS__
#define DEPAREN_(...) __VA_ARGS__
#define IS_ENCLOSED(x, ...) PP_MATCHER ( IS_ENCLOSED_TEST x, 0 )
#define IS_ENCLOSED_TEST(...) EXISTS(1)
#define IF_ENCLOSED(...) CAT(_IF_ENCLOSED_, IS_ENCLOSED(__VA_ARGS__))
#define _IF_ENCLOSED_0(true, ...) __VA_ARGS__
#define _IF_ENCLOSED_1(true, ...) true
// This function will optionally remove parentheses around its arguments
// if there are any. Otherwise it will return normally
#define OPT_DEPAREN(...) IF_ENCLOSED (__VA_ARGS__) ( DEPAREN(__VA_ARGS__), __VA_ARGS__ )
#endif //PP_TUPLES
//Argument counting
#ifndef PP_UTIL
#define PP_UTIL
#define EXPAND(x) x
#define PP_SEQ_N() 0, 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
#define PP_RSEQ_N() 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
#endif //PP_UTIL
#ifndef PP_NARG
#define PP_ARG_N(...) EXPAND(_PP_ARG_N(__VA_ARGS__))
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
#define PP_NARG(...) EXPAND(PP_ARG_N(_0, ##__VA_ARGS__, PP_RSEQ_N()))
#define _PP_ARG_N(_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
#else
#define PP_NARG(...) EXPAND(PP_ARG_N(__VA_ARGS__, PP_RSEQ_N()))
#define _PP_ARG_N(_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, N, ...) N
#endif
#endif //PP_NARG
//PP_EACH
#ifndef PP_EACH
#define PP_EACH(TF, ...) \
EVAL(_PP_EACH_DEFER(TF, __VA_ARGS__))
#define _PP_EACH_DEFER(TF, ...) \
IF ( NOT_EMPTY( __VA_ARGS__ ) ) \
( \
DEFER(TF) (OPT_DEPAREN(HEAD(__VA_ARGS__))) \
DEFER2 ( __PP_EACH_DEFER ) () (TF, TAIL(__VA_ARGS__)) \
)
//This indirection along with the DEFER2 and EVAL macros allows the recursive implementation of _PP_EACH_DEFER
#define __PP_EACH_DEFER() _PP_EACH_DEFER
#endif //PP_EACH
//PP_EACH_IDX
#ifndef PP_EACH_IDX
#define PP_EACH_IDX(TF, ...) EVAL(_PP_EACH_IDX_DEFER(TF, (PP_SEQ_N()), __VA_ARGS__))
#define _PP_EACH_IDX_DEFER(TF, VA_INDICES, ...) \
IF ( NOT_EMPTY( __VA_ARGS__ ) ) \
( \
DEFER2(TF) (OPT_DEPAREN(HEAD(__VA_ARGS__)), DEFER(HEAD)(DEPAREN(VA_INDICES))) \
DEFER2 ( __PP_EACH_IDX_DEFER ) () (TF, (TAIL VA_INDICES), TAIL(__VA_ARGS__)) \
)
#define __PP_EACH_IDX_DEFER() _PP_EACH_IDX_DEFER
#endif //PP_EACH_IDX
//PP_PAR_EACH_IDX
#ifndef PP_PAR_EACH_IDX
#define PP_PAR_EACH_IDX(TF, FARGS, ...) EVAL(_PP_PAR_EACH_IDX_DEFER(TF, FARGS, (PP_SEQ_N()), __VA_ARGS__))
#define _PP_PAR_EACH_IDX_DEFER(TF, FARGS, VA_INDICES, ...) \
IF ( NOT_EMPTY( __VA_ARGS__ ) ) \
( \
DEFER2(TF) (OPT_DEPAREN(FARGS), OPT_DEPAREN(HEAD(__VA_ARGS__)), DEFER(HEAD)(DEPAREN(VA_INDICES))) \
DEFER2 ( __PP_PAR_EACH_IDX_DEFER ) () (TF, FARGS, (TAIL VA_INDICES), TAIL(__VA_ARGS__)) \
)
#define __PP_PAR_EACH_IDX_DEFER() _PP_PAR_EACH_IDX_DEFER
#endif //PP_PAR_EACH_IDX
//PP_xPAR_EACH_IDX (Wrappers for deprecated macros)
#define PP_1PAR_EACH_IDX(TF, P1, ...) PP_PAR_EACH_IDX(TF, (P1), __VA_ARGS__)
#define PP_2PAR_EACH_IDX(TF, P1, P2, ...) PP_PAR_EACH_IDX(TF, (P1, P2), __VA_ARGS__)
//PP_COMMA
#ifndef PP_COMMA
#define PP_COMMA() ,
#endif //PP_COMMA
//PP_COMMA_EACH
#ifndef PP_COMMA_EACH
#define PP_COMMA_EACH(TF, ...) \
EVAL(_PP_COMMA_EACH_DEFER(TF, __VA_ARGS__))
#define _PP_COMMA_EACH_DEFER(TF, ...) \
IF ( NOT_EMPTY( __VA_ARGS__ ) ) \
( \
DEFER(TF) (OPT_DEPAREN(HEAD(__VA_ARGS__))) \
IF ( NOT_EMPTY(TAIL(__VA_ARGS__))) (PP_COMMA()) \
DEFER2 ( __PP_COMMA_EACH_DEFER ) () (TF, TAIL(__VA_ARGS__)) \
)
//This indirection along with the DEFER2 and EVAL macros allows the recursive implementation of _PP_COMMA_EACH_DEFER
#define __PP_COMMA_EACH_DEFER() _PP_COMMA_EACH_DEFER
#endif //PP_COMMA_EACH
# ifdef __cplusplus
}
# endif
#endif /* PP_ITER_H */