1 | /* |
2 | * Copyright 2012-present Facebook, Inc. |
3 | * |
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * You may obtain a copy of the License at |
7 | * |
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | * |
10 | * Unless required by applicable law or agreed to in writing, software |
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | * See the License for the specific language governing permissions and |
14 | * limitations under the License. |
15 | */ |
16 | |
17 | // @author: Andrei Alexandrescu |
18 | |
19 | #pragma once |
20 | |
21 | #include <folly/CPortability.h> |
22 | |
23 | /** |
24 | * Necessarily evil preprocessor-related amenities. |
25 | */ |
26 | |
27 | // MSVC's preprocessor is a pain, so we have to |
28 | // forcefully expand the VA args in some places. |
29 | #define FB_VA_GLUE(a, b) a b |
30 | |
31 | /** |
32 | * FB_ONE_OR_NONE(hello, world) expands to hello and |
33 | * FB_ONE_OR_NONE(hello) expands to nothing. This macro is used to |
34 | * insert or eliminate text based on the presence of another argument. |
35 | */ |
36 | #define FB_ONE_OR_NONE(a, ...) FB_VA_GLUE(FB_THIRD, (a, ##__VA_ARGS__, a)) |
37 | #define FB_THIRD(a, b, ...) __VA_ARGS__ |
38 | |
39 | /** |
40 | * Helper macro that extracts the first argument out of a list of any |
41 | * number of arguments. |
42 | */ |
43 | #define FB_ARG_1(a, ...) a |
44 | |
45 | /** |
46 | * Helper macro that extracts the second argument out of a list of any |
47 | * number of arguments. If only one argument is given, it returns |
48 | * that. |
49 | */ |
50 | #ifdef _MSC_VER |
51 | // GCC refuses to expand this correctly if this macro itself was |
52 | // called with FB_VA_GLUE :( |
53 | #define FB_ARG_2_OR_1(...) \ |
54 | FB_VA_GLUE(FB_ARG_2_OR_1_IMPL, (__VA_ARGS__, __VA_ARGS__)) |
55 | #else |
56 | #define FB_ARG_2_OR_1(...) FB_ARG_2_OR_1_IMPL(__VA_ARGS__, __VA_ARGS__) |
57 | #endif |
58 | // Support macro for the above |
59 | #define FB_ARG_2_OR_1_IMPL(a, b, ...) b |
60 | |
61 | /** |
62 | * Helper macro that provides a way to pass argument with commas in it to |
63 | * some other macro whose syntax doesn't allow using extra parentheses. |
64 | * Example: |
65 | * |
66 | * #define MACRO(type, name) type name |
67 | * MACRO(FB_SINGLE_ARG(std::pair<size_t, size_t>), x); |
68 | * |
69 | */ |
70 | #define FB_SINGLE_ARG(...) __VA_ARGS__ |
71 | |
72 | #define FOLLY_PP_DETAIL_APPEND_VA_ARG(...) , ##__VA_ARGS__ |
73 | |
74 | /** |
75 | * Helper macro that just ignores its parameters. |
76 | */ |
77 | #define FOLLY_IGNORE(...) |
78 | |
79 | /** |
80 | * Helper macro that just ignores its parameters and inserts a semicolon. |
81 | */ |
82 | #define FOLLY_SEMICOLON(...) ; |
83 | |
84 | /** |
85 | * FB_ANONYMOUS_VARIABLE(str) introduces an identifier starting with |
86 | * str and ending with a number that varies with the line. |
87 | */ |
88 | #ifndef FB_ANONYMOUS_VARIABLE |
89 | #define FB_CONCATENATE_IMPL(s1, s2) s1##s2 |
90 | #define FB_CONCATENATE(s1, s2) FB_CONCATENATE_IMPL(s1, s2) |
91 | #ifdef __COUNTER__ |
92 | // Modular builds build each module with its own preprocessor state, meaning |
93 | // `__COUNTER__` no longer provides a unique number across a TU. Instead of |
94 | // calling back to just `__LINE__`, use a mix of `__COUNTER__` and `__LINE__` |
95 | // to try provide as much uniqueness as possible. |
96 | #if FOLLY_HAS_FEATURE(modules) |
97 | #define FB_ANONYMOUS_VARIABLE(str) \ |
98 | FB_CONCATENATE(FB_CONCATENATE(FB_CONCATENATE(str, __COUNTER__), _), __LINE__) |
99 | #else |
100 | #define FB_ANONYMOUS_VARIABLE(str) FB_CONCATENATE(str, __COUNTER__) |
101 | #endif |
102 | #else |
103 | #define FB_ANONYMOUS_VARIABLE(str) FB_CONCATENATE(str, __LINE__) |
104 | #endif |
105 | #endif |
106 | |
107 | /** |
108 | * Use FB_STRINGIZE(x) when you'd want to do what #x does inside |
109 | * another macro expansion. |
110 | */ |
111 | #define FB_STRINGIZE(x) #x |
112 | |
113 | #define FOLLY_PP_DETAIL_NARGS_1(dummy, _7, _6, _5, _4, _3, _2, _1, _0, ...) _0 |
114 | #define FOLLY_PP_DETAIL_NARGS(...) \ |
115 | FOLLY_PP_DETAIL_NARGS_1(dummy, ##__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0) |
116 | |
117 | #define FOLLY_PP_DETAIL_FOR_EACH_REC_0(fn, ...) |
118 | #define FOLLY_PP_DETAIL_FOR_EACH_REC_1(fn, a, ...) \ |
119 | fn(a) FOLLY_PP_DETAIL_FOR_EACH_REC_0(fn, __VA_ARGS__) |
120 | #define FOLLY_PP_DETAIL_FOR_EACH_REC_2(fn, a, ...) \ |
121 | fn(a) FOLLY_PP_DETAIL_FOR_EACH_REC_1(fn, __VA_ARGS__) |
122 | #define FOLLY_PP_DETAIL_FOR_EACH_REC_3(fn, a, ...) \ |
123 | fn(a) FOLLY_PP_DETAIL_FOR_EACH_REC_2(fn, __VA_ARGS__) |
124 | #define FOLLY_PP_DETAIL_FOR_EACH_REC_4(fn, a, ...) \ |
125 | fn(a) FOLLY_PP_DETAIL_FOR_EACH_REC_3(fn, __VA_ARGS__) |
126 | #define FOLLY_PP_DETAIL_FOR_EACH_REC_5(fn, a, ...) \ |
127 | fn(a) FOLLY_PP_DETAIL_FOR_EACH_REC_4(fn, __VA_ARGS__) |
128 | #define FOLLY_PP_DETAIL_FOR_EACH_REC_6(fn, a, ...) \ |
129 | fn(a) FOLLY_PP_DETAIL_FOR_EACH_REC_5(fn, __VA_ARGS__) |
130 | #define FOLLY_PP_DETAIL_FOR_EACH_REC_7(fn, a, ...) \ |
131 | fn(a) FOLLY_PP_DETAIL_FOR_EACH_REC_6(fn, __VA_ARGS__) |
132 | |
133 | #define FOLLY_PP_DETAIL_FOR_EACH_2(fn, n, ...) \ |
134 | FOLLY_PP_DETAIL_FOR_EACH_REC_##n(fn, __VA_ARGS__) |
135 | #define FOLLY_PP_DETAIL_FOR_EACH_1(fn, n, ...) \ |
136 | FOLLY_PP_DETAIL_FOR_EACH_2(fn, n, __VA_ARGS__) |
137 | |
138 | /** |
139 | * FOLLY_PP_FOR_EACH |
140 | * |
141 | * Used to invoke a preprocessor macro, the name of which is passed as the |
142 | * first argument, once for each subsequent variadic argument. |
143 | * |
144 | * At present, supports [0, 8) arguments. |
145 | * |
146 | * This input: |
147 | * |
148 | * #define DOIT(a) go_do_it(a); |
149 | * FOLLY_PP_FOR_EACH(DOIT, 3, 5, 7) |
150 | * #undef DOIT |
151 | * |
152 | * Expands to this output (with whitespace adjusted for clarity): |
153 | * |
154 | * go_do_it(3); |
155 | * go_do_it(5); |
156 | * go_do_it(7); |
157 | */ |
158 | #define FOLLY_PP_FOR_EACH(fn, ...) \ |
159 | FOLLY_PP_DETAIL_FOR_EACH_1( \ |
160 | fn, FOLLY_PP_DETAIL_NARGS(__VA_ARGS__), __VA_ARGS__) |
161 | |