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