blob: 5aefb05ecdda636c9a95226bf20b9c938d8972b2 [file] [log] [blame]
Andrew Walbran16937d02019-10-22 13:54:20 +01001//===- VariadicFunction.h - Variadic Functions ------------------*- C++ -*-===//
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01002//
Andrew Walbran16937d02019-10-22 13:54:20 +01003// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
Andrew Scull5e1ddfa2018-08-14 10:06:54 +01006//
7//===----------------------------------------------------------------------===//
8//
9// This file implements compile-time type-safe variadic functions.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef LLVM_ADT_VARIADICFUNCTION_H
14#define LLVM_ADT_VARIADICFUNCTION_H
15
16#include "llvm/ADT/ArrayRef.h"
17
18namespace llvm {
19
20// Define macros to aid in expanding a comma separated series with the index of
21// the series pasted onto the last token.
22#define LLVM_COMMA_JOIN1(x) x ## 0
23#define LLVM_COMMA_JOIN2(x) LLVM_COMMA_JOIN1(x), x ## 1
24#define LLVM_COMMA_JOIN3(x) LLVM_COMMA_JOIN2(x), x ## 2
25#define LLVM_COMMA_JOIN4(x) LLVM_COMMA_JOIN3(x), x ## 3
26#define LLVM_COMMA_JOIN5(x) LLVM_COMMA_JOIN4(x), x ## 4
27#define LLVM_COMMA_JOIN6(x) LLVM_COMMA_JOIN5(x), x ## 5
28#define LLVM_COMMA_JOIN7(x) LLVM_COMMA_JOIN6(x), x ## 6
29#define LLVM_COMMA_JOIN8(x) LLVM_COMMA_JOIN7(x), x ## 7
30#define LLVM_COMMA_JOIN9(x) LLVM_COMMA_JOIN8(x), x ## 8
31#define LLVM_COMMA_JOIN10(x) LLVM_COMMA_JOIN9(x), x ## 9
32#define LLVM_COMMA_JOIN11(x) LLVM_COMMA_JOIN10(x), x ## 10
33#define LLVM_COMMA_JOIN12(x) LLVM_COMMA_JOIN11(x), x ## 11
34#define LLVM_COMMA_JOIN13(x) LLVM_COMMA_JOIN12(x), x ## 12
35#define LLVM_COMMA_JOIN14(x) LLVM_COMMA_JOIN13(x), x ## 13
36#define LLVM_COMMA_JOIN15(x) LLVM_COMMA_JOIN14(x), x ## 14
37#define LLVM_COMMA_JOIN16(x) LLVM_COMMA_JOIN15(x), x ## 15
38#define LLVM_COMMA_JOIN17(x) LLVM_COMMA_JOIN16(x), x ## 16
39#define LLVM_COMMA_JOIN18(x) LLVM_COMMA_JOIN17(x), x ## 17
40#define LLVM_COMMA_JOIN19(x) LLVM_COMMA_JOIN18(x), x ## 18
41#define LLVM_COMMA_JOIN20(x) LLVM_COMMA_JOIN19(x), x ## 19
42#define LLVM_COMMA_JOIN21(x) LLVM_COMMA_JOIN20(x), x ## 20
43#define LLVM_COMMA_JOIN22(x) LLVM_COMMA_JOIN21(x), x ## 21
44#define LLVM_COMMA_JOIN23(x) LLVM_COMMA_JOIN22(x), x ## 22
45#define LLVM_COMMA_JOIN24(x) LLVM_COMMA_JOIN23(x), x ## 23
46#define LLVM_COMMA_JOIN25(x) LLVM_COMMA_JOIN24(x), x ## 24
47#define LLVM_COMMA_JOIN26(x) LLVM_COMMA_JOIN25(x), x ## 25
48#define LLVM_COMMA_JOIN27(x) LLVM_COMMA_JOIN26(x), x ## 26
49#define LLVM_COMMA_JOIN28(x) LLVM_COMMA_JOIN27(x), x ## 27
50#define LLVM_COMMA_JOIN29(x) LLVM_COMMA_JOIN28(x), x ## 28
51#define LLVM_COMMA_JOIN30(x) LLVM_COMMA_JOIN29(x), x ## 29
52#define LLVM_COMMA_JOIN31(x) LLVM_COMMA_JOIN30(x), x ## 30
53#define LLVM_COMMA_JOIN32(x) LLVM_COMMA_JOIN31(x), x ## 31
54
Andrew Scullcdfcccc2018-10-05 20:58:37 +010055/// Class which can simulate a type-safe variadic function.
Andrew Scull5e1ddfa2018-08-14 10:06:54 +010056///
57/// The VariadicFunction class template makes it easy to define
58/// type-safe variadic functions where all arguments have the same
59/// type.
60///
61/// Suppose we need a variadic function like this:
62///
63/// ResultT Foo(const ArgT &A_0, const ArgT &A_1, ..., const ArgT &A_N);
64///
65/// Instead of many overloads of Foo(), we only need to define a helper
66/// function that takes an array of arguments:
67///
68/// ResultT FooImpl(ArrayRef<const ArgT *> Args) {
69/// // 'Args[i]' is a pointer to the i-th argument passed to Foo().
70/// ...
71/// }
72///
73/// and then define Foo() like this:
74///
75/// const VariadicFunction<ResultT, ArgT, FooImpl> Foo;
76///
77/// VariadicFunction takes care of defining the overloads of Foo().
78///
79/// Actually, Foo is a function object (i.e. functor) instead of a plain
80/// function. This object is stateless and its constructor/destructor
81/// does nothing, so it's safe to create global objects and call Foo(...) at
82/// any time.
83///
84/// Sometimes we need a variadic function to have some fixed leading
85/// arguments whose types may be different from that of the optional
86/// arguments. For example:
87///
88/// bool FullMatch(const StringRef &S, const RE &Regex,
89/// const ArgT &A_0, ..., const ArgT &A_N);
90///
91/// VariadicFunctionN is for such cases, where N is the number of fixed
92/// arguments. It is like VariadicFunction, except that it takes N more
93/// template arguments for the types of the fixed arguments:
94///
95/// bool FullMatchImpl(const StringRef &S, const RE &Regex,
96/// ArrayRef<const ArgT *> Args) { ... }
97/// const VariadicFunction2<bool, const StringRef&,
98/// const RE&, ArgT, FullMatchImpl>
99/// FullMatch;
100///
101/// Currently VariadicFunction and friends support up-to 3
102/// fixed leading arguments and up-to 32 optional arguments.
103template <typename ResultT, typename ArgT,
104 ResultT (*Func)(ArrayRef<const ArgT *>)>
105struct VariadicFunction {
106 ResultT operator()() const {
107 return Func(None);
108 }
109
110#define LLVM_DEFINE_OVERLOAD(N) \
111 ResultT operator()(LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \
112 const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \
113 return Func(makeArrayRef(Args)); \
114 }
115 LLVM_DEFINE_OVERLOAD(1)
116 LLVM_DEFINE_OVERLOAD(2)
117 LLVM_DEFINE_OVERLOAD(3)
118 LLVM_DEFINE_OVERLOAD(4)
119 LLVM_DEFINE_OVERLOAD(5)
120 LLVM_DEFINE_OVERLOAD(6)
121 LLVM_DEFINE_OVERLOAD(7)
122 LLVM_DEFINE_OVERLOAD(8)
123 LLVM_DEFINE_OVERLOAD(9)
124 LLVM_DEFINE_OVERLOAD(10)
125 LLVM_DEFINE_OVERLOAD(11)
126 LLVM_DEFINE_OVERLOAD(12)
127 LLVM_DEFINE_OVERLOAD(13)
128 LLVM_DEFINE_OVERLOAD(14)
129 LLVM_DEFINE_OVERLOAD(15)
130 LLVM_DEFINE_OVERLOAD(16)
131 LLVM_DEFINE_OVERLOAD(17)
132 LLVM_DEFINE_OVERLOAD(18)
133 LLVM_DEFINE_OVERLOAD(19)
134 LLVM_DEFINE_OVERLOAD(20)
135 LLVM_DEFINE_OVERLOAD(21)
136 LLVM_DEFINE_OVERLOAD(22)
137 LLVM_DEFINE_OVERLOAD(23)
138 LLVM_DEFINE_OVERLOAD(24)
139 LLVM_DEFINE_OVERLOAD(25)
140 LLVM_DEFINE_OVERLOAD(26)
141 LLVM_DEFINE_OVERLOAD(27)
142 LLVM_DEFINE_OVERLOAD(28)
143 LLVM_DEFINE_OVERLOAD(29)
144 LLVM_DEFINE_OVERLOAD(30)
145 LLVM_DEFINE_OVERLOAD(31)
146 LLVM_DEFINE_OVERLOAD(32)
147#undef LLVM_DEFINE_OVERLOAD
148};
149
150template <typename ResultT, typename Param0T, typename ArgT,
151 ResultT (*Func)(Param0T, ArrayRef<const ArgT *>)>
152struct VariadicFunction1 {
153 ResultT operator()(Param0T P0) const {
154 return Func(P0, None);
155 }
156
157#define LLVM_DEFINE_OVERLOAD(N) \
158 ResultT operator()(Param0T P0, LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \
159 const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \
160 return Func(P0, makeArrayRef(Args)); \
161 }
162 LLVM_DEFINE_OVERLOAD(1)
163 LLVM_DEFINE_OVERLOAD(2)
164 LLVM_DEFINE_OVERLOAD(3)
165 LLVM_DEFINE_OVERLOAD(4)
166 LLVM_DEFINE_OVERLOAD(5)
167 LLVM_DEFINE_OVERLOAD(6)
168 LLVM_DEFINE_OVERLOAD(7)
169 LLVM_DEFINE_OVERLOAD(8)
170 LLVM_DEFINE_OVERLOAD(9)
171 LLVM_DEFINE_OVERLOAD(10)
172 LLVM_DEFINE_OVERLOAD(11)
173 LLVM_DEFINE_OVERLOAD(12)
174 LLVM_DEFINE_OVERLOAD(13)
175 LLVM_DEFINE_OVERLOAD(14)
176 LLVM_DEFINE_OVERLOAD(15)
177 LLVM_DEFINE_OVERLOAD(16)
178 LLVM_DEFINE_OVERLOAD(17)
179 LLVM_DEFINE_OVERLOAD(18)
180 LLVM_DEFINE_OVERLOAD(19)
181 LLVM_DEFINE_OVERLOAD(20)
182 LLVM_DEFINE_OVERLOAD(21)
183 LLVM_DEFINE_OVERLOAD(22)
184 LLVM_DEFINE_OVERLOAD(23)
185 LLVM_DEFINE_OVERLOAD(24)
186 LLVM_DEFINE_OVERLOAD(25)
187 LLVM_DEFINE_OVERLOAD(26)
188 LLVM_DEFINE_OVERLOAD(27)
189 LLVM_DEFINE_OVERLOAD(28)
190 LLVM_DEFINE_OVERLOAD(29)
191 LLVM_DEFINE_OVERLOAD(30)
192 LLVM_DEFINE_OVERLOAD(31)
193 LLVM_DEFINE_OVERLOAD(32)
194#undef LLVM_DEFINE_OVERLOAD
195};
196
197template <typename ResultT, typename Param0T, typename Param1T, typename ArgT,
198 ResultT (*Func)(Param0T, Param1T, ArrayRef<const ArgT *>)>
199struct VariadicFunction2 {
200 ResultT operator()(Param0T P0, Param1T P1) const {
201 return Func(P0, P1, None);
202 }
203
204#define LLVM_DEFINE_OVERLOAD(N) \
205 ResultT operator()(Param0T P0, Param1T P1, \
206 LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \
207 const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \
208 return Func(P0, P1, makeArrayRef(Args)); \
209 }
210 LLVM_DEFINE_OVERLOAD(1)
211 LLVM_DEFINE_OVERLOAD(2)
212 LLVM_DEFINE_OVERLOAD(3)
213 LLVM_DEFINE_OVERLOAD(4)
214 LLVM_DEFINE_OVERLOAD(5)
215 LLVM_DEFINE_OVERLOAD(6)
216 LLVM_DEFINE_OVERLOAD(7)
217 LLVM_DEFINE_OVERLOAD(8)
218 LLVM_DEFINE_OVERLOAD(9)
219 LLVM_DEFINE_OVERLOAD(10)
220 LLVM_DEFINE_OVERLOAD(11)
221 LLVM_DEFINE_OVERLOAD(12)
222 LLVM_DEFINE_OVERLOAD(13)
223 LLVM_DEFINE_OVERLOAD(14)
224 LLVM_DEFINE_OVERLOAD(15)
225 LLVM_DEFINE_OVERLOAD(16)
226 LLVM_DEFINE_OVERLOAD(17)
227 LLVM_DEFINE_OVERLOAD(18)
228 LLVM_DEFINE_OVERLOAD(19)
229 LLVM_DEFINE_OVERLOAD(20)
230 LLVM_DEFINE_OVERLOAD(21)
231 LLVM_DEFINE_OVERLOAD(22)
232 LLVM_DEFINE_OVERLOAD(23)
233 LLVM_DEFINE_OVERLOAD(24)
234 LLVM_DEFINE_OVERLOAD(25)
235 LLVM_DEFINE_OVERLOAD(26)
236 LLVM_DEFINE_OVERLOAD(27)
237 LLVM_DEFINE_OVERLOAD(28)
238 LLVM_DEFINE_OVERLOAD(29)
239 LLVM_DEFINE_OVERLOAD(30)
240 LLVM_DEFINE_OVERLOAD(31)
241 LLVM_DEFINE_OVERLOAD(32)
242#undef LLVM_DEFINE_OVERLOAD
243};
244
245template <typename ResultT, typename Param0T, typename Param1T,
246 typename Param2T, typename ArgT,
247 ResultT (*Func)(Param0T, Param1T, Param2T, ArrayRef<const ArgT *>)>
248struct VariadicFunction3 {
249 ResultT operator()(Param0T P0, Param1T P1, Param2T P2) const {
250 return Func(P0, P1, P2, None);
251 }
252
253#define LLVM_DEFINE_OVERLOAD(N) \
254 ResultT operator()(Param0T P0, Param1T P1, Param2T P2, \
255 LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \
256 const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \
257 return Func(P0, P1, P2, makeArrayRef(Args)); \
258 }
259 LLVM_DEFINE_OVERLOAD(1)
260 LLVM_DEFINE_OVERLOAD(2)
261 LLVM_DEFINE_OVERLOAD(3)
262 LLVM_DEFINE_OVERLOAD(4)
263 LLVM_DEFINE_OVERLOAD(5)
264 LLVM_DEFINE_OVERLOAD(6)
265 LLVM_DEFINE_OVERLOAD(7)
266 LLVM_DEFINE_OVERLOAD(8)
267 LLVM_DEFINE_OVERLOAD(9)
268 LLVM_DEFINE_OVERLOAD(10)
269 LLVM_DEFINE_OVERLOAD(11)
270 LLVM_DEFINE_OVERLOAD(12)
271 LLVM_DEFINE_OVERLOAD(13)
272 LLVM_DEFINE_OVERLOAD(14)
273 LLVM_DEFINE_OVERLOAD(15)
274 LLVM_DEFINE_OVERLOAD(16)
275 LLVM_DEFINE_OVERLOAD(17)
276 LLVM_DEFINE_OVERLOAD(18)
277 LLVM_DEFINE_OVERLOAD(19)
278 LLVM_DEFINE_OVERLOAD(20)
279 LLVM_DEFINE_OVERLOAD(21)
280 LLVM_DEFINE_OVERLOAD(22)
281 LLVM_DEFINE_OVERLOAD(23)
282 LLVM_DEFINE_OVERLOAD(24)
283 LLVM_DEFINE_OVERLOAD(25)
284 LLVM_DEFINE_OVERLOAD(26)
285 LLVM_DEFINE_OVERLOAD(27)
286 LLVM_DEFINE_OVERLOAD(28)
287 LLVM_DEFINE_OVERLOAD(29)
288 LLVM_DEFINE_OVERLOAD(30)
289 LLVM_DEFINE_OVERLOAD(31)
290 LLVM_DEFINE_OVERLOAD(32)
291#undef LLVM_DEFINE_OVERLOAD
292};
293
294// Cleanup the macro namespace.
295#undef LLVM_COMMA_JOIN1
296#undef LLVM_COMMA_JOIN2
297#undef LLVM_COMMA_JOIN3
298#undef LLVM_COMMA_JOIN4
299#undef LLVM_COMMA_JOIN5
300#undef LLVM_COMMA_JOIN6
301#undef LLVM_COMMA_JOIN7
302#undef LLVM_COMMA_JOIN8
303#undef LLVM_COMMA_JOIN9
304#undef LLVM_COMMA_JOIN10
305#undef LLVM_COMMA_JOIN11
306#undef LLVM_COMMA_JOIN12
307#undef LLVM_COMMA_JOIN13
308#undef LLVM_COMMA_JOIN14
309#undef LLVM_COMMA_JOIN15
310#undef LLVM_COMMA_JOIN16
311#undef LLVM_COMMA_JOIN17
312#undef LLVM_COMMA_JOIN18
313#undef LLVM_COMMA_JOIN19
314#undef LLVM_COMMA_JOIN20
315#undef LLVM_COMMA_JOIN21
316#undef LLVM_COMMA_JOIN22
317#undef LLVM_COMMA_JOIN23
318#undef LLVM_COMMA_JOIN24
319#undef LLVM_COMMA_JOIN25
320#undef LLVM_COMMA_JOIN26
321#undef LLVM_COMMA_JOIN27
322#undef LLVM_COMMA_JOIN28
323#undef LLVM_COMMA_JOIN29
324#undef LLVM_COMMA_JOIN30
325#undef LLVM_COMMA_JOIN31
326#undef LLVM_COMMA_JOIN32
327
328} // end namespace llvm
329
330#endif // LLVM_ADT_VARIADICFUNCTION_H