blob: 365e795cc5dad949680e13492a811fe12c06e367 [file] [log] [blame]
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +00001//===--- 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
21namespace clang {
22namespace clangd {
23
24/// A move-only type-erasing function wrapper. Similar to `std::function`, but
25/// allows to store move-only callables.
26template <class> class UniqueFunction;
27
28template <class Ret, class... Args> class UniqueFunction<Ret(Args...)> {
29public:
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
52private:
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.
82template <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
90public:
91 ForwardBinder(Tuple FuncWithArguments)
92 : FuncWithArguments(std::move(FuncWithArguments)) {}
93
94private:
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
106public:
107 template <class... RestArgs>
108 auto operator()(RestArgs &&... Rest)
Ilya Biryukov4923a802017-10-10 08:40:57 +0000109 -> decltype(this->CallImpl(llvm::index_sequence_for<Args...>(),
110 std::forward<RestArgs>(Rest)...)) {
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +0000111
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.
127template <class Func, class... Args>
128ForwardBinder<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