Preprocessor.hpp
Go to the documentation of this file.
1 //
3 // Aurora C++ Library
4 // Copyright (c) 2012-2016 Jan Haller
5 //
6 // This software is provided 'as-is', without any express or implied
7 // warranty. In no event will the authors be held liable for any damages
8 // arising from the use of this software.
9 //
10 // Permission is granted to anyone to use this software for any purpose,
11 // including commercial applications, and to alter it and redistribute it
12 // freely, subject to the following restrictions:
13 //
14 // 1. The origin of this software must not be misrepresented; you must not
15 // claim that you wrote the original software. If you use this software
16 // in a product, an acknowledgment in the product documentation would be
17 // appreciated but is not required.
18 //
19 // 2. Altered source versions must be plainly marked as such, and must not be
20 // misrepresented as being the original software.
21 //
22 // 3. This notice may not be removed or altered from any source distribution.
23 //
25 
28 
29 // Minimalistic implementation inspired by Boost.Preprocessor
30 // Tricks used:
31 // - Map numbers/values to other values: Concatenate macro with value; result is a predefined macro which is then substituted
32 // - Force expansion: Forward macros to others that effectively do the same (often 2 layers of indirection)
33 // - Unpack tuples: Call macro without parenthesis around argument
34 // - Count VA arguments: Forward them to another VA macro with enumerated argument list
35 // - Detect empty arguments: Exploit property of function-style macros that are not substituted without an argument list
36 // - Get rid of garbage passed as part of argument: Forward to VA macro that consumes all arguments
37 //
38 // Notes:
39 // - Preprocessor metaprogramming is a whole different approach than anything else from C++; nothing is intuitive
40 // - AURORA_PP_AT() can be implemented without O(n^2) helper macros, e.g. in <boost/preprocessor/array/elem.hpp>
41 // - Passing __VA_ARGS__ to non-variadic macros does not work reliably
42 // (see http://www.boost.org/doc/libs/1_55_0/libs/preprocessor/doc/topics/variadic_macros.html).
43 // - Some macros behave differently when deeply nested; it may be difficult to combine them
44 // - Many macros behave differently on VC++ and g++, just in case it gets boring
45 
46 
47 #ifndef AURORA_PREPROCESSOR_HPP
48 #define AURORA_PREPROCESSOR_HPP
49 
50 #include <Aurora/Config.hpp>
51 
52 
55 
58 #define AURORA_PP_LIMIT 5
59 
60 
61 // Concatenation
62 #define AURORA_PP_CAT_IMPL(a, b) a ## b
63 
77 #define AURORA_PP_CAT(a, b) AURORA_PP_CAT_IMPL(a, b)
78 #define AURORA_PP_CAT3(a, b, c) AURORA_PP_CAT(AURORA_PP_CAT(a, b), c)
79 #define AURORA_PP_CAT4(a, b, c, d) AURORA_PP_CAT3(AURORA_PP_CAT(a, b), c, d)
80 #define AURORA_PP_CAT5(a, b, c, d, e) AURORA_PP_CAT4(AURORA_PP_CAT(a, b), c, d, e)
81 
82 
83 // Convert to string literal
84 #define AURORA_PP_STRINGIZE_IMPL(a) #a
85 
98 #define AURORA_PP_STRINGIZE(a) AURORA_PP_STRINGIZE_IMPL(a)
99 
100 
101 // Object and function macro that evaluate to empty space
102 #define AURORA_PP_NOTHING
103 #define AURORA_PP_VA_CONSUME(...)
104 
105 
106 // Macro that evaluates to its argument without changing it
107 #define AURORA_PP_ID_IMPL(expr) expr
108 #define AURORA_PP_ID(expr) AURORA_PP_ID_IMPL(expr)
109 
110 
111 // Conditional evaluation
112 #define AURORA_PP_IF_0(trueCase, falseCase) falseCase
113 #define AURORA_PP_IF_1(trueCase, falseCase) trueCase
114 #define AURORA_PP_IF_2(trueCase, falseCase) trueCase
115 #define AURORA_PP_IF_3(trueCase, falseCase) trueCase
116 #define AURORA_PP_IF_4(trueCase, falseCase) trueCase
117 #define AURORA_PP_IF_5(trueCase, falseCase) trueCase
118 #define AURORA_PP_IF_IMPL2(condition, trueCase, falseCase) AURORA_PP_IF_ ## condition(trueCase, falseCase)
119 #define AURORA_PP_IF_IMPL(condition, trueCase, falseCase) AURORA_PP_IF_IMPL2(condition, trueCase, falseCase)
120 
132 #define AURORA_PP_IF(condition, trueCase, falseCase) AURORA_PP_IF_IMPL(condition, trueCase, falseCase)
133 
134 
135 // Apply macro repeated times, counting from 0 to n
136 #define AURORA_PP_ENUMERATE_0(macro)
137 #define AURORA_PP_ENUMERATE_1(macro) macro(0)
138 #define AURORA_PP_ENUMERATE_2(macro) AURORA_PP_ENUMERATE_1(macro) macro(1)
139 #define AURORA_PP_ENUMERATE_3(macro) AURORA_PP_ENUMERATE_2(macro) macro(2)
140 #define AURORA_PP_ENUMERATE_4(macro) AURORA_PP_ENUMERATE_3(macro) macro(3)
141 #define AURORA_PP_ENUMERATE_5(macro) AURORA_PP_ENUMERATE_4(macro) macro(4)
142 
155 #define AURORA_PP_ENUMERATE(n, macro) AURORA_PP_CAT(AURORA_PP_ENUMERATE_, n)(macro)
156 
157 
158 // Apply macro repeated times, counting from 0 to n and using a comma separator
159 #define AURORA_PP_ENUMERATE_COMMA_0(macro)
160 #define AURORA_PP_ENUMERATE_COMMA_1(macro) macro(0)
161 #define AURORA_PP_ENUMERATE_COMMA_2(macro) AURORA_PP_ENUMERATE_COMMA_1(macro), macro(1)
162 #define AURORA_PP_ENUMERATE_COMMA_3(macro) AURORA_PP_ENUMERATE_COMMA_2(macro), macro(2)
163 #define AURORA_PP_ENUMERATE_COMMA_4(macro) AURORA_PP_ENUMERATE_COMMA_3(macro), macro(3)
164 #define AURORA_PP_ENUMERATE_COMMA_5(macro) AURORA_PP_ENUMERATE_COMMA_4(macro), macro(4)
165 
179 #define AURORA_PP_ENUMERATE_COMMA(n, macro) AURORA_PP_ENUMERATE_COMMA_ ## n(macro)
180 
181 
182 // Put a comma, if the argument is not zero
183 #define AURORA_PP_COMMA_IF_0()
184 #define AURORA_PP_COMMA_IF_1() ,
185 #define AURORA_PP_COMMA_IF_2() ,
186 #define AURORA_PP_COMMA_IF_3() ,
187 #define AURORA_PP_COMMA_IF_4() ,
188 #define AURORA_PP_COMMA_IF_5() ,
189 
193 #define AURORA_PP_COMMA_IF(n) AURORA_PP_COMMA_IF_ ## n()
194 
195 
196 // Index access to tuple
197 #define AURORA_PP_AT_S1_N0(v0) v0
198 #define AURORA_PP_AT_S2_N0(v0, v1) v0
199 #define AURORA_PP_AT_S2_N1(v0, v1) v1
200 #define AURORA_PP_AT_S3_N0(v0, v1, v2) v0
201 #define AURORA_PP_AT_S3_N1(v0, v1, v2) v1
202 #define AURORA_PP_AT_S3_N2(v0, v1, v2) v2
203 #define AURORA_PP_AT_S4_N0(v0, v1, v2, v3) v0
204 #define AURORA_PP_AT_S4_N1(v0, v1, v2, v3) v1
205 #define AURORA_PP_AT_S4_N2(v0, v1, v2, v3) v2
206 #define AURORA_PP_AT_S4_N3(v0, v1, v2, v3) v3
207 #define AURORA_PP_AT_S5_N0(v0, v1, v2, v3, v4) v0
208 #define AURORA_PP_AT_S5_N1(v0, v1, v2, v3, v4) v1
209 #define AURORA_PP_AT_S5_N2(v0, v1, v2, v3, v4) v2
210 #define AURORA_PP_AT_S5_N3(v0, v1, v2, v3, v4) v3
211 #define AURORA_PP_AT_S5_N4(v0, v1, v2, v3, v4) v4
212 
224 #define AURORA_PP_AT(size, n, tuple) AURORA_PP_CAT4(AURORA_PP_AT_S, size, _N, n) tuple
225 
226 
227 // Iterate over tuple, apply each macro once. macro is MACRO(value, index)
228 #define AURORA_PP_FOREACH_0(macro, size, tuple)
229 #define AURORA_PP_FOREACH_1(macro, size, tuple) macro(AURORA_PP_AT(size, 0, tuple), 0)
230 #define AURORA_PP_FOREACH_2(macro, size, tuple) AURORA_PP_FOREACH_1(macro, size, tuple) macro(AURORA_PP_AT(size, 1, tuple), 1)
231 #define AURORA_PP_FOREACH_3(macro, size, tuple) AURORA_PP_FOREACH_2(macro, size, tuple) macro(AURORA_PP_AT(size, 2, tuple), 2)
232 #define AURORA_PP_FOREACH_4(macro, size, tuple) AURORA_PP_FOREACH_3(macro, size, tuple) macro(AURORA_PP_AT(size, 3, tuple), 3)
233 #define AURORA_PP_FOREACH_5(macro, size, tuple) AURORA_PP_FOREACH_4(macro, size, tuple) macro(AURORA_PP_AT(size, 4, tuple), 4)
234 
235 #define AURORA_PP_FOREACH_SIZED(macro, size, tuple) AURORA_PP_CAT(AURORA_PP_FOREACH_, size) (macro, size, tuple)
236 
253 #define AURORA_PP_FOREACH(macro, tuple) AURORA_PP_FOREACH_SIZED(macro, AURORA_PP_SIZE(tuple), tuple)
254 
255 
256 // Iterate over tuple, passing additional data to each macro. macro is MACRO(value, index, data)
257 #define AURORA_PP_FOREACH_DATA_0(macro, size, tuple, data)
258 #define AURORA_PP_FOREACH_DATA_1(macro, size, tuple, data) macro(AURORA_PP_AT(size, 0, tuple), 0, data)
259 #define AURORA_PP_FOREACH_DATA_2(macro, size, tuple, data) AURORA_PP_FOREACH_DATA_1(macro, size, tuple, data) macro(AURORA_PP_AT(size, 1, tuple), 1, data)
260 #define AURORA_PP_FOREACH_DATA_3(macro, size, tuple, data) AURORA_PP_FOREACH_DATA_2(macro, size, tuple, data) macro(AURORA_PP_AT(size, 2, tuple), 2, data)
261 #define AURORA_PP_FOREACH_DATA_4(macro, size, tuple, data) AURORA_PP_FOREACH_DATA_3(macro, size, tuple, data) macro(AURORA_PP_AT(size, 3, tuple), 3, data)
262 #define AURORA_PP_FOREACH_DATA_5(macro, size, tuple, data) AURORA_PP_FOREACH_DATA_4(macro, size, tuple, data) macro(AURORA_PP_AT(size, 4, tuple), 4, data)
263 
264 #define AURORA_PP_FOREACH_DATA_SIZED(macro, size, tuple, data) AURORA_PP_CAT(AURORA_PP_FOREACH_DATA_, size) (macro, size, tuple, data)
265 
284 #define AURORA_PP_FOREACH_DATA(macro, tuple, data) AURORA_PP_FOREACH_DATA_SIZED(macro, AURORA_PP_SIZE(tuple), tuple, data)
285 
286 
287 // Check whether a variadic argument list starts with (
288 // Warning: From now on, you are entering the deep abyss of the preprocessor. The following macros depend on black magic; their functioning is probabilistic.
289 #define AURORA_PP_AURORA_PP_NO 0 AURORA_PP_VA_CONSUME(
290 #define AURORA_PP_AURORA_PP_YES 1 AURORA_PP_VA_CONSUME(
291 #define AURORA_PP_VA_CAT2(a, b, ...) AURORA_PP_CAT(a, b)
292 #define AURORA_PP_VA_YESNO_TO_10(a, ...) AURORA_PP_VA_CAT2(AURORA_PP_, a) )
293 #define AURORA_PP_NO(...) AURORA_PP_YES
294 
295 #define AURORA_PP_VA_HAS_PARENTHESIS(...) AURORA_PP_ID(AURORA_PP_VA_YESNO_TO_10(AURORA_PP_NO __VA_ARGS__))
296 
297 
298 // VA size inference (argument lists with at least one argument)
299 #define AURORA_PP_VA_POSITIVE_SIZE_IMPL(e0, e1, e2, e3, e4, e5, size, ...) size
300 #define AURORA_PP_VA_POSITIVE_SIZE(...) AURORA_PP_CAT(AURORA_PP_VA_POSITIVE_SIZE_IMPL(__VA_ARGS__, 6, 5, 4, 3, 2, 1,), AURORA_PP_NOTHING)
301 
302 
303 // VA size inference, including empty argument lists
304 #define AURORA_PP_VA_SIZE_1 1
305 #define AURORA_PP_VA_SIZE_2 2
306 #define AURORA_PP_VA_SIZE_3 3
307 #define AURORA_PP_VA_SIZE_4 4
308 #define AURORA_PP_VA_SIZE_5 5
309 #define AURORA_PP_VA_SIZE_6 0
310 
311 #define AURORA_PP_VA_5COMMAS(...) ,,,,,
312 #define AURORA_PP_VA_SIZE_IMPL(...) AURORA_PP_CAT(AURORA_PP_VA_SIZE_, AURORA_PP_VA_POSITIVE_SIZE(__VA_ARGS__))
313 #define AURORA_PP_VA_SIZE(...) AURORA_PP_VA_SIZE_IMPL(AURORA_PP_VA_5COMMAS __VA_ARGS__ ())
314 
315 
316 // Tuple size
317 
328 #define AURORA_PP_POSITIVE_SIZE(tuple) AURORA_PP_VA_POSITIVE_SIZE tuple
329 
330 #define AURORA_PP_SIZE_IMPL2(tuple) AURORA_PP_IF(AURORA_PP_VA_HAS_PARENTHESIS tuple, AURORA_PP_VA_POSITIVE_SIZE, AURORA_PP_VA_SIZE) tuple
331 #define AURORA_PP_SIZE_IMPL1(tuple) AURORA_PP_SIZE_IMPL2(tuple)
332 
333 #ifdef _MSC_VER
334  #define AURORA_PP_SIZE_IMPL(tuple) AURORA_PP_CAT(AURORA_PP_SIZE_IMPL1(tuple),) // works with nested tuples, but not deep inside other macros (especially IF)
335  #define AURORA_PP_FLAT_SIZE(tuple) AURORA_PP_CAT(AURORA_PP_VA_SIZE tuple,) // doesn't work with nested tuples
336 #else
337  #define AURORA_PP_SIZE_IMPL(tuple) AURORA_PP_SIZE_IMPL1(tuple)
338  #define AURORA_PP_FLAT_SIZE(tuple) AURORA_PP_CAT(AURORA_PP_VA_SIZE tuple,)
339 #endif
340 
353 #define AURORA_PP_SIZE(tuple) AURORA_PP_SIZE_IMPL(tuple)
354 
356 
357 #endif // AURORA_PREPROCESSOR_HPP
Configuration header of the library.