blob: 8d1da07d09519d0c0c400dd381f4ba11c1239025 [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
Ilya Biryukoveab499d2017-10-10 16:12:50 +000017#include "llvm/ADT/STLExtras.h"
18#include <cassert>
19#include <memory>
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000020#include <tuple>
21#include <type_traits>
22#include <utility>
23
24namespace clang {
25namespace clangd {
26
27/// A move-only type-erasing function wrapper. Similar to `std::function`, but
28/// allows to store move-only callables.
29template <class> class UniqueFunction;
30
31template <class Ret, class... Args> class UniqueFunction<Ret(Args...)> {
32public:
33 UniqueFunction() = default;
34 UniqueFunction(std::nullptr_t) : UniqueFunction(){};
35
36 UniqueFunction(UniqueFunction const &) = delete;
37 UniqueFunction &operator=(UniqueFunction const &) = delete;
38
39 UniqueFunction(UniqueFunction &&) noexcept = default;
40 UniqueFunction &operator=(UniqueFunction &&) noexcept = default;
41
Ilya Biryukov940901e2017-12-13 12:51:22 +000042 template <class Callable,
43 /// A sfinae-check that Callable can be called with Args... and
44 class = typename std::enable_if<std::is_convertible<
45 decltype(std::declval<Callable>()(std::declval<Args>()...)),
46 Ret>::value>::type>
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000047 UniqueFunction(Callable &&Func)
48 : CallablePtr(llvm::make_unique<
49 FunctionCallImpl<typename std::decay<Callable>::type>>(
50 std::forward<Callable>(Func))) {}
51
Ilya Biryukov0d501682017-12-20 14:06:05 +000052 explicit operator bool() { return bool(CallablePtr); }
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000053
54 Ret operator()(Args... As) {
55 assert(CallablePtr);
Ilya Biryukovcfcc0d32017-10-10 16:12:47 +000056 return CallablePtr->Call(std::forward<Args>(As)...);
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000057 }
58
59private:
60 class FunctionCallBase {
61 public:
62 virtual ~FunctionCallBase() = default;
63 virtual Ret Call(Args... As) = 0;
64 };
65
66 template <class Callable>
67 class FunctionCallImpl final : public FunctionCallBase {
68 static_assert(
69 std::is_same<Callable, typename std::decay<Callable>::type>::value,
70 "FunctionCallImpl must be instanstiated with std::decay'ed types");
71
72 public:
73 FunctionCallImpl(Callable Func) : Func(std::move(Func)) {}
74
75 Ret Call(Args... As) override { return Func(std::forward<Args>(As)...); }
76
77 private:
78 Callable Func;
79 };
80
81 std::unique_ptr<FunctionCallBase> CallablePtr;
82};
83
84/// Stores a callable object (Func) and arguments (Args) and allows to call the
85/// callable with provided arguments later using `operator ()`. The arguments
86/// are std::forward'ed into the callable in the body of `operator()`. Therefore
87/// `operator()` can only be called once, as some of the arguments could be
88/// std::move'ed into the callable on first call.
89template <class Func, class... Args> struct ForwardBinder {
90 using Tuple = std::tuple<typename std::decay<Func>::type,
91 typename std::decay<Args>::type...>;
92 Tuple FuncWithArguments;
93#ifndef NDEBUG
94 bool WasCalled = false;
95#endif
96
97public:
98 ForwardBinder(Tuple FuncWithArguments)
99 : FuncWithArguments(std::move(FuncWithArguments)) {}
100
101private:
102 template <std::size_t... Indexes, class... RestArgs>
103 auto CallImpl(llvm::integer_sequence<std::size_t, Indexes...> Seq,
104 RestArgs &&... Rest)
105 -> decltype(std::get<0>(this->FuncWithArguments)(
106 std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
107 std::forward<RestArgs>(Rest)...)) {
108 return std::get<0>(this->FuncWithArguments)(
109 std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
110 std::forward<RestArgs>(Rest)...);
111 }
112
113public:
114 template <class... RestArgs>
115 auto operator()(RestArgs &&... Rest)
Ilya Biryukov4923a802017-10-10 08:40:57 +0000116 -> decltype(this->CallImpl(llvm::index_sequence_for<Args...>(),
117 std::forward<RestArgs>(Rest)...)) {
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +0000118
119#ifndef NDEBUG
120 assert(!WasCalled && "Can only call result of BindWithForward once.");
121 WasCalled = true;
122#endif
123 return CallImpl(llvm::index_sequence_for<Args...>(),
124 std::forward<RestArgs>(Rest)...);
125 }
126};
127
128/// Creates an object that stores a callable (\p F) and first arguments to the
129/// callable (\p As) and allows to call \p F with \Args at a later point.
130/// Similar to std::bind, but also works with move-only \p F and \p As.
131///
132/// The returned object must be called no more than once, as \p As are
133/// std::forwarded'ed (therefore can be moved) into \p F during the call.
134template <class Func, class... Args>
135ForwardBinder<Func, Args...> BindWithForward(Func F, Args &&... As) {
136 return ForwardBinder<Func, Args...>(
137 std::make_tuple(std::forward<Func>(F), std::forward<Args>(As)...));
138}
139
Ilya Biryukov940901e2017-12-13 12:51:22 +0000140namespace detail {
141/// Runs provided callback in destructor. Use onScopeExit helper function to
142/// create this object.
143template <class Func> struct ScopeExitGuard {
144 static_assert(std::is_same<typename std::decay<Func>::type, Func>::value,
145 "Func must be decayed");
146
147 ScopeExitGuard(Func F) : F(std::move(F)) {}
148 ~ScopeExitGuard() {
149 if (!F)
150 return;
151 (*F)();
152 }
153
154 // Move-only.
155 ScopeExitGuard(const ScopeExitGuard &) = delete;
156 ScopeExitGuard &operator=(const ScopeExitGuard &) = delete;
157
158 ScopeExitGuard(ScopeExitGuard &&Other) = default;
159 ScopeExitGuard &operator=(ScopeExitGuard &&Other) = default;
160
161private:
162 llvm::Optional<Func> F;
163};
164} // namespace detail
165
166/// Creates a RAII object that will run \p F in its destructor.
167template <class Func>
168auto onScopeExit(Func &&F)
169 -> detail::ScopeExitGuard<typename std::decay<Func>::type> {
170 return detail::ScopeExitGuard<typename std::decay<Func>::type>(
171 std::forward<Func>(F));
172}
173
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +0000174} // namespace clangd
175} // namespace clang
176
177#endif