#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_FUNCTION_H
#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_SUPPORT_FUNCTION_H
#include "llvm/ADT/FunctionExtras.h"
#include "llvm/Support/Error.h"
#include <mutex>
#include <tuple>
#include <utility>
namespace clang {
namespace clangd {
template <typename T>
using Callback = llvm::unique_function<void(llvm::Expected<T>)>;
template <typename T> class Event {
public:
using Listener = std::function<void(const T &)>;
class [[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 (Parent) {
std::lock_guard<std::recursive_mutex> Lock(Parent->ListenersMu);
llvm::erase_if(Parent->Listeners,
[&](const std::pair<Listener, unsigned> &P) {
return P.second == ListenerID;
});
}
std::tie(Parent, ListenerID) = std::tie(Other.Parent, Other.ListenerID);
Other.Parent = nullptr;
return *this;
}
~Subscription() {
if (Parent)
*this = Subscription();
}
};
Subscription observe(Listener L) {
std::lock_guard<std::recursive_mutex> Lock(ListenersMu);
Listeners.push_back({std::move(L), ++ListenerCount});
return Subscription(this, ListenerCount);
}
void broadcast(const T &V) {
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<std::decay_t<T>, T>::value,
"use a plain type: event values are always passed by const&");
std::recursive_mutex ListenersMu;
std::vector<std::pair<Listener, unsigned>> Listeners;
unsigned ListenerCount = 0;
};
}
}
#endif