// Copyright (C) 2020 Jérôme Leclercq // This file is part of the "Nazara Engine - Core module" // For conditions of distribution and use, see copyright notice in Config.hpp #pragma once #ifndef NAZARA_SIGNAL_HPP #define NAZARA_SIGNAL_HPP #include #include #include #define NazaraDetailSignal(Keyword, SignalName, ...) using SignalName ## Type = Nz::Signal<__VA_ARGS__>; \ Keyword SignalName ## Type SignalName #define NazaraSignal(SignalName, ...) NazaraDetailSignal(mutable, SignalName, __VA_ARGS__) #define NazaraStaticSignal(SignalName, ...) NazaraDetailSignal(static, SignalName, __VA_ARGS__) #define NazaraStaticSignalImpl(Class, SignalName) Class :: SignalName ## Type Class :: SignalName #define NazaraSlotType(Class, SignalName) Class::SignalName ## Type::ConnectionGuard #define NazaraSlot(Class, SignalName, SlotName) NazaraSlotType(Class, SignalName) SlotName namespace Nz { template class Signal { public: using Callback = std::function; class Connection; class ConnectionGuard; Signal(); Signal(const Signal&); Signal(Signal&& signal) noexcept; ~Signal() = default; void Clear(); Connection Connect(const Callback& func); Connection Connect(Callback&& func); template Connection Connect(O& object, void (O::*method)(Args...)); template Connection Connect(O* object, void (O::*method)(Args...)); template Connection Connect(const O& object, void (O::*method)(Args...) const); template Connection Connect(const O* object, void (O::*method)(Args...) const); void operator()(Args... args) const; Signal& operator=(const Signal&); Signal& operator=(Signal&& signal) noexcept; private: struct Slot; using SlotPtr = std::shared_ptr; using SlotList = std::vector; using SlotListIndex = typename SlotList::size_type; struct Slot { Slot(Signal* me) : signal(me) { } Callback callback; Signal* signal; SlotListIndex index; }; void Disconnect(const SlotPtr& slot) noexcept; SlotList m_slots; mutable SlotListIndex m_slotIterator; }; template class Signal::Connection { using BaseClass = Signal; friend BaseClass; public: Connection() = default; Connection(const Connection& connection) = default; Connection(Connection&& connection) noexcept; ~Connection() = default; template void Connect(BaseClass& signal, ConnectArgs&&... args); void Disconnect() noexcept; bool IsConnected() const; Connection& operator=(const Connection& connection) = default; Connection& operator=(Connection&& connection) noexcept; private: Connection(const SlotPtr& slot); std::weak_ptr m_ptr; }; template class Signal::ConnectionGuard { using BaseClass = Signal; using Connection = typename BaseClass::Connection; public: ConnectionGuard() = default; ConnectionGuard(const Connection& connection); ConnectionGuard(const ConnectionGuard& connection) = delete; ConnectionGuard(Connection&& connection); ConnectionGuard(ConnectionGuard&& connection) noexcept = default; ~ConnectionGuard(); template void Connect(BaseClass& signal, ConnectArgs&&... args); void Disconnect() noexcept; Connection& GetConnection(); bool IsConnected() const; ConnectionGuard& operator=(const Connection& connection); ConnectionGuard& operator=(const ConnectionGuard& connection) = delete; ConnectionGuard& operator=(Connection&& connection); ConnectionGuard& operator=(ConnectionGuard&& connection) noexcept; private: Connection m_connection; }; } #include #endif // NAZARA_SIGNAL_HPP