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 | // |
Benjamin Kramer | c36c09f | 2018-07-03 20:59:33 +0000 | [diff] [blame] | 10 | // This file provides utilities for callable objects. |
Ilya Biryukov | 08e6ccb | 2017-10-09 16:26:26 +0000 | [diff] [blame] | 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H |
| 15 | #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H |
| 16 | |
Benjamin Kramer | c36c09f | 2018-07-03 20:59:33 +0000 | [diff] [blame] | 17 | #include "llvm/ADT/FunctionExtras.h" |
Sam McCall | a7bb0cc | 2018-03-12 23:22:35 +0000 | [diff] [blame] | 18 | #include "llvm/Support/Error.h" |
Ilya Biryukov | 08e6ccb | 2017-10-09 16:26:26 +0000 | [diff] [blame] | 19 | #include <tuple> |
Ilya Biryukov | 08e6ccb | 2017-10-09 16:26:26 +0000 | [diff] [blame] | 20 | #include <utility> |
| 21 | |
| 22 | namespace clang { |
| 23 | namespace clangd { |
| 24 | |
Sam McCall | a7bb0cc | 2018-03-12 23:22:35 +0000 | [diff] [blame] | 25 | /// A Callback<T> is a void function that accepts Expected<T>. |
| 26 | /// This is accepted by ClangdServer functions that logically return T. |
Benjamin Kramer | c36c09f | 2018-07-03 20:59:33 +0000 | [diff] [blame] | 27 | template <typename T> |
| 28 | using Callback = llvm::unique_function<void(llvm::Expected<T>)>; |
Ilya Biryukov | 08e6ccb | 2017-10-09 16:26:26 +0000 | [diff] [blame] | 29 | |
| 30 | /// Stores a callable object (Func) and arguments (Args) and allows to call the |
| 31 | /// callable with provided arguments later using `operator ()`. The arguments |
| 32 | /// are std::forward'ed into the callable in the body of `operator()`. Therefore |
| 33 | /// `operator()` can only be called once, as some of the arguments could be |
| 34 | /// std::move'ed into the callable on first call. |
| 35 | template <class Func, class... Args> struct ForwardBinder { |
| 36 | using Tuple = std::tuple<typename std::decay<Func>::type, |
| 37 | typename std::decay<Args>::type...>; |
| 38 | Tuple FuncWithArguments; |
| 39 | #ifndef NDEBUG |
| 40 | bool WasCalled = false; |
| 41 | #endif |
| 42 | |
| 43 | public: |
| 44 | ForwardBinder(Tuple FuncWithArguments) |
| 45 | : FuncWithArguments(std::move(FuncWithArguments)) {} |
| 46 | |
| 47 | private: |
| 48 | template <std::size_t... Indexes, class... RestArgs> |
| 49 | auto CallImpl(llvm::integer_sequence<std::size_t, Indexes...> Seq, |
| 50 | RestArgs &&... Rest) |
| 51 | -> decltype(std::get<0>(this->FuncWithArguments)( |
| 52 | std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))..., |
| 53 | std::forward<RestArgs>(Rest)...)) { |
| 54 | return std::get<0>(this->FuncWithArguments)( |
| 55 | std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))..., |
| 56 | std::forward<RestArgs>(Rest)...); |
| 57 | } |
| 58 | |
| 59 | public: |
| 60 | template <class... RestArgs> |
| 61 | auto operator()(RestArgs &&... Rest) |
Ilya Biryukov | 4923a80 | 2017-10-10 08:40:57 +0000 | [diff] [blame] | 62 | -> decltype(this->CallImpl(llvm::index_sequence_for<Args...>(), |
| 63 | std::forward<RestArgs>(Rest)...)) { |
Ilya Biryukov | 08e6ccb | 2017-10-09 16:26:26 +0000 | [diff] [blame] | 64 | |
| 65 | #ifndef NDEBUG |
Sam McCall | 091557d | 2018-02-23 07:54:17 +0000 | [diff] [blame] | 66 | assert(!WasCalled && "Can only call result of Bind once."); |
Ilya Biryukov | 08e6ccb | 2017-10-09 16:26:26 +0000 | [diff] [blame] | 67 | WasCalled = true; |
| 68 | #endif |
| 69 | return CallImpl(llvm::index_sequence_for<Args...>(), |
| 70 | std::forward<RestArgs>(Rest)...); |
| 71 | } |
| 72 | }; |
| 73 | |
| 74 | /// Creates an object that stores a callable (\p F) and first arguments to the |
| 75 | /// callable (\p As) and allows to call \p F with \Args at a later point. |
| 76 | /// Similar to std::bind, but also works with move-only \p F and \p As. |
| 77 | /// |
| 78 | /// The returned object must be called no more than once, as \p As are |
| 79 | /// std::forwarded'ed (therefore can be moved) into \p F during the call. |
| 80 | template <class Func, class... Args> |
Sam McCall | 091557d | 2018-02-23 07:54:17 +0000 | [diff] [blame] | 81 | ForwardBinder<Func, Args...> Bind(Func F, Args &&... As) { |
Ilya Biryukov | 08e6ccb | 2017-10-09 16:26:26 +0000 | [diff] [blame] | 82 | return ForwardBinder<Func, Args...>( |
| 83 | std::make_tuple(std::forward<Func>(F), std::forward<Args>(As)...)); |
| 84 | } |
| 85 | |
Ilya Biryukov | 08e6ccb | 2017-10-09 16:26:26 +0000 | [diff] [blame] | 86 | } // namespace clangd |
| 87 | } // namespace clang |
| 88 | |
| 89 | #endif |