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...>;
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  }
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.
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
std::function< void(const std::vector< std::string > &)> Listener
Definition: Function.h:91
Subscription(Subscription &&Other)
Definition: Function.h:105
An Event<T> allows events of type T to be broadcast to listeners.
Definition: Function.h:88
llvm::unique_function< void(llvm::Expected< T >)> Callback
A Callback<T> is a void function that accepts Expected<T>.
Definition: Function.h:29
Subscription & operator=(Subscription &&Other)
Definition: Function.h:108
void broadcast(const T &V)
Definition: Function.h:140
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
ForwardBinder(Tuple FuncWithArguments)
Definition: Function.h:45
std::tuple< typename std::decay< Func >::type, typename std::decay< Args >::type... > Tuple
Definition: Function.h:38
===– Representation.cpp - ClangDoc Representation --------—*- C++ -*-===//
Stores a callable object (Func) and arguments (Args) and allows to call the callable with provided ar...
Definition: Function.h:36
auto operator()(RestArgs &&... Rest) -> decltype(this->CallImpl(llvm::index_sequence_for< Args... >(), std::forward< RestArgs >(Rest)...))
Definition: Function.h:62
Subscription observe(Listener L)
Definition: Function.h:132