| //===- VariadicFunction.h - Variadic Functions ------------------*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This file implements compile-time type-safe variadic functions. |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_ADT_VARIADICFUNCTION_H |
| #define LLVM_ADT_VARIADICFUNCTION_H |
| |
| #include "llvm/ADT/ArrayRef.h" |
| |
| namespace llvm { |
| |
| // Define macros to aid in expanding a comma separated series with the index of |
| // the series pasted onto the last token. |
| #define LLVM_COMMA_JOIN1(x) x ## 0 |
| #define LLVM_COMMA_JOIN2(x) LLVM_COMMA_JOIN1(x), x ## 1 |
| #define LLVM_COMMA_JOIN3(x) LLVM_COMMA_JOIN2(x), x ## 2 |
| #define LLVM_COMMA_JOIN4(x) LLVM_COMMA_JOIN3(x), x ## 3 |
| #define LLVM_COMMA_JOIN5(x) LLVM_COMMA_JOIN4(x), x ## 4 |
| #define LLVM_COMMA_JOIN6(x) LLVM_COMMA_JOIN5(x), x ## 5 |
| #define LLVM_COMMA_JOIN7(x) LLVM_COMMA_JOIN6(x), x ## 6 |
| #define LLVM_COMMA_JOIN8(x) LLVM_COMMA_JOIN7(x), x ## 7 |
| #define LLVM_COMMA_JOIN9(x) LLVM_COMMA_JOIN8(x), x ## 8 |
| #define LLVM_COMMA_JOIN10(x) LLVM_COMMA_JOIN9(x), x ## 9 |
| #define LLVM_COMMA_JOIN11(x) LLVM_COMMA_JOIN10(x), x ## 10 |
| #define LLVM_COMMA_JOIN12(x) LLVM_COMMA_JOIN11(x), x ## 11 |
| #define LLVM_COMMA_JOIN13(x) LLVM_COMMA_JOIN12(x), x ## 12 |
| #define LLVM_COMMA_JOIN14(x) LLVM_COMMA_JOIN13(x), x ## 13 |
| #define LLVM_COMMA_JOIN15(x) LLVM_COMMA_JOIN14(x), x ## 14 |
| #define LLVM_COMMA_JOIN16(x) LLVM_COMMA_JOIN15(x), x ## 15 |
| #define LLVM_COMMA_JOIN17(x) LLVM_COMMA_JOIN16(x), x ## 16 |
| #define LLVM_COMMA_JOIN18(x) LLVM_COMMA_JOIN17(x), x ## 17 |
| #define LLVM_COMMA_JOIN19(x) LLVM_COMMA_JOIN18(x), x ## 18 |
| #define LLVM_COMMA_JOIN20(x) LLVM_COMMA_JOIN19(x), x ## 19 |
| #define LLVM_COMMA_JOIN21(x) LLVM_COMMA_JOIN20(x), x ## 20 |
| #define LLVM_COMMA_JOIN22(x) LLVM_COMMA_JOIN21(x), x ## 21 |
| #define LLVM_COMMA_JOIN23(x) LLVM_COMMA_JOIN22(x), x ## 22 |
| #define LLVM_COMMA_JOIN24(x) LLVM_COMMA_JOIN23(x), x ## 23 |
| #define LLVM_COMMA_JOIN25(x) LLVM_COMMA_JOIN24(x), x ## 24 |
| #define LLVM_COMMA_JOIN26(x) LLVM_COMMA_JOIN25(x), x ## 25 |
| #define LLVM_COMMA_JOIN27(x) LLVM_COMMA_JOIN26(x), x ## 26 |
| #define LLVM_COMMA_JOIN28(x) LLVM_COMMA_JOIN27(x), x ## 27 |
| #define LLVM_COMMA_JOIN29(x) LLVM_COMMA_JOIN28(x), x ## 28 |
| #define LLVM_COMMA_JOIN30(x) LLVM_COMMA_JOIN29(x), x ## 29 |
| #define LLVM_COMMA_JOIN31(x) LLVM_COMMA_JOIN30(x), x ## 30 |
| #define LLVM_COMMA_JOIN32(x) LLVM_COMMA_JOIN31(x), x ## 31 |
| |
| /// Class which can simulate a type-safe variadic function. |
| /// |
| /// The VariadicFunction class template makes it easy to define |
| /// type-safe variadic functions where all arguments have the same |
| /// type. |
| /// |
| /// Suppose we need a variadic function like this: |
| /// |
| /// ResultT Foo(const ArgT &A_0, const ArgT &A_1, ..., const ArgT &A_N); |
| /// |
| /// Instead of many overloads of Foo(), we only need to define a helper |
| /// function that takes an array of arguments: |
| /// |
| /// ResultT FooImpl(ArrayRef<const ArgT *> Args) { |
| /// // 'Args[i]' is a pointer to the i-th argument passed to Foo(). |
| /// ... |
| /// } |
| /// |
| /// and then define Foo() like this: |
| /// |
| /// const VariadicFunction<ResultT, ArgT, FooImpl> Foo; |
| /// |
| /// VariadicFunction takes care of defining the overloads of Foo(). |
| /// |
| /// Actually, Foo is a function object (i.e. functor) instead of a plain |
| /// function. This object is stateless and its constructor/destructor |
| /// does nothing, so it's safe to create global objects and call Foo(...) at |
| /// any time. |
| /// |
| /// Sometimes we need a variadic function to have some fixed leading |
| /// arguments whose types may be different from that of the optional |
| /// arguments. For example: |
| /// |
| /// bool FullMatch(const StringRef &S, const RE &Regex, |
| /// const ArgT &A_0, ..., const ArgT &A_N); |
| /// |
| /// VariadicFunctionN is for such cases, where N is the number of fixed |
| /// arguments. It is like VariadicFunction, except that it takes N more |
| /// template arguments for the types of the fixed arguments: |
| /// |
| /// bool FullMatchImpl(const StringRef &S, const RE &Regex, |
| /// ArrayRef<const ArgT *> Args) { ... } |
| /// const VariadicFunction2<bool, const StringRef&, |
| /// const RE&, ArgT, FullMatchImpl> |
| /// FullMatch; |
| /// |
| /// Currently VariadicFunction and friends support up-to 3 |
| /// fixed leading arguments and up-to 32 optional arguments. |
| template <typename ResultT, typename ArgT, |
| ResultT (*Func)(ArrayRef<const ArgT *>)> |
| struct VariadicFunction { |
| ResultT operator()() const { |
| return Func(None); |
| } |
| |
| #define LLVM_DEFINE_OVERLOAD(N) \ |
| ResultT operator()(LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \ |
| const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \ |
| return Func(makeArrayRef(Args)); \ |
| } |
| LLVM_DEFINE_OVERLOAD(1) |
| LLVM_DEFINE_OVERLOAD(2) |
| LLVM_DEFINE_OVERLOAD(3) |
| LLVM_DEFINE_OVERLOAD(4) |
| LLVM_DEFINE_OVERLOAD(5) |
| LLVM_DEFINE_OVERLOAD(6) |
| LLVM_DEFINE_OVERLOAD(7) |
| LLVM_DEFINE_OVERLOAD(8) |
| LLVM_DEFINE_OVERLOAD(9) |
| LLVM_DEFINE_OVERLOAD(10) |
| LLVM_DEFINE_OVERLOAD(11) |
| LLVM_DEFINE_OVERLOAD(12) |
| LLVM_DEFINE_OVERLOAD(13) |
| LLVM_DEFINE_OVERLOAD(14) |
| LLVM_DEFINE_OVERLOAD(15) |
| LLVM_DEFINE_OVERLOAD(16) |
| LLVM_DEFINE_OVERLOAD(17) |
| LLVM_DEFINE_OVERLOAD(18) |
| LLVM_DEFINE_OVERLOAD(19) |
| LLVM_DEFINE_OVERLOAD(20) |
| LLVM_DEFINE_OVERLOAD(21) |
| LLVM_DEFINE_OVERLOAD(22) |
| LLVM_DEFINE_OVERLOAD(23) |
| LLVM_DEFINE_OVERLOAD(24) |
| LLVM_DEFINE_OVERLOAD(25) |
| LLVM_DEFINE_OVERLOAD(26) |
| LLVM_DEFINE_OVERLOAD(27) |
| LLVM_DEFINE_OVERLOAD(28) |
| LLVM_DEFINE_OVERLOAD(29) |
| LLVM_DEFINE_OVERLOAD(30) |
| LLVM_DEFINE_OVERLOAD(31) |
| LLVM_DEFINE_OVERLOAD(32) |
| #undef LLVM_DEFINE_OVERLOAD |
| }; |
| |
| template <typename ResultT, typename Param0T, typename ArgT, |
| ResultT (*Func)(Param0T, ArrayRef<const ArgT *>)> |
| struct VariadicFunction1 { |
| ResultT operator()(Param0T P0) const { |
| return Func(P0, None); |
| } |
| |
| #define LLVM_DEFINE_OVERLOAD(N) \ |
| ResultT operator()(Param0T P0, LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \ |
| const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \ |
| return Func(P0, makeArrayRef(Args)); \ |
| } |
| LLVM_DEFINE_OVERLOAD(1) |
| LLVM_DEFINE_OVERLOAD(2) |
| LLVM_DEFINE_OVERLOAD(3) |
| LLVM_DEFINE_OVERLOAD(4) |
| LLVM_DEFINE_OVERLOAD(5) |
| LLVM_DEFINE_OVERLOAD(6) |
| LLVM_DEFINE_OVERLOAD(7) |
| LLVM_DEFINE_OVERLOAD(8) |
| LLVM_DEFINE_OVERLOAD(9) |
| LLVM_DEFINE_OVERLOAD(10) |
| LLVM_DEFINE_OVERLOAD(11) |
| LLVM_DEFINE_OVERLOAD(12) |
| LLVM_DEFINE_OVERLOAD(13) |
| LLVM_DEFINE_OVERLOAD(14) |
| LLVM_DEFINE_OVERLOAD(15) |
| LLVM_DEFINE_OVERLOAD(16) |
| LLVM_DEFINE_OVERLOAD(17) |
| LLVM_DEFINE_OVERLOAD(18) |
| LLVM_DEFINE_OVERLOAD(19) |
| LLVM_DEFINE_OVERLOAD(20) |
| LLVM_DEFINE_OVERLOAD(21) |
| LLVM_DEFINE_OVERLOAD(22) |
| LLVM_DEFINE_OVERLOAD(23) |
| LLVM_DEFINE_OVERLOAD(24) |
| LLVM_DEFINE_OVERLOAD(25) |
| LLVM_DEFINE_OVERLOAD(26) |
| LLVM_DEFINE_OVERLOAD(27) |
| LLVM_DEFINE_OVERLOAD(28) |
| LLVM_DEFINE_OVERLOAD(29) |
| LLVM_DEFINE_OVERLOAD(30) |
| LLVM_DEFINE_OVERLOAD(31) |
| LLVM_DEFINE_OVERLOAD(32) |
| #undef LLVM_DEFINE_OVERLOAD |
| }; |
| |
| template <typename ResultT, typename Param0T, typename Param1T, typename ArgT, |
| ResultT (*Func)(Param0T, Param1T, ArrayRef<const ArgT *>)> |
| struct VariadicFunction2 { |
| ResultT operator()(Param0T P0, Param1T P1) const { |
| return Func(P0, P1, None); |
| } |
| |
| #define LLVM_DEFINE_OVERLOAD(N) \ |
| ResultT operator()(Param0T P0, Param1T P1, \ |
| LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \ |
| const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \ |
| return Func(P0, P1, makeArrayRef(Args)); \ |
| } |
| LLVM_DEFINE_OVERLOAD(1) |
| LLVM_DEFINE_OVERLOAD(2) |
| LLVM_DEFINE_OVERLOAD(3) |
| LLVM_DEFINE_OVERLOAD(4) |
| LLVM_DEFINE_OVERLOAD(5) |
| LLVM_DEFINE_OVERLOAD(6) |
| LLVM_DEFINE_OVERLOAD(7) |
| LLVM_DEFINE_OVERLOAD(8) |
| LLVM_DEFINE_OVERLOAD(9) |
| LLVM_DEFINE_OVERLOAD(10) |
| LLVM_DEFINE_OVERLOAD(11) |
| LLVM_DEFINE_OVERLOAD(12) |
| LLVM_DEFINE_OVERLOAD(13) |
| LLVM_DEFINE_OVERLOAD(14) |
| LLVM_DEFINE_OVERLOAD(15) |
| LLVM_DEFINE_OVERLOAD(16) |
| LLVM_DEFINE_OVERLOAD(17) |
| LLVM_DEFINE_OVERLOAD(18) |
| LLVM_DEFINE_OVERLOAD(19) |
| LLVM_DEFINE_OVERLOAD(20) |
| LLVM_DEFINE_OVERLOAD(21) |
| LLVM_DEFINE_OVERLOAD(22) |
| LLVM_DEFINE_OVERLOAD(23) |
| LLVM_DEFINE_OVERLOAD(24) |
| LLVM_DEFINE_OVERLOAD(25) |
| LLVM_DEFINE_OVERLOAD(26) |
| LLVM_DEFINE_OVERLOAD(27) |
| LLVM_DEFINE_OVERLOAD(28) |
| LLVM_DEFINE_OVERLOAD(29) |
| LLVM_DEFINE_OVERLOAD(30) |
| LLVM_DEFINE_OVERLOAD(31) |
| LLVM_DEFINE_OVERLOAD(32) |
| #undef LLVM_DEFINE_OVERLOAD |
| }; |
| |
| template <typename ResultT, typename Param0T, typename Param1T, |
| typename Param2T, typename ArgT, |
| ResultT (*Func)(Param0T, Param1T, Param2T, ArrayRef<const ArgT *>)> |
| struct VariadicFunction3 { |
| ResultT operator()(Param0T P0, Param1T P1, Param2T P2) const { |
| return Func(P0, P1, P2, None); |
| } |
| |
| #define LLVM_DEFINE_OVERLOAD(N) \ |
| ResultT operator()(Param0T P0, Param1T P1, Param2T P2, \ |
| LLVM_COMMA_JOIN ## N(const ArgT &A)) const { \ |
| const ArgT *const Args[] = { LLVM_COMMA_JOIN ## N(&A) }; \ |
| return Func(P0, P1, P2, makeArrayRef(Args)); \ |
| } |
| LLVM_DEFINE_OVERLOAD(1) |
| LLVM_DEFINE_OVERLOAD(2) |
| LLVM_DEFINE_OVERLOAD(3) |
| LLVM_DEFINE_OVERLOAD(4) |
| LLVM_DEFINE_OVERLOAD(5) |
| LLVM_DEFINE_OVERLOAD(6) |
| LLVM_DEFINE_OVERLOAD(7) |
| LLVM_DEFINE_OVERLOAD(8) |
| LLVM_DEFINE_OVERLOAD(9) |
| LLVM_DEFINE_OVERLOAD(10) |
| LLVM_DEFINE_OVERLOAD(11) |
| LLVM_DEFINE_OVERLOAD(12) |
| LLVM_DEFINE_OVERLOAD(13) |
| LLVM_DEFINE_OVERLOAD(14) |
| LLVM_DEFINE_OVERLOAD(15) |
| LLVM_DEFINE_OVERLOAD(16) |
| LLVM_DEFINE_OVERLOAD(17) |
| LLVM_DEFINE_OVERLOAD(18) |
| LLVM_DEFINE_OVERLOAD(19) |
| LLVM_DEFINE_OVERLOAD(20) |
| LLVM_DEFINE_OVERLOAD(21) |
| LLVM_DEFINE_OVERLOAD(22) |
| LLVM_DEFINE_OVERLOAD(23) |
| LLVM_DEFINE_OVERLOAD(24) |
| LLVM_DEFINE_OVERLOAD(25) |
| LLVM_DEFINE_OVERLOAD(26) |
| LLVM_DEFINE_OVERLOAD(27) |
| LLVM_DEFINE_OVERLOAD(28) |
| LLVM_DEFINE_OVERLOAD(29) |
| LLVM_DEFINE_OVERLOAD(30) |
| LLVM_DEFINE_OVERLOAD(31) |
| LLVM_DEFINE_OVERLOAD(32) |
| #undef LLVM_DEFINE_OVERLOAD |
| }; |
| |
| // Cleanup the macro namespace. |
| #undef LLVM_COMMA_JOIN1 |
| #undef LLVM_COMMA_JOIN2 |
| #undef LLVM_COMMA_JOIN3 |
| #undef LLVM_COMMA_JOIN4 |
| #undef LLVM_COMMA_JOIN5 |
| #undef LLVM_COMMA_JOIN6 |
| #undef LLVM_COMMA_JOIN7 |
| #undef LLVM_COMMA_JOIN8 |
| #undef LLVM_COMMA_JOIN9 |
| #undef LLVM_COMMA_JOIN10 |
| #undef LLVM_COMMA_JOIN11 |
| #undef LLVM_COMMA_JOIN12 |
| #undef LLVM_COMMA_JOIN13 |
| #undef LLVM_COMMA_JOIN14 |
| #undef LLVM_COMMA_JOIN15 |
| #undef LLVM_COMMA_JOIN16 |
| #undef LLVM_COMMA_JOIN17 |
| #undef LLVM_COMMA_JOIN18 |
| #undef LLVM_COMMA_JOIN19 |
| #undef LLVM_COMMA_JOIN20 |
| #undef LLVM_COMMA_JOIN21 |
| #undef LLVM_COMMA_JOIN22 |
| #undef LLVM_COMMA_JOIN23 |
| #undef LLVM_COMMA_JOIN24 |
| #undef LLVM_COMMA_JOIN25 |
| #undef LLVM_COMMA_JOIN26 |
| #undef LLVM_COMMA_JOIN27 |
| #undef LLVM_COMMA_JOIN28 |
| #undef LLVM_COMMA_JOIN29 |
| #undef LLVM_COMMA_JOIN30 |
| #undef LLVM_COMMA_JOIN31 |
| #undef LLVM_COMMA_JOIN32 |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_ADT_VARIADICFUNCTION_H |