106 lines
2.3 KiB
C++
106 lines
2.3 KiB
C++
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <functional>
|
|
#include <memory>
|
|
#include <td/common/NonCopyable.h>
|
|
#include <vector>
|
|
|
|
namespace td {
|
|
namespace utils {
|
|
|
|
/**
|
|
* \brief Signal class
|
|
*/
|
|
template <typename... Args>
|
|
class SignalRaw : private NonCopyable {
|
|
public:
|
|
using FnType = void(Args...);
|
|
using CallBack = std::shared_ptr<std::function<FnType>>;
|
|
|
|
private:
|
|
std::vector<CallBack> m_Callbacks;
|
|
|
|
public:
|
|
void Connect(const CallBack& a_Callback) {
|
|
m_Callbacks.push_back(a_Callback);
|
|
}
|
|
|
|
void Disconnect(const CallBack& a_Callback) {
|
|
auto it = std::find(m_Callbacks.begin(), m_Callbacks.end(), a_Callback);
|
|
m_Callbacks.erase(it);
|
|
}
|
|
|
|
void operator()(Args... args) const {
|
|
for (const CallBack& callback : m_Callbacks) {
|
|
callback->operator()(args...);
|
|
}
|
|
}
|
|
};
|
|
|
|
/**
|
|
* \brief Memory managed Signal class
|
|
*/
|
|
template <typename... Args>
|
|
class Signal {
|
|
public:
|
|
using SignalBase = SignalRaw<Args...>;
|
|
using CallBack = typename SignalBase::CallBack;
|
|
using CallBackRaw = typename CallBack::element_type;
|
|
using SignalPtr = std::shared_ptr<SignalBase>;
|
|
class ConnectionGuard;
|
|
|
|
private:
|
|
SignalPtr m_Signal;
|
|
|
|
public:
|
|
Signal() : m_Signal(std::make_shared<SignalBase>()) {}
|
|
Signal(const Signal&) = default;
|
|
|
|
/**
|
|
* \warning The callback won't be disconnectable, use it wisely!
|
|
*/
|
|
void Connect(const CallBackRaw& a_Callback) {
|
|
m_Signal->Connect(std::make_shared<CallBackRaw>(a_Callback));
|
|
}
|
|
|
|
[[nodiscard]] std::unique_ptr<ConnectionGuard> ConnectSafe(const CallBack& a_Callback) {
|
|
m_Signal->Connect(a_Callback);
|
|
return std::make_unique<ConnectionGuard>(*this, a_Callback);
|
|
}
|
|
|
|
void Disconnect(const CallBack& a_Callback) {
|
|
m_Signal->Disconnect(a_Callback);
|
|
}
|
|
|
|
void operator()(Args... args) const {
|
|
m_Signal->operator()(args...);
|
|
}
|
|
};
|
|
|
|
class Connection {
|
|
public:
|
|
virtual ~Connection() {}
|
|
};
|
|
|
|
template <typename... Args>
|
|
class Signal<Args...>::ConnectionGuard : public Connection {
|
|
private:
|
|
using CallBack = typename Signal<Args...>::CallBack;
|
|
|
|
std::weak_ptr<SignalRaw<Args...>> m_Signal;
|
|
CallBack m_Callback;
|
|
|
|
public:
|
|
ConnectionGuard(const Signal<Args...>& a_Signal, const CallBack& a_Callback) :
|
|
m_Signal(a_Signal.m_Signal), m_Callback(a_Callback) {}
|
|
|
|
~ConnectionGuard() {
|
|
if (!m_Signal.expired())
|
|
m_Signal.lock()->Disconnect(m_Callback);
|
|
}
|
|
};
|
|
|
|
} // namespace utils
|
|
} // namespace td
|