From fe12806c6bff17e3c50fb367a8a59e76c0cbb578 Mon Sep 17 00:00:00 2001 From: Gawaboumga Date: Sun, 21 Feb 2016 14:26:10 +0100 Subject: [PATCH] Documentation for Signal Former-commit-id: 8c69830fe9e23ec85ced5f29ce43c96ea26298eb --- include/Nazara/Core/Signal.inl | 179 ++++++++++++++++++++++++++++++++- tests/Engine/Core/Signal.cpp | 48 +++++++++ 2 files changed, 226 insertions(+), 1 deletion(-) create mode 100644 tests/Engine/Core/Signal.cpp diff --git a/include/Nazara/Core/Signal.inl b/include/Nazara/Core/Signal.inl index a635302ec..de1609d78 100644 --- a/include/Nazara/Core/Signal.inl +++ b/include/Nazara/Core/Signal.inl @@ -8,18 +8,37 @@ namespace Nz { + /*! + * \class Nz::Signal + * \brief Core class that represents a signal, a list of objects waiting for its message + */ + + /*! + * \brief Constructs a Signal object by default + */ + template Signal::Signal() : m_slotIterator(0) { } + /*! + * \brief Constructs a Signal object by move semantic + * + * \param signal Signal to move in this + */ + template Signal::Signal(Signal&& signal) { operator=(std::move(signal)); } + /*! + * \brief Clears the list of actions attached to the signal + */ + template void Signal::Clear() { @@ -27,12 +46,26 @@ namespace Nz m_slotIterator = 0; } + /*! + * \brief Connects a function to the signal + * \return Connection attached to the signal + * + * \param func Non-member function + */ + template typename Signal::Connection Signal::Connect(const Callback& func) { return Connect(Callback(func)); } + /*! + * \brief Connects a function to the signal + * \return Connection attached to the signal + * + * \param func Non-member function + */ + template typename Signal::Connection Signal::Connect(Callback&& func) { @@ -54,6 +87,14 @@ namespace Nz return Connection(m_slots.back()); } + /*! + * \brief Connects a member function and its object to the signal + * \return Connection attached to the signal + * + * \param object Object to send the message + * \param method Member function + */ + template template typename Signal::Connection Signal::Connect(O& object, void (O::*method) (Args...)) @@ -64,6 +105,14 @@ namespace Nz }); } + /*! + * \brief Connects a member function and its object to the signal + * \return Connection attached to the signal + * + * \param object Object to send the message + * \param method Member function + */ + template template typename Signal::Connection Signal::Connect(O* object, void (O::*method)(Args...)) @@ -74,6 +123,14 @@ namespace Nz }); } + /*! + * \brief Connects a member function and its object to the signal + * \return Connection attached to the signal + * + * \param object Object to send the message + * \param method Member function + */ + template template typename Signal::Connection Signal::Connect(const O& object, void (O::*method) (Args...) const) @@ -84,6 +141,14 @@ namespace Nz }); } + /*! + * \brief Connects a member function and its object to the signal + * \return Connection attached to the signal + * + * \param object Object to send the message + * \param method Member function + */ + template template typename Signal::Connection Signal::Connect(const O* object, void (O::*method)(Args...) const) @@ -94,6 +159,12 @@ namespace Nz }); } + /*! + * \brief Applies the list of arguments to every callback functions + * + * \param args Arguments to send with the message + */ + template void Signal::operator()(Args... args) const { @@ -101,6 +172,13 @@ namespace Nz m_slots[m_slotIterator]->callback(args...); } + /*! + * \brief Moves the signal into this + * \return A reference to this + * + * \param signal Signal to move in this + */ + template Signal& Signal::operator=(Signal&& signal) { @@ -114,17 +192,28 @@ namespace Nz return *this; } + /*! + * \brief Disconnects a listener from this signal + * + * \param slot Pointer to the ith listener of the signal + * + * \remark Produces a NazaraAssert if slot is invalid (nullptr) + * \remark Produces a NazaraAssert if index of slot is invalid + * \remark Produces a NazaraAssert if slot is not attached to this signal + */ + template void Signal::Disconnect(const SlotPtr& slot) { NazaraAssert(slot, "Invalid slot pointer"); NazaraAssert(slot->index < m_slots.size(), "Invalid slot index"); + NazaraAssert(slot->signal == this, "Slot is not attached to this signal"); // "Swap this slot with the last one and pop" idiom // This will preserve slot indexes // Can we safely "remove" this slot? - if (m_slotIterator >= m_slots.size()-1 || slot->index > m_slotIterator) + if (m_slotIterator >= (m_slots.size() - 1) || slot->index > m_slotIterator) { // Yes we can SlotPtr& newSlot = m_slots[slot->index]; @@ -150,6 +239,16 @@ namespace Nz m_slots.pop_back(); } + /*! + * \class Nz::Signal::Connection + * \brief Core class that represents a connection attached to a signal + */ + + /*! + * \brief Constructs a Signal::Connection object with a slot + * + * \param slot Slot of the listener + */ template Signal::Connection::Connection(const SlotPtr& slot) : @@ -157,6 +256,13 @@ namespace Nz { } + /*! + * \brief Connects to a signal with arguments + * + * \param signal New signal to listen + * \param args Arguments for the signal + */ + template template void Signal::Connection::Connect(BaseClass& signal, ConnectArgs&&... args) @@ -164,6 +270,10 @@ namespace Nz operator=(signal.Connect(std::forward(args)...)); } + /*! + * \brief Disconnects the connection from the signal + */ + template void Signal::Connection::Disconnect() { @@ -171,12 +281,27 @@ namespace Nz ptr->signal->Disconnect(ptr); } + /*! + * \brief Checks whether the connection is still active with the signal + * \return true if signal is still active + */ + template bool Signal::Connection::IsConnected() const { return !m_ptr.expired(); } + /*! + * \class Nz::Signal::ConnectionGuard + * \brief Core class that represents a RAII for a connection attached to a signal + */ + + /*! + * \brief Constructs a Signal::ConnectionGuard object with a connection + * + * \param connection Connection for the scope + */ template Signal::ConnectionGuard::ConnectionGuard(const Connection& connection) : @@ -184,18 +309,35 @@ namespace Nz { } + /*! + * \brief Constructs a Signal::ConnectionGuard object with a connection by move semantic + * + * \param connection Connection for the scope + */ + template Signal::ConnectionGuard::ConnectionGuard(Connection&& connection) : m_connection(std::move(connection)) { } + /*! + * \brief Destructs the object and disconnects the connection + */ + template Signal::ConnectionGuard::~ConnectionGuard() { m_connection.Disconnect(); } + /*! + * \brief Connects to a signal with arguments + * + * \param signal New signal to listen + * \param args Arguments for the signal + */ + template template void Signal::ConnectionGuard::Connect(BaseClass& signal, ConnectArgs&&... args) @@ -204,24 +346,45 @@ namespace Nz m_connection.Connect(signal, std::forward(args)...); } + /*! + * \brief Disconnects the connection from the signal + */ + template void Signal::ConnectionGuard::Disconnect() { m_connection.Disconnect(); } + /*! + * \brief Gets the connection attached to the signal + * \return Connection of the signal + */ + template typename Signal::Connection& Signal::ConnectionGuard::GetConnection() { return m_connection; } + /*! + * \brief Checks whether the connection is still active with the signal + * \return true if signal is still active + */ + template bool Signal::ConnectionGuard::IsConnected() const { return m_connection.IsConnected(); } + /*! + * \brief Assigns the connection into this + * \return A reference to this + * + * \param connection Connection to assign into this + */ + template typename Signal::ConnectionGuard& Signal::ConnectionGuard::operator=(const Connection& connection) { @@ -231,6 +394,13 @@ namespace Nz return *this; } + /*! + * \brief Moves the Connection into this + * \return A reference to this + * + * \param connection Connection to move in this + */ + template typename Signal::ConnectionGuard& Signal::ConnectionGuard::operator=(Connection&& connection) { @@ -240,6 +410,13 @@ namespace Nz return *this; } + /*! + * \brief Moves the ConnectionGuard into this + * \return A reference to this + * + * \param connection ConnectionGuard to move in this + */ + template typename Signal::ConnectionGuard& Signal::ConnectionGuard::operator=(ConnectionGuard&& connection) { diff --git a/tests/Engine/Core/Signal.cpp b/tests/Engine/Core/Signal.cpp new file mode 100644 index 000000000..c5582d866 --- /dev/null +++ b/tests/Engine/Core/Signal.cpp @@ -0,0 +1,48 @@ +#include +#include + +struct Incrementer +{ + void increment(int* inc) + { + *inc += 1; + } +}; + +void increment(int* inc) +{ + *inc += 1; +} + +SCENARIO("Signal", "[CORE][SIGNAL]") +{ + GIVEN("A signal") + { + Nz::Signal signal; + + WHEN("We connection different callbacks") + { + auto connection = signal.Connect(increment); + signal.Connect([](int* inc){ *inc += 1; }); + Incrementer incrementer; + signal.Connect(incrementer, &Incrementer::increment); + + THEN("The call of signal with inc = 0 must return 3") + { + int inc = 0; + signal(&inc); + REQUIRE(inc == 3); + } + + AND_THEN("When we disconnect one function, there should be only two listeners") + { + connection.Disconnect(); + REQUIRE(!connection.IsConnected()); + + int inc = 0; + signal(&inc); + REQUIRE(inc == 2); + } + } + } +}