|  | //===--- Function.h - Utility callable wrappers  -----------------*- C++-*-===// | 
|  | // | 
|  | //                     The LLVM Compiler Infrastructure | 
|  | // | 
|  | // This file is distributed under the University of Illinois Open Source | 
|  | // License. See LICENSE.TXT for details. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file provides utilities for callable objects. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H | 
|  | #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_FUNCTION_H | 
|  |  | 
|  | #include "llvm/ADT/FunctionExtras.h" | 
|  | #include "llvm/Support/Error.h" | 
|  | #include <mutex> | 
|  | #include <tuple> | 
|  | #include <utility> | 
|  |  | 
|  | namespace clang { | 
|  | namespace clangd { | 
|  |  | 
|  | /// A Callback<T> is a void function that accepts Expected<T>. | 
|  | /// This is accepted by ClangdServer functions that logically return T. | 
|  | template <typename T> | 
|  | using Callback = llvm::unique_function<void(llvm::Expected<T>)>; | 
|  |  | 
|  | /// Stores a callable object (Func) and arguments (Args) and allows to call the | 
|  | /// callable with provided arguments later using `operator ()`. The arguments | 
|  | /// are std::forward'ed into the callable in the body of `operator()`. Therefore | 
|  | /// `operator()` can only be called once, as some of the arguments could be | 
|  | /// std::move'ed into the callable on first call. | 
|  | template <class Func, class... Args> struct ForwardBinder { | 
|  | using Tuple = std::tuple<typename std::decay<Func>::type, | 
|  | typename std::decay<Args>::type...>; | 
|  | Tuple FuncWithArguments; | 
|  | #ifndef NDEBUG | 
|  | bool WasCalled = false; | 
|  | #endif | 
|  |  | 
|  | public: | 
|  | ForwardBinder(Tuple FuncWithArguments) | 
|  | : FuncWithArguments(std::move(FuncWithArguments)) {} | 
|  |  | 
|  | private: | 
|  | template <std::size_t... Indexes, class... RestArgs> | 
|  | auto CallImpl(llvm::integer_sequence<std::size_t, Indexes...> Seq, | 
|  | RestArgs &&... Rest) | 
|  | -> decltype(std::get<0>(this->FuncWithArguments)( | 
|  | std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))..., | 
|  | std::forward<RestArgs>(Rest)...)) { | 
|  | return std::get<0>(this->FuncWithArguments)( | 
|  | std::forward<Args>(std::get<Indexes + 1>(this->FuncWithArguments))..., | 
|  | std::forward<RestArgs>(Rest)...); | 
|  | } | 
|  |  | 
|  | public: | 
|  | template <class... RestArgs> | 
|  | auto operator()(RestArgs &&... Rest) | 
|  | -> decltype(this->CallImpl(llvm::index_sequence_for<Args...>(), | 
|  | std::forward<RestArgs>(Rest)...)) { | 
|  |  | 
|  | #ifndef NDEBUG | 
|  | assert(!WasCalled && "Can only call result of Bind once."); | 
|  | WasCalled = true; | 
|  | #endif | 
|  | return CallImpl(llvm::index_sequence_for<Args...>(), | 
|  | std::forward<RestArgs>(Rest)...); | 
|  | } | 
|  | }; | 
|  |  | 
|  | /// Creates an object that stores a callable (\p F) and first arguments to the | 
|  | /// callable (\p As) and allows to call \p F with \Args at a later point. | 
|  | /// Similar to std::bind, but also works with move-only \p F and \p As. | 
|  | /// | 
|  | /// The returned object must be called no more than once, as \p As are | 
|  | /// std::forwarded'ed (therefore can be moved) into \p F during the call. | 
|  | template <class Func, class... Args> | 
|  | ForwardBinder<Func, Args...> Bind(Func F, Args &&... As) { | 
|  | return ForwardBinder<Func, Args...>( | 
|  | std::make_tuple(std::forward<Func>(F), std::forward<Args>(As)...)); | 
|  | } | 
|  |  | 
|  | /// An Event<T> allows events of type T to be broadcast to listeners. | 
|  | template <typename T> class Event { | 
|  | public: | 
|  | // A Listener is the callback through which events are delivered. | 
|  | using Listener = std::function<void(const T &)>; | 
|  |  | 
|  | // A subscription defines the scope of when a listener should receive events. | 
|  | // After destroying the subscription, no more events are received. | 
|  | class LLVM_NODISCARD Subscription { | 
|  | Event *Parent; | 
|  | unsigned ListenerID; | 
|  |  | 
|  | Subscription(Event *Parent, unsigned ListenerID) | 
|  | : Parent(Parent), ListenerID(ListenerID) {} | 
|  | friend Event; | 
|  |  | 
|  | public: | 
|  | Subscription() : Parent(nullptr) {} | 
|  | Subscription(Subscription &&Other) : Parent(nullptr) { | 
|  | *this = std::move(Other); | 
|  | } | 
|  | Subscription &operator=(Subscription &&Other) { | 
|  | // If *this is active, unsubscribe. | 
|  | if (Parent) { | 
|  | std::lock_guard<std::recursive_mutex>(Parent->ListenersMu); | 
|  | llvm::erase_if(Parent->Listeners, | 
|  | [&](const std::pair<Listener, unsigned> &P) { | 
|  | return P.second == ListenerID; | 
|  | }); | 
|  | } | 
|  | // Take over the other subscription, and mark it inactive. | 
|  | std::tie(Parent, ListenerID) = std::tie(Other.Parent, Other.ListenerID); | 
|  | Other.Parent = nullptr; | 
|  | return *this; | 
|  | } | 
|  | // Destroying a subscription may block if an event is being broadcast. | 
|  | ~Subscription() { | 
|  | if (Parent) | 
|  | *this = Subscription(); // Unsubscribe. | 
|  | } | 
|  | }; | 
|  |  | 
|  | // Adds a listener that will observe all future events until the returned | 
|  | // subscription is destroyed. | 
|  | // May block if an event is currently being broadcast. | 
|  | Subscription observe(Listener L) { | 
|  | std::lock_guard<std::recursive_mutex> Lock(ListenersMu); | 
|  | Listeners.push_back({std::move(L), ++ListenerCount}); | 
|  | return Subscription(this, ListenerCount); | 
|  | } | 
|  |  | 
|  | // Synchronously sends an event to all registered listeners. | 
|  | // Must not be called from a listener to this event. | 
|  | void broadcast(const T &V) { | 
|  | // FIXME: it would be nice to dynamically check non-reentrancy here. | 
|  | std::lock_guard<std::recursive_mutex> Lock(ListenersMu); | 
|  | for (const auto &L : Listeners) | 
|  | L.first(V); | 
|  | } | 
|  |  | 
|  | ~Event() { | 
|  | std::lock_guard<std::recursive_mutex> Lock(ListenersMu); | 
|  | assert(Listeners.empty()); | 
|  | } | 
|  |  | 
|  | private: | 
|  | static_assert(std::is_same<typename std::decay<T>::type, T>::value, | 
|  | "use a plain type: event values are always passed by const&"); | 
|  |  | 
|  | std::recursive_mutex ListenersMu; | 
|  | bool IsBroadcasting = false; | 
|  | std::vector<std::pair<Listener, unsigned>> Listeners; | 
|  | unsigned ListenerCount = 0; | 
|  | }; | 
|  |  | 
|  | } // namespace clangd | 
|  | } // namespace clang | 
|  |  | 
|  | #endif |