clang-tools 8.0.0

Function.h
Go to the documentation of this file.
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 utilities for callable objects.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H
15 #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H
16
17 #include "llvm/ADT/FunctionExtras.h"
18 #include "llvm/Support/Error.h"
19 #include <mutex>
20 #include <tuple>
21 #include <utility>
22
23 namespace clang {
24 namespace clangd {
25
26 /// A Callback<T> is a void function that accepts Expected<T>.
27 /// This is accepted by ClangdServer functions that logically return T.
28 template <typename T>
29 using Callback = llvm::unique_function<void(llvm::Expected<T>)>;
30
31 /// Stores a callable object (Func) and arguments (Args) and allows to call the
32 /// callable with provided arguments later using `operator ()`. The arguments
33 /// are std::forward'ed into the callable in the body of `operator()`. Therefore
34 /// `operator()` can only be called once, as some of the arguments could be
35 /// std::move'ed into the callable on first call.
36 template <class Func, class... Args> struct ForwardBinder {
37 using Tuple = std::tuple<typename std::decay<Func>::type,
38 typename std::decay<Args>::type...>;
39 Tuple FuncWithArguments;
40 #ifndef NDEBUG
41 bool WasCalled = false;
42 #endif
43
44 public:
45 ForwardBinder(Tuple FuncWithArguments)
46 : FuncWithArguments(std::move(FuncWithArguments)) {}
47
48 private:
49 template <std::size_t... Indexes, class... RestArgs>
50 auto CallImpl(llvm::integer_sequence<std::size_t, Indexes...> Seq,
51 RestArgs &&... Rest)
52 -> decltype(std::get<0>(this->FuncWithArguments)(
53 std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
54 std::forward<RestArgs>(Rest)...)) {
55 return std::get<0>(this->FuncWithArguments)(
56 std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))...,
57 std::forward<RestArgs>(Rest)...);
58 }
59
60 public:
61 template <class... RestArgs>
62 auto operator()(RestArgs &&... Rest)
63 -> decltype(this->CallImpl(llvm::index_sequence_for<Args...>(),
64 std::forward<RestArgs>(Rest)...)) {
65
66 #ifndef NDEBUG
67 assert(!WasCalled && "Can only call result of Bind once.");
68 WasCalled = true;
69 #endif
70 return CallImpl(llvm::index_sequence_for<Args...>(),
71 std::forward<RestArgs>(Rest)...);
72 }
73 };
74
75 /// Creates an object that stores a callable (\p F) and first arguments to the
76 /// callable (\p As) and allows to call \p F with \Args at a later point.
77 /// Similar to std::bind, but also works with move-only \p F and \p As.
78 ///
79 /// The returned object must be called no more than once, as \p As are
80 /// std::forwarded'ed (therefore can be moved) into \p F during the call.
81 template <class Func, class... Args>
82 ForwardBinder<Func, Args...> Bind(Func F, Args &&... As) {
83 return ForwardBinder<Func, Args...>(
84 std::make_tuple(std::forward<Func>(F), std::forward<Args>(As)...));
85 }
86
87 /// An Event<T> allows events of type T to be broadcast to listeners.
88 template <typename T> class Event {
89 public:
90 // A Listener is the callback through which events are delivered.
91 using Listener = std::function<void(const T &)>;
92
93 // A subscription defines the scope of when a listener should receive events.
94 // After destroying the subscription, no more events are received.
95 class LLVM_NODISCARD Subscription {
96 Event *Parent;
97 unsigned ListenerID;
98
99 Subscription(Event *Parent, unsigned ListenerID)
100 : Parent(Parent), ListenerID(ListenerID) {}
101 friend Event;
102
103 public:
104 Subscription() : Parent(nullptr) {}
105 Subscription(Subscription &&Other) : Parent(nullptr) {
106 *this = std::move(Other);
107 }
108 Subscription &operator=(Subscription &&Other) {
109 // If *this is active, unsubscribe.
110 if (Parent) {
111 std::lock_guard<std::recursive_mutex>(Parent->ListenersMu);
112 llvm::erase_if(Parent->Listeners,
113 [&](const std::pair<Listener, unsigned> &P) {
114 return P.second == ListenerID;
115 });
116 }
117 // Take over the other subscription, and mark it inactive.
118 std::tie(Parent, ListenerID) = std::tie(Other.Parent, Other.ListenerID);
119 Other.Parent = nullptr;
120 return *this;
121 }
122 // Destroying a subscription may block if an event is being broadcast.
123 ~Subscription() {
124 if (Parent)
125 *this = Subscription(); // Unsubscribe.
126 }
127 };
128
129 // Adds a listener that will observe all future events until the returned
130 // subscription is destroyed.
131 // May block if an event is currently being broadcast.
132 Subscription observe(Listener L) {
133 std::lock_guard<std::recursive_mutex> Lock(ListenersMu);
134 Listeners.push_back({std::move(L), ++ListenerCount});
135 return Subscription(this, ListenerCount);
136 }
137
138 // Synchronously sends an event to all registered listeners.
139 // Must not be called from a listener to this event.
140 void broadcast(const T &V) {
141 // FIXME: it would be nice to dynamically check non-reentrancy here.
142 std::lock_guard<std::recursive_mutex> Lock(ListenersMu);
143 for (const auto &L : Listeners)
144 L.first(V);
145 }
146
147 ~Event() {
148 std::lock_guard<std::recursive_mutex> Lock(ListenersMu);
149 assert(Listeners.empty());
150 }
151
152 private:
153 static_assert(std::is_same<typename std::decay<T>::type, T>::value,
154 "use a plain type: event values are always passed by const&");
155
156 std::recursive_mutex ListenersMu;
157 bool IsBroadcasting = false;
158 std::vector<std::pair<Listener, unsigned>> Listeners;
159 unsigned ListenerCount = 0;
160 };
161
162 } // namespace clangd
163 } // namespace clang
164
165 #endif
clang::clangd::Event< std::vector< std::string > >::Listener
std::function< void(const std::vector< std::string > &)> Listener
Definition: Function.h:91
clang::clangd::Event::Subscription::Subscription
Subscription(Subscription &&Other)
Definition: Function.h:105
clang::clangd::Event
An Event<T> allows events of type T to be broadcast to listeners.
Definition: Function.h:88
clang::clangd::Callback
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:29
clang::clangd::Event::Subscription
Definition: Function.h:95
clang::clangd::Event::Subscription::operator=
Subscription & operator=(Subscription &&Other)
Definition: Function.h:108
clang::clangd::Event::broadcast
void broadcast(const T &V)
Definition: Function.h:140
clang::clangd::Bind
ForwardBinder< Func, Args... > Bind(Func F, Args &&... As)
Creates an object that stores a callable (F) and first arguments to the callable (As) and allows to c...
Definition: Function.h:82
clang::clangd::Event::~Event
~Event()
Definition: Function.h:147
clang::clangd::ForwardBinder::ForwardBinder
ForwardBinder(Tuple FuncWithArguments)
Definition: Function.h:45
clang::clangd::ForwardBinder::Tuple
std::tuple< typename std::decay< Func >::type, typename std::decay< Args >::type... > Tuple
Definition: Function.h:38
clang::clangd::CompletionItemKind::Event
clang::clangd::ForwardBinder::WasCalled
bool WasCalled
Definition: Function.h:41
clang
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Definition: ChangeNamespace.cpp:18
clang::clangd::ForwardBinder::FuncWithArguments
Tuple FuncWithArguments
Definition: Function.h:39
clang::clangd::Event::Subscription::Subscription
Subscription()
Definition: Function.h:104
clang::clangd::ForwardBinder
Stores a callable object (Func) and arguments (Args) and allows to call the callable with provided ar...
Definition: Function.h:36
clang::clangd::ForwardBinder::operator()
auto operator()(RestArgs &&... Rest) -> decltype(this->CallImpl(llvm::index_sequence_for< Args... >(), std::forward< RestArgs >(Rest)...))
Definition: Function.h:62
clang::clangd::Event::observe
Subscription observe(Listener L)
Definition: Function.h:132
clang::clangd::Event::Subscription::~Subscription
~Subscription()
Definition: Function.h:123