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