1234285Sdim//===--- VariadicFunctions.h - Variadic Functions ---------------*- C++ -*-===//
2234285Sdim//
3234285Sdim//                     The LLVM Compiler Infrastructure
4234285Sdim//
5234285Sdim// This file is distributed under the University of Illinois Open Source
6234285Sdim// License. See LICENSE.TXT for details.
7234285Sdim//
8234285Sdim//===----------------------------------------------------------------------===//
9234285Sdim//
10234285Sdim//  This file implements compile-time type-safe variadic functions.
11234285Sdim//
12234285Sdim//===----------------------------------------------------------------------===//
13234285Sdim
14249423Sdim#ifndef LLVM_ADT_VARIADICFUNCTION_H
15249423Sdim#define LLVM_ADT_VARIADICFUNCTION_H
16234285Sdim
17234285Sdim#include "llvm/ADT/ArrayRef.h"
18234285Sdim
19234285Sdimnamespace llvm {
20234285Sdim
21234285Sdim// Define macros to aid in expanding a comma separated series with the index of
22234285Sdim// the series pasted onto the last token.
23234285Sdim#define LLVM_COMMA_JOIN1(x) x ## 0
24234285Sdim#define LLVM_COMMA_JOIN2(x) LLVM_COMMA_JOIN1(x), x ## 1
25234285Sdim#define LLVM_COMMA_JOIN3(x) LLVM_COMMA_JOIN2(x), x ## 2
26234285Sdim#define LLVM_COMMA_JOIN4(x) LLVM_COMMA_JOIN3(x), x ## 3
27234285Sdim#define LLVM_COMMA_JOIN5(x) LLVM_COMMA_JOIN4(x), x ## 4
28234285Sdim#define LLVM_COMMA_JOIN6(x) LLVM_COMMA_JOIN5(x), x ## 5
29234285Sdim#define LLVM_COMMA_JOIN7(x) LLVM_COMMA_JOIN6(x), x ## 6
30234285Sdim#define LLVM_COMMA_JOIN8(x) LLVM_COMMA_JOIN7(x), x ## 7
31234285Sdim#define LLVM_COMMA_JOIN9(x) LLVM_COMMA_JOIN8(x), x ## 8
32234285Sdim#define LLVM_COMMA_JOIN10(x) LLVM_COMMA_JOIN9(x), x ## 9
33234285Sdim#define LLVM_COMMA_JOIN11(x) LLVM_COMMA_JOIN10(x), x ## 10
34234285Sdim#define LLVM_COMMA_JOIN12(x) LLVM_COMMA_JOIN11(x), x ## 11
35234285Sdim#define LLVM_COMMA_JOIN13(x) LLVM_COMMA_JOIN12(x), x ## 12
36234285Sdim#define LLVM_COMMA_JOIN14(x) LLVM_COMMA_JOIN13(x), x ## 13
37234285Sdim#define LLVM_COMMA_JOIN15(x) LLVM_COMMA_JOIN14(x), x ## 14
38234285Sdim#define LLVM_COMMA_JOIN16(x) LLVM_COMMA_JOIN15(x), x ## 15
39234285Sdim#define LLVM_COMMA_JOIN17(x) LLVM_COMMA_JOIN16(x), x ## 16
40234285Sdim#define LLVM_COMMA_JOIN18(x) LLVM_COMMA_JOIN17(x), x ## 17
41234285Sdim#define LLVM_COMMA_JOIN19(x) LLVM_COMMA_JOIN18(x), x ## 18
42234285Sdim#define LLVM_COMMA_JOIN20(x) LLVM_COMMA_JOIN19(x), x ## 19
43234285Sdim#define LLVM_COMMA_JOIN21(x) LLVM_COMMA_JOIN20(x), x ## 20
44234285Sdim#define LLVM_COMMA_JOIN22(x) LLVM_COMMA_JOIN21(x), x ## 21
45234285Sdim#define LLVM_COMMA_JOIN23(x) LLVM_COMMA_JOIN22(x), x ## 22
46234285Sdim#define LLVM_COMMA_JOIN24(x) LLVM_COMMA_JOIN23(x), x ## 23
47234285Sdim#define LLVM_COMMA_JOIN25(x) LLVM_COMMA_JOIN24(x), x ## 24
48234285Sdim#define LLVM_COMMA_JOIN26(x) LLVM_COMMA_JOIN25(x), x ## 25
49234285Sdim#define LLVM_COMMA_JOIN27(x) LLVM_COMMA_JOIN26(x), x ## 26
50234285Sdim#define LLVM_COMMA_JOIN28(x) LLVM_COMMA_JOIN27(x), x ## 27
51234285Sdim#define LLVM_COMMA_JOIN29(x) LLVM_COMMA_JOIN28(x), x ## 28
52234285Sdim#define LLVM_COMMA_JOIN30(x) LLVM_COMMA_JOIN29(x), x ## 29
53234285Sdim#define LLVM_COMMA_JOIN31(x) LLVM_COMMA_JOIN30(x), x ## 30
54234285Sdim#define LLVM_COMMA_JOIN32(x) LLVM_COMMA_JOIN31(x), x ## 31
55234285Sdim
56234285Sdim/// \brief Class which can simulate a type-safe variadic function.
57234285Sdim///
58234285Sdim/// The VariadicFunction class template makes it easy to define
59234285Sdim/// type-safe variadic functions where all arguments have the same
60234285Sdim/// type.
61234285Sdim///
62234285Sdim/// Suppose we need a variadic function like this:
63234285Sdim///
64234285Sdim///   ResultT Foo(const ArgT &A_0, const ArgT &A_1, ..., const ArgT &A_N);
65234285Sdim///
66234285Sdim/// Instead of many overloads of Foo(), we only need to define a helper
67234285Sdim/// function that takes an array of arguments:
68234285Sdim///
69234285Sdim///   ResultT FooImpl(ArrayRef<const ArgT *> Args) {
70234285Sdim///     // 'Args[i]' is a pointer to the i-th argument passed to Foo().
71234285Sdim///     ...
72234285Sdim///   }
73234285Sdim///
74234285Sdim/// and then define Foo() like this:
75234285Sdim///
76234285Sdim///   const VariadicFunction<ResultT, ArgT, FooImpl> Foo;
77234285Sdim///
78234285Sdim/// VariadicFunction takes care of defining the overloads of Foo().
79234285Sdim///
80234285Sdim/// Actually, Foo is a function object (i.e. functor) instead of a plain
81234285Sdim/// function.  This object is stateless and its constructor/destructor
82234285Sdim/// does nothing, so it's safe to create global objects and call Foo(...) at
83234285Sdim/// any time.
84234285Sdim///
85234285Sdim/// Sometimes we need a variadic function to have some fixed leading
86234285Sdim/// arguments whose types may be different from that of the optional
87234285Sdim/// arguments.  For example:
88234285Sdim///
89234285Sdim///   bool FullMatch(const StringRef &S, const RE &Regex,
90234285Sdim///                  const ArgT &A_0, ..., const ArgT &A_N);
91234285Sdim///
92234285Sdim/// VariadicFunctionN is for such cases, where N is the number of fixed
93234285Sdim/// arguments.  It is like VariadicFunction, except that it takes N more
94234285Sdim/// template arguments for the types of the fixed arguments:
95234285Sdim///
96234285Sdim///   bool FullMatchImpl(const StringRef &S, const RE &Regex,
97234285Sdim///                      ArrayRef<const ArgT *> Args) { ... }
98234285Sdim///   const VariadicFunction2<bool, const StringRef&,
99234285Sdim///                           const RE&, ArgT, FullMatchImpl>
100234285Sdim///       FullMatch;
101234285Sdim///
102234285Sdim/// Currently VariadicFunction and friends support up-to 3
103234285Sdim/// fixed leading arguments and up-to 32 optional arguments.
104234285Sdimtemplate <typename ResultT, typename ArgT,
105234285Sdim          ResultT (*Func)(ArrayRef<const ArgT *>)>
106234285Sdimstruct VariadicFunction {
107234285Sdim  ResultT operator()() const {
108234285Sdim    return Func(ArrayRef<const ArgT *>());
109234285Sdim  }
110234285Sdim
111234285Sdim#define LLVM_DEFINE_OVERLOAD(N) \
112234285Sdim  ResultT operator()(LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \
113234285Sdim    const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \
114234285Sdim    return Func(makeArrayRef(Args)); \
115234285Sdim  }
116234285Sdim  LLVM_DEFINE_OVERLOAD(1)
117234285Sdim  LLVM_DEFINE_OVERLOAD(2)
118234285Sdim  LLVM_DEFINE_OVERLOAD(3)
119234285Sdim  LLVM_DEFINE_OVERLOAD(4)
120234285Sdim  LLVM_DEFINE_OVERLOAD(5)
121234285Sdim  LLVM_DEFINE_OVERLOAD(6)
122234285Sdim  LLVM_DEFINE_OVERLOAD(7)
123234285Sdim  LLVM_DEFINE_OVERLOAD(8)
124234285Sdim  LLVM_DEFINE_OVERLOAD(9)
125234285Sdim  LLVM_DEFINE_OVERLOAD(10)
126234285Sdim  LLVM_DEFINE_OVERLOAD(11)
127234285Sdim  LLVM_DEFINE_OVERLOAD(12)
128234285Sdim  LLVM_DEFINE_OVERLOAD(13)
129234285Sdim  LLVM_DEFINE_OVERLOAD(14)
130234285Sdim  LLVM_DEFINE_OVERLOAD(15)
131234285Sdim  LLVM_DEFINE_OVERLOAD(16)
132234285Sdim  LLVM_DEFINE_OVERLOAD(17)
133234285Sdim  LLVM_DEFINE_OVERLOAD(18)
134234285Sdim  LLVM_DEFINE_OVERLOAD(19)
135234285Sdim  LLVM_DEFINE_OVERLOAD(20)
136234285Sdim  LLVM_DEFINE_OVERLOAD(21)
137234285Sdim  LLVM_DEFINE_OVERLOAD(22)
138234285Sdim  LLVM_DEFINE_OVERLOAD(23)
139234285Sdim  LLVM_DEFINE_OVERLOAD(24)
140234285Sdim  LLVM_DEFINE_OVERLOAD(25)
141234285Sdim  LLVM_DEFINE_OVERLOAD(26)
142234285Sdim  LLVM_DEFINE_OVERLOAD(27)
143234285Sdim  LLVM_DEFINE_OVERLOAD(28)
144234285Sdim  LLVM_DEFINE_OVERLOAD(29)
145234285Sdim  LLVM_DEFINE_OVERLOAD(30)
146234285Sdim  LLVM_DEFINE_OVERLOAD(31)
147234285Sdim  LLVM_DEFINE_OVERLOAD(32)
148234285Sdim#undef LLVM_DEFINE_OVERLOAD
149234285Sdim};
150234285Sdim
151234285Sdimtemplate <typename ResultT, typename Param0T, typename ArgT,
152234285Sdim          ResultT (*Func)(Param0T, ArrayRef<const ArgT *>)>
153234285Sdimstruct VariadicFunction1 {
154234285Sdim  ResultT operator()(Param0T P0) const {
155234285Sdim    return Func(P0, ArrayRef<const ArgT *>());
156234285Sdim  }
157234285Sdim
158234285Sdim#define LLVM_DEFINE_OVERLOAD(N) \
159234285Sdim  ResultT operator()(Param0T P0, LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \
160234285Sdim    const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \
161234285Sdim    return Func(P0, makeArrayRef(Args)); \
162234285Sdim  }
163234285Sdim  LLVM_DEFINE_OVERLOAD(1)
164234285Sdim  LLVM_DEFINE_OVERLOAD(2)
165234285Sdim  LLVM_DEFINE_OVERLOAD(3)
166234285Sdim  LLVM_DEFINE_OVERLOAD(4)
167234285Sdim  LLVM_DEFINE_OVERLOAD(5)
168234285Sdim  LLVM_DEFINE_OVERLOAD(6)
169234285Sdim  LLVM_DEFINE_OVERLOAD(7)
170234285Sdim  LLVM_DEFINE_OVERLOAD(8)
171234285Sdim  LLVM_DEFINE_OVERLOAD(9)
172234285Sdim  LLVM_DEFINE_OVERLOAD(10)
173234285Sdim  LLVM_DEFINE_OVERLOAD(11)
174234285Sdim  LLVM_DEFINE_OVERLOAD(12)
175234285Sdim  LLVM_DEFINE_OVERLOAD(13)
176234285Sdim  LLVM_DEFINE_OVERLOAD(14)
177234285Sdim  LLVM_DEFINE_OVERLOAD(15)
178234285Sdim  LLVM_DEFINE_OVERLOAD(16)
179234285Sdim  LLVM_DEFINE_OVERLOAD(17)
180234285Sdim  LLVM_DEFINE_OVERLOAD(18)
181234285Sdim  LLVM_DEFINE_OVERLOAD(19)
182234285Sdim  LLVM_DEFINE_OVERLOAD(20)
183234285Sdim  LLVM_DEFINE_OVERLOAD(21)
184234285Sdim  LLVM_DEFINE_OVERLOAD(22)
185234285Sdim  LLVM_DEFINE_OVERLOAD(23)
186234285Sdim  LLVM_DEFINE_OVERLOAD(24)
187234285Sdim  LLVM_DEFINE_OVERLOAD(25)
188234285Sdim  LLVM_DEFINE_OVERLOAD(26)
189234285Sdim  LLVM_DEFINE_OVERLOAD(27)
190234285Sdim  LLVM_DEFINE_OVERLOAD(28)
191234285Sdim  LLVM_DEFINE_OVERLOAD(29)
192234285Sdim  LLVM_DEFINE_OVERLOAD(30)
193234285Sdim  LLVM_DEFINE_OVERLOAD(31)
194234285Sdim  LLVM_DEFINE_OVERLOAD(32)
195234285Sdim#undef LLVM_DEFINE_OVERLOAD
196234285Sdim};
197234285Sdim
198234285Sdimtemplate <typename ResultT, typename Param0T, typename Param1T, typename ArgT,
199234285Sdim          ResultT (*Func)(Param0T, Param1T, ArrayRef<const ArgT *>)>
200234285Sdimstruct VariadicFunction2 {
201234285Sdim  ResultT operator()(Param0T P0, Param1T P1) const {
202234285Sdim    return Func(P0, P1, ArrayRef<const ArgT *>());
203234285Sdim  }
204234285Sdim
205234285Sdim#define LLVM_DEFINE_OVERLOAD(N) \
206234285Sdim  ResultT operator()(Param0T P0, Param1T P1, \
207234285Sdim                     LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \
208234285Sdim    const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \
209239462Sdim    return Func(P0, P1, makeArrayRef(Args)); \
210234285Sdim  }
211234285Sdim  LLVM_DEFINE_OVERLOAD(1)
212234285Sdim  LLVM_DEFINE_OVERLOAD(2)
213234285Sdim  LLVM_DEFINE_OVERLOAD(3)
214234285Sdim  LLVM_DEFINE_OVERLOAD(4)
215234285Sdim  LLVM_DEFINE_OVERLOAD(5)
216234285Sdim  LLVM_DEFINE_OVERLOAD(6)
217234285Sdim  LLVM_DEFINE_OVERLOAD(7)
218234285Sdim  LLVM_DEFINE_OVERLOAD(8)
219234285Sdim  LLVM_DEFINE_OVERLOAD(9)
220234285Sdim  LLVM_DEFINE_OVERLOAD(10)
221234285Sdim  LLVM_DEFINE_OVERLOAD(11)
222234285Sdim  LLVM_DEFINE_OVERLOAD(12)
223234285Sdim  LLVM_DEFINE_OVERLOAD(13)
224234285Sdim  LLVM_DEFINE_OVERLOAD(14)
225234285Sdim  LLVM_DEFINE_OVERLOAD(15)
226234285Sdim  LLVM_DEFINE_OVERLOAD(16)
227234285Sdim  LLVM_DEFINE_OVERLOAD(17)
228234285Sdim  LLVM_DEFINE_OVERLOAD(18)
229234285Sdim  LLVM_DEFINE_OVERLOAD(19)
230234285Sdim  LLVM_DEFINE_OVERLOAD(20)
231234285Sdim  LLVM_DEFINE_OVERLOAD(21)
232234285Sdim  LLVM_DEFINE_OVERLOAD(22)
233234285Sdim  LLVM_DEFINE_OVERLOAD(23)
234234285Sdim  LLVM_DEFINE_OVERLOAD(24)
235234285Sdim  LLVM_DEFINE_OVERLOAD(25)
236234285Sdim  LLVM_DEFINE_OVERLOAD(26)
237234285Sdim  LLVM_DEFINE_OVERLOAD(27)
238234285Sdim  LLVM_DEFINE_OVERLOAD(28)
239234285Sdim  LLVM_DEFINE_OVERLOAD(29)
240234285Sdim  LLVM_DEFINE_OVERLOAD(30)
241234285Sdim  LLVM_DEFINE_OVERLOAD(31)
242234285Sdim  LLVM_DEFINE_OVERLOAD(32)
243234285Sdim#undef LLVM_DEFINE_OVERLOAD
244234285Sdim};
245234285Sdim
246234285Sdimtemplate <typename ResultT, typename Param0T, typename Param1T,
247234285Sdim          typename Param2T, typename ArgT,
248234285Sdim          ResultT (*Func)(Param0T, Param1T, Param2T, ArrayRef<const ArgT *>)>
249234285Sdimstruct VariadicFunction3 {
250234285Sdim  ResultT operator()(Param0T P0, Param1T P1, Param2T P2) const {
251234285Sdim    return Func(P0, P1, P2, ArrayRef<const ArgT *>());
252234285Sdim  }
253234285Sdim
254234285Sdim#define LLVM_DEFINE_OVERLOAD(N) \
255234285Sdim  ResultT operator()(Param0T P0, Param1T P1, Param2T P2, \
256234285Sdim                     LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \
257234285Sdim    const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \
258234285Sdim    return Func(P0, P1, P2, makeArrayRef(Args)); \
259234285Sdim  }
260234285Sdim  LLVM_DEFINE_OVERLOAD(1)
261234285Sdim  LLVM_DEFINE_OVERLOAD(2)
262234285Sdim  LLVM_DEFINE_OVERLOAD(3)
263234285Sdim  LLVM_DEFINE_OVERLOAD(4)
264234285Sdim  LLVM_DEFINE_OVERLOAD(5)
265234285Sdim  LLVM_DEFINE_OVERLOAD(6)
266234285Sdim  LLVM_DEFINE_OVERLOAD(7)
267234285Sdim  LLVM_DEFINE_OVERLOAD(8)
268234285Sdim  LLVM_DEFINE_OVERLOAD(9)
269234285Sdim  LLVM_DEFINE_OVERLOAD(10)
270234285Sdim  LLVM_DEFINE_OVERLOAD(11)
271234285Sdim  LLVM_DEFINE_OVERLOAD(12)
272234285Sdim  LLVM_DEFINE_OVERLOAD(13)
273234285Sdim  LLVM_DEFINE_OVERLOAD(14)
274234285Sdim  LLVM_DEFINE_OVERLOAD(15)
275234285Sdim  LLVM_DEFINE_OVERLOAD(16)
276234285Sdim  LLVM_DEFINE_OVERLOAD(17)
277234285Sdim  LLVM_DEFINE_OVERLOAD(18)
278234285Sdim  LLVM_DEFINE_OVERLOAD(19)
279234285Sdim  LLVM_DEFINE_OVERLOAD(20)
280234285Sdim  LLVM_DEFINE_OVERLOAD(21)
281234285Sdim  LLVM_DEFINE_OVERLOAD(22)
282234285Sdim  LLVM_DEFINE_OVERLOAD(23)
283234285Sdim  LLVM_DEFINE_OVERLOAD(24)
284234285Sdim  LLVM_DEFINE_OVERLOAD(25)
285234285Sdim  LLVM_DEFINE_OVERLOAD(26)
286234285Sdim  LLVM_DEFINE_OVERLOAD(27)
287234285Sdim  LLVM_DEFINE_OVERLOAD(28)
288234285Sdim  LLVM_DEFINE_OVERLOAD(29)
289234285Sdim  LLVM_DEFINE_OVERLOAD(30)
290234285Sdim  LLVM_DEFINE_OVERLOAD(31)
291234285Sdim  LLVM_DEFINE_OVERLOAD(32)
292234285Sdim#undef LLVM_DEFINE_OVERLOAD
293234285Sdim};
294234285Sdim
295234285Sdim// Cleanup the macro namespace.
296234285Sdim#undef LLVM_COMMA_JOIN1
297234285Sdim#undef LLVM_COMMA_JOIN2
298234285Sdim#undef LLVM_COMMA_JOIN3
299234285Sdim#undef LLVM_COMMA_JOIN4
300234285Sdim#undef LLVM_COMMA_JOIN5
301234285Sdim#undef LLVM_COMMA_JOIN6
302234285Sdim#undef LLVM_COMMA_JOIN7
303234285Sdim#undef LLVM_COMMA_JOIN8
304234285Sdim#undef LLVM_COMMA_JOIN9
305234285Sdim#undef LLVM_COMMA_JOIN10
306234285Sdim#undef LLVM_COMMA_JOIN11
307234285Sdim#undef LLVM_COMMA_JOIN12
308234285Sdim#undef LLVM_COMMA_JOIN13
309234285Sdim#undef LLVM_COMMA_JOIN14
310234285Sdim#undef LLVM_COMMA_JOIN15
311234285Sdim#undef LLVM_COMMA_JOIN16
312234285Sdim#undef LLVM_COMMA_JOIN17
313234285Sdim#undef LLVM_COMMA_JOIN18
314234285Sdim#undef LLVM_COMMA_JOIN19
315234285Sdim#undef LLVM_COMMA_JOIN20
316234285Sdim#undef LLVM_COMMA_JOIN21
317234285Sdim#undef LLVM_COMMA_JOIN22
318234285Sdim#undef LLVM_COMMA_JOIN23
319234285Sdim#undef LLVM_COMMA_JOIN24
320234285Sdim#undef LLVM_COMMA_JOIN25
321234285Sdim#undef LLVM_COMMA_JOIN26
322234285Sdim#undef LLVM_COMMA_JOIN27
323234285Sdim#undef LLVM_COMMA_JOIN28
324234285Sdim#undef LLVM_COMMA_JOIN29
325234285Sdim#undef LLVM_COMMA_JOIN30
326234285Sdim#undef LLVM_COMMA_JOIN31
327234285Sdim#undef LLVM_COMMA_JOIN32
328234285Sdim
329234285Sdim} // end namespace llvm
330234285Sdim
331249423Sdim#endif  // LLVM_ADT_VARIADICFUNCTION_H
332