#pragma once #include #include #include #include #include namespace td { namespace utils { /** * \brief Signal class */ template class SignalRaw : private NonCopyable { public: using FnType = void(Args...); using CallBack = std::shared_ptr>; private: std::vector 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 class Signal { public: using SignalBase = SignalRaw; using CallBack = typename SignalBase::CallBack; using CallBackRaw = typename CallBack::element_type; using SignalPtr = std::shared_ptr; class ConnectionGuard; private: SignalPtr m_Signal; public: Signal() : m_Signal(std::make_shared()) {} 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(a_Callback)); } [[nodiscard]] std::unique_ptr ConnectSafe(const CallBack& a_Callback) { m_Signal->Connect(a_Callback); return std::make_unique(*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 class Signal::ConnectionGuard : public Connection { private: using CallBack = typename Signal::CallBack; std::weak_ptr> m_Signal; CallBack m_Callback; public: ConnectionGuard(const Signal& 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