blob: 975134b51d21a5c277774b7cbd0ebcac6d1b3625 [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"
Sam McCalla7bb0cc2018-03-12 23:22:35 +000018#include "llvm/Support/Error.h"
Ilya Biryukoveab499d2017-10-10 16:12:50 +000019#include <cassert>
20#include <memory>
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000021#include <tuple>
22#include <type_traits>
23#include <utility>
24
25namespace clang {
26namespace clangd {
27
28/// A move-only type-erasing function wrapper. Similar to `std::function`, but
29/// allows to store move-only callables.
30template <class> class UniqueFunction;
Sam McCalla7bb0cc2018-03-12 23:22:35 +000031/// A Callback<T> is a void function that accepts Expected<T>.
32/// This is accepted by ClangdServer functions that logically return T.
33template <typename T> using Callback = UniqueFunction<void(llvm::Expected<T>)>;
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000034
35template <class Ret, class... Args> class UniqueFunction<Ret(Args...)> {
36public:
37 UniqueFunction() = default;
38 UniqueFunction(std::nullptr_t) : UniqueFunction(){};
39
40 UniqueFunction(UniqueFunction const &) = delete;
41 UniqueFunction &operator=(UniqueFunction const &) = delete;
42
43 UniqueFunction(UniqueFunction &&) noexcept = default;
44 UniqueFunction &operator=(UniqueFunction &&) noexcept = default;
45
Ilya Biryukov940901e2017-12-13 12:51:22 +000046 template <class Callable,
47 /// A sfinae-check that Callable can be called with Args... and
48 class = typename std::enable_if<std::is_convertible<
49 decltype(std::declval<Callable>()(std::declval<Args>()...)),
50 Ret>::value>::type>
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000051 UniqueFunction(Callable &&Func)
52 : CallablePtr(llvm::make_unique<
53 FunctionCallImpl<typename std::decay<Callable>::type>>(
54 std::forward<Callable>(Func))) {}
55
Ilya Biryukov0d501682017-12-20 14:06:05 +000056 explicit operator bool() { return bool(CallablePtr); }
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000057
58 Ret operator()(Args... As) {
59 assert(CallablePtr);
Ilya Biryukovcfcc0d32017-10-10 16:12:47 +000060 return CallablePtr->Call(std::forward<Args>(As)...);
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +000061 }
62
63private:
64 class FunctionCallBase {
65 public:
66 virtual ~FunctionCallBase() = default;
67 virtual Ret Call(Args... As) = 0;
68 };
69
70 template <class Callable>
71 class FunctionCallImpl final : public FunctionCallBase {
72 static_assert(
73 std::is_same<Callable, typename std::decay<Callable>::type>::value,
74 "FunctionCallImpl must be instanstiated with std::decay'ed types");
75
76 public:
77 FunctionCallImpl(Callable Func) : Func(std::move(Func)) {}
78
79 Ret Call(Args... As) override { return Func(std::forward<Args>(As)...); }
80
81 private:
82 Callable Func;
83 };
84
85 std::unique_ptr<FunctionCallBase> CallablePtr;
86};
87
88/// Stores a callable object (Func) and arguments (Args) and allows to call the
89/// callable with provided arguments later using `operator ()`. The arguments
90/// are std::forward'ed into the callable in the body of `operator()`. Therefore
91/// `operator()` can only be called once, as some of the arguments could be
92/// std::move'ed into the callable on first call.
93template <class Func, class... Args> struct ForwardBinder {
94 using Tuple = std::tuple<typename std::decay<Func>::type,
95 typename std::decay<Args>::type...>;
96 Tuple FuncWithArguments;
97#ifndef NDEBUG
98 bool WasCalled = false;
99#endif
100
101public:
102 ForwardBinder(Tuple FuncWithArguments)
103 : FuncWithArguments(std::move(FuncWithArguments)) {}
104
105private:
106 template <std::size_t... Indexes, class... RestArgs>
107 auto CallImpl(llvm::integer_sequence<std::size_t, Indexes...> Seq,
108 RestArgs &&... Rest)
109 -> decltype(std::get<0>(this->FuncWithArguments)(
110 std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
111 std::forward<RestArgs>(Rest)...)) {
112 return std::get<0>(this->FuncWithArguments)(
113 std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
114 std::forward<RestArgs>(Rest)...);
115 }
116
117public:
118 template <class... RestArgs>
119 auto operator()(RestArgs &&... Rest)
Ilya Biryukov4923a802017-10-10 08:40:57 +0000120 -> decltype(this->CallImpl(llvm::index_sequence_for<Args...>(),
121 std::forward<RestArgs>(Rest)...)) {
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +0000122
123#ifndef NDEBUG
Sam McCall091557d2018-02-23 07:54:17 +0000124 assert(!WasCalled && "Can only call result of Bind once.");
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +0000125 WasCalled = true;
126#endif
127 return CallImpl(llvm::index_sequence_for<Args...>(),
128 std::forward<RestArgs>(Rest)...);
129 }
130};
131
132/// Creates an object that stores a callable (\p F) and first arguments to the
133/// callable (\p As) and allows to call \p F with \Args at a later point.
134/// Similar to std::bind, but also works with move-only \p F and \p As.
135///
136/// The returned object must be called no more than once, as \p As are
137/// std::forwarded'ed (therefore can be moved) into \p F during the call.
138template <class Func, class... Args>
Sam McCall091557d2018-02-23 07:54:17 +0000139ForwardBinder<Func, Args...> Bind(Func F, Args &&... As) {
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +0000140 return ForwardBinder<Func, Args...>(
141 std::make_tuple(std::forward<Func>(F), std::forward<Args>(As)...));
142}
143
Ilya Biryukov08e6ccb2017-10-09 16:26:26 +0000144} // namespace clangd
145} // namespace clang
146
147#endif