]>
Commit | Line | Data |
---|---|---|
90609253 JMM |
1 | /* |
2 | * BIRD Macro Tricks | |
3 | * | |
4 | * (c) 2018 Jan Maria Matejka <mq@jmq.cz> | |
5 | * | |
6 | * Can be freely distributed and used under the terms of the GNU GPL. | |
7 | * | |
8 | * Contains useful but dirty macro tricks: | |
9 | * MACRO_CONCAT(a, b) -> concatenates a##b | |
10 | * MACRO_BOOL(x) -> convert 0 to 0, anything else to 1 | |
11 | * MACRO_IFELSE(b)(true-branch)(false-branch) | |
12 | * -> b shall be 0 or 1; expands to the appropriate branch | |
13 | * MACRO_ISEMPTY(...) -> 1 for empty argument list, 0 otherwise | |
14 | * MACRO_FOREACH(func, ...) | |
15 | * -> calling FOREACH(func, a, b, c, d) expands to | |
16 | * func(a) func(b) func(c) func(d) | |
17 | * MACRO_RPACK(func, terminator, ...) | |
18 | * -> packs the list into recursive calls: | |
19 | * func(func(func(func(terminator, a), b), c), d) | |
20 | */ | |
21 | ||
22 | #ifndef _BIRD_MACRO_H_ | |
23 | #define _BIRD_MACRO_H_ | |
24 | ||
25 | /* What to do with args */ | |
26 | #define MACRO_DROP(...) | |
27 | #define MACRO_UNPAREN(...) __VA_ARGS__ | |
28 | #define MACRO_SEP(a, b, sep) a sep b | |
29 | ||
30 | /* Aliases for some special chars */ | |
31 | #define MACRO_COMMA , | |
32 | #define MACRO_LPAREN ( | |
33 | #define MACRO_RPAREN ) | |
34 | #define MACRO_LPAREN_() ( | |
35 | #define MACRO_RPAREN_() ) | |
36 | ||
37 | /* Multiple expansion trick */ | |
38 | #define MACRO_EXPAND0(...) __VA_ARGS__ | |
39 | #define MACRO_EXPAND1(...) MACRO_EXPAND0(MACRO_EXPAND0(__VA_ARGS__)) | |
40 | #define MACRO_EXPAND2(...) MACRO_EXPAND1(MACRO_EXPAND1(__VA_ARGS__)) | |
41 | #define MACRO_EXPAND3(...) MACRO_EXPAND2(MACRO_EXPAND2(__VA_ARGS__)) | |
42 | #define MACRO_EXPAND(...) MACRO_EXPAND3(MACRO_EXPAND3(__VA_ARGS__)) | |
43 | ||
44 | /* Deferring expansion in the expansion trick */ | |
45 | #define MACRO_EMPTY() | |
46 | #define MACRO_DEFER(t) t MACRO_EMPTY() | |
47 | #define MACRO_DEFER2(t) t MACRO_EMPTY MACRO_EMPTY()() | |
48 | #define MACRO_DEFER3(t) t MACRO_EMPTY MACRO_EMPTY MACRO_EMPTY()()() | |
49 | ||
50 | /* Token concatenation */ | |
51 | #define MACRO_CONCAT(prefix, ...) prefix##__VA_ARGS__ | |
52 | #define MACRO_CONCAT_AFTER(...) MACRO_CONCAT(__VA_ARGS__) | |
53 | ||
54 | /* Get first or second argument only */ | |
55 | #define MACRO_FIRST(a, ...) a | |
56 | #define MACRO_SECOND(a, b, ...) b | |
57 | #define MACRO_SECOND_OR_ZERO(...) MACRO_SECOND(__VA_ARGS__, 0,) | |
58 | ||
59 | /* Macro Boolean auxiliary macros */ | |
60 | #define MACRO_BOOL_CHECK_0 ~, 1 | |
61 | #define MACRO_BOOL_NEG(x) MACRO_SECOND_OR_ZERO(MACRO_CONCAT(MACRO_BOOL_CHECK_, x)) | |
62 | ||
63 | #define MACRO_BOOL_NOT_0 1 | |
64 | #define MACRO_BOOL_NOT_1 0 | |
65 | ||
66 | /* Macro Boolean negation */ | |
67 | #define MACRO_NOT(x) MACRO_CONCAT(MACRO_BOOL_NOT_, x) | |
68 | ||
69 | /* Convert anything to bool (anything -> 1, 0 -> 0) */ | |
70 | #define MACRO_BOOL(x) MACRO_NOT(MACRO_BOOL_NEG(x)) | |
71 | ||
72 | /* | |
73 | * Macro If/Else condition | |
74 | * Usage: MACRO_IFELSE(condition)(true-branch)(false-branch) | |
75 | * Expands to true-branch if condition is true, otherwise to false-branch. | |
76 | */ | |
77 | #define MACRO_IFELSE(b) MACRO_CONCAT(MACRO_IFELSE_, b) | |
78 | #define MACRO_IFELSE_0(...) MACRO_UNPAREN | |
79 | #define MACRO_IFELSE_1(...) __VA_ARGS__ MACRO_DROP | |
80 | ||
81 | /* Auxiliary macros for MACRO_FOREACH */ | |
82 | #define MACRO_ISLAST(...) MACRO_BOOL_NEG(MACRO_FIRST(MACRO_ISLAST_CHECK __VA_ARGS__)()) | |
83 | #define MACRO_ISLAST_CHECK() 0 | |
84 | ||
85 | #define MACRO_FOREACH_EXPAND(call, a, ...) MACRO_IFELSE(MACRO_ISLAST(__VA_ARGS__))(call(a))(call(a) MACRO_DEFER2(MACRO_FOREACH_PAREN)()(call, __VA_ARGS__)) | |
86 | #define MACRO_FOREACH_PAREN() MACRO_FOREACH_EXPAND | |
87 | ||
88 | #define MACRO_RPACK_EXPAND(call, terminator, a, ...) MACRO_IFELSE(MACRO_ISLAST(__VA_ARGS__))(call(terminator, a))(call(MACRO_DEFER2(MACRO_RPACK_PAREN)()(call, terminator, __VA_ARGS__), a)) | |
89 | #define MACRO_RPACK_PAREN() MACRO_RPACK_EXPAND | |
90 | /* | |
91 | * Call the first argument for each following: | |
92 | * MACRO_FOREACH(func, a, b, c, d) expands to func(a) func(b) func(c) func(d). | |
93 | * It supports also macros as func. | |
94 | */ | |
95 | #define MACRO_FOREACH(call, ...) MACRO_EXPAND(MACRO_FOREACH_EXPAND(call, __VA_ARGS__)) | |
96 | #define MACRO_RPACK(call, terminator, ...) MACRO_EXPAND(MACRO_RPACK_EXPAND(call, terminator, __VA_ARGS__)) | |
97 | ||
98 | #endif |