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