#pragma once #include #include #include #include namespace td { namespace utils { /** * \brief Signal class */ template class SignalRaw : private NonCopyable { public: using FnType = void(Args...); using CallBack = std::function; 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_if(m_Callbacks.begin(), m_Callbacks.end(), [&a_Callback](CallBack& callback) { return a_Callback.template target() == callback.template target(); }); m_Callbacks.erase(it); } void operator()(Args... args) const { for (const CallBack& callback : m_Callbacks) { callback(args...); } } }; /** * \brief Memory managed Signal class */ template class Signal { public: using SignalBase = SignalRaw; using CallBack = typename SignalBase::CallBack; using SignalPtr = std::shared_ptr; class ConnectionGuard; private: SignalPtr m_Signal; public: Signal() : m_Signal(std::make_shared()) {} Signal(const Signal&) = default; void Connect(const CallBack& a_Callback) { m_Signal->Connect(a_Callback); } [[nodiscard]] std::unique_ptr ConnectSafe(const CallBack& a_Callback) { 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