Ilya Biryukov | 08e6ccb | 2017-10-09 16:26:26 +0000 | [diff] [blame] | 1 | //===--- Function.h - Utility callable wrappers -----------------*- C++-*-===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file provides an analogue to std::function that supports move semantics. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H |
| 15 | #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H |
| 16 | |
| 17 | #include <tuple> |
| 18 | #include <type_traits> |
| 19 | #include <utility> |
| 20 | |
| 21 | namespace clang { |
| 22 | namespace clangd { |
| 23 | |
| 24 | /// A move-only type-erasing function wrapper. Similar to `std::function`, but |
| 25 | /// allows to store move-only callables. |
| 26 | template <class> class UniqueFunction; |
| 27 | |
| 28 | template <class Ret, class... Args> class UniqueFunction<Ret(Args...)> { |
| 29 | public: |
| 30 | UniqueFunction() = default; |
| 31 | UniqueFunction(std::nullptr_t) : UniqueFunction(){}; |
| 32 | |
| 33 | UniqueFunction(UniqueFunction const &) = delete; |
| 34 | UniqueFunction &operator=(UniqueFunction const &) = delete; |
| 35 | |
| 36 | UniqueFunction(UniqueFunction &&) noexcept = default; |
| 37 | UniqueFunction &operator=(UniqueFunction &&) noexcept = default; |
| 38 | |
| 39 | template <class Callable> |
| 40 | UniqueFunction(Callable &&Func) |
| 41 | : CallablePtr(llvm::make_unique< |
| 42 | FunctionCallImpl<typename std::decay<Callable>::type>>( |
| 43 | std::forward<Callable>(Func))) {} |
| 44 | |
| 45 | operator bool() { return CallablePtr; } |
| 46 | |
| 47 | Ret operator()(Args... As) { |
| 48 | assert(CallablePtr); |
| 49 | CallablePtr->Call(std::forward<Args>(As)...); |
| 50 | } |
| 51 | |
| 52 | private: |
| 53 | class FunctionCallBase { |
| 54 | public: |
| 55 | virtual ~FunctionCallBase() = default; |
| 56 | virtual Ret Call(Args... As) = 0; |
| 57 | }; |
| 58 | |
| 59 | template <class Callable> |
| 60 | class FunctionCallImpl final : public FunctionCallBase { |
| 61 | static_assert( |
| 62 | std::is_same<Callable, typename std::decay<Callable>::type>::value, |
| 63 | "FunctionCallImpl must be instanstiated with std::decay'ed types"); |
| 64 | |
| 65 | public: |
| 66 | FunctionCallImpl(Callable Func) : Func(std::move(Func)) {} |
| 67 | |
| 68 | Ret Call(Args... As) override { return Func(std::forward<Args>(As)...); } |
| 69 | |
| 70 | private: |
| 71 | Callable Func; |
| 72 | }; |
| 73 | |
| 74 | std::unique_ptr<FunctionCallBase> CallablePtr; |
| 75 | }; |
| 76 | |
| 77 | /// Stores a callable object (Func) and arguments (Args) and allows to call the |
| 78 | /// callable with provided arguments later using `operator ()`. The arguments |
| 79 | /// are std::forward'ed into the callable in the body of `operator()`. Therefore |
| 80 | /// `operator()` can only be called once, as some of the arguments could be |
| 81 | /// std::move'ed into the callable on first call. |
| 82 | template <class Func, class... Args> struct ForwardBinder { |
| 83 | using Tuple = std::tuple<typename std::decay<Func>::type, |
| 84 | typename std::decay<Args>::type...>; |
| 85 | Tuple FuncWithArguments; |
| 86 | #ifndef NDEBUG |
| 87 | bool WasCalled = false; |
| 88 | #endif |
| 89 | |
| 90 | public: |
| 91 | ForwardBinder(Tuple FuncWithArguments) |
| 92 | : FuncWithArguments(std::move(FuncWithArguments)) {} |
| 93 | |
| 94 | private: |
| 95 | template <std::size_t... Indexes, class... RestArgs> |
| 96 | auto CallImpl(llvm::integer_sequence<std::size_t, Indexes...> Seq, |
| 97 | RestArgs &&... Rest) |
| 98 | -> decltype(std::get<0>(this->FuncWithArguments)( |
| 99 | std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))..., |
| 100 | std::forward<RestArgs>(Rest)...)) { |
| 101 | return std::get<0>(this->FuncWithArguments)( |
| 102 | std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))..., |
| 103 | std::forward<RestArgs>(Rest)...); |
| 104 | } |
| 105 | |
| 106 | public: |
| 107 | template <class... RestArgs> |
| 108 | auto operator()(RestArgs &&... Rest) |
Ilya Biryukov | 4923a80 | 2017-10-10 08:40:57 +0000 | [diff] [blame^] | 109 | -> decltype(this->CallImpl(llvm::index_sequence_for<Args...>(), |
| 110 | std::forward<RestArgs>(Rest)...)) { |
Ilya Biryukov | 08e6ccb | 2017-10-09 16:26:26 +0000 | [diff] [blame] | 111 | |
| 112 | #ifndef NDEBUG |
| 113 | assert(!WasCalled && "Can only call result of BindWithForward once."); |
| 114 | WasCalled = true; |
| 115 | #endif |
| 116 | return CallImpl(llvm::index_sequence_for<Args...>(), |
| 117 | std::forward<RestArgs>(Rest)...); |
| 118 | } |
| 119 | }; |
| 120 | |
| 121 | /// Creates an object that stores a callable (\p F) and first arguments to the |
| 122 | /// callable (\p As) and allows to call \p F with \Args at a later point. |
| 123 | /// Similar to std::bind, but also works with move-only \p F and \p As. |
| 124 | /// |
| 125 | /// The returned object must be called no more than once, as \p As are |
| 126 | /// std::forwarded'ed (therefore can be moved) into \p F during the call. |
| 127 | template <class Func, class... Args> |
| 128 | ForwardBinder<Func, Args...> BindWithForward(Func F, Args &&... As) { |
| 129 | return ForwardBinder<Func, Args...>( |
| 130 | std::make_tuple(std::forward<Func>(F), std::forward<Args>(As)...)); |
| 131 | } |
| 132 | |
| 133 | } // namespace clangd |
| 134 | } // namespace clang |
| 135 | |
| 136 | #endif |