Documentation for Signal

Former-commit-id: 8c69830fe9e23ec85ced5f29ce43c96ea26298eb
This commit is contained in:
Gawaboumga 2016-02-21 14:26:10 +01:00
parent 1d5518b0d3
commit fe12806c6b
2 changed files with 226 additions and 1 deletions

View File

@ -8,18 +8,37 @@
namespace Nz
{
/*!
* \class Nz::Signal<Args...>
* \brief Core class that represents a signal, a list of objects waiting for its message
*/
/*!
* \brief Constructs a Signal<Args...> object by default
*/
template<typename... Args>
Signal<Args...>::Signal() :
m_slotIterator(0)
{
}
/*!
* \brief Constructs a Signal<Args...> object by move semantic
*
* \param signal Signal to move in this
*/
template<typename... Args>
Signal<Args...>::Signal(Signal&& signal)
{
operator=(std::move(signal));
}
/*!
* \brief Clears the list of actions attached to the signal
*/
template<typename... Args>
void Signal<Args...>::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... Args>
typename Signal<Args...>::Connection Signal<Args...>::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... Args>
typename Signal<Args...>::Connection Signal<Args...>::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<typename... Args>
template<typename O>
typename Signal<Args...>::Connection Signal<Args...>::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<typename... Args>
template<typename O>
typename Signal<Args...>::Connection Signal<Args...>::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<typename... Args>
template<typename O>
typename Signal<Args...>::Connection Signal<Args...>::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<typename... Args>
template<typename O>
typename Signal<Args...>::Connection Signal<Args...>::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<typename... Args>
void Signal<Args...>::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<typename... Args>
Signal<Args...>& Signal<Args...>::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<typename... Args>
void Signal<Args...>::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<Args...>::Connection
* \brief Core class that represents a connection attached to a signal
*/
/*!
* \brief Constructs a Signal<Args...>::Connection object with a slot
*
* \param slot Slot of the listener
*/
template<typename... Args>
Signal<Args...>::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<typename... Args>
template<typename... ConnectArgs>
void Signal<Args...>::Connection::Connect(BaseClass& signal, ConnectArgs&&... args)
@ -164,6 +270,10 @@ namespace Nz
operator=(signal.Connect(std::forward<ConnectArgs>(args)...));
}
/*!
* \brief Disconnects the connection from the signal
*/
template<typename... Args>
void Signal<Args...>::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<typename... Args>
bool Signal<Args...>::Connection::IsConnected() const
{
return !m_ptr.expired();
}
/*!
* \class Nz::Signal<Args...>::ConnectionGuard
* \brief Core class that represents a RAII for a connection attached to a signal
*/
/*!
* \brief Constructs a Signal<Args...>::ConnectionGuard object with a connection
*
* \param connection Connection for the scope
*/
template<typename... Args>
Signal<Args...>::ConnectionGuard::ConnectionGuard(const Connection& connection) :
@ -184,18 +309,35 @@ namespace Nz
{
}
/*!
* \brief Constructs a Signal<Args...>::ConnectionGuard object with a connection by move semantic
*
* \param connection Connection for the scope
*/
template<typename... Args>
Signal<Args...>::ConnectionGuard::ConnectionGuard(Connection&& connection) :
m_connection(std::move(connection))
{
}
/*!
* \brief Destructs the object and disconnects the connection
*/
template<typename... Args>
Signal<Args...>::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<typename... Args>
template<typename... ConnectArgs>
void Signal<Args...>::ConnectionGuard::Connect(BaseClass& signal, ConnectArgs&&... args)
@ -204,24 +346,45 @@ namespace Nz
m_connection.Connect(signal, std::forward<ConnectArgs>(args)...);
}
/*!
* \brief Disconnects the connection from the signal
*/
template<typename... Args>
void Signal<Args...>::ConnectionGuard::Disconnect()
{
m_connection.Disconnect();
}
/*!
* \brief Gets the connection attached to the signal
* \return Connection of the signal
*/
template<typename... Args>
typename Signal<Args...>::Connection& Signal<Args...>::ConnectionGuard::GetConnection()
{
return m_connection;
}
/*!
* \brief Checks whether the connection is still active with the signal
* \return true if signal is still active
*/
template<typename... Args>
bool Signal<Args...>::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... Args>
typename Signal<Args...>::ConnectionGuard& Signal<Args...>::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... Args>
typename Signal<Args...>::ConnectionGuard& Signal<Args...>::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... Args>
typename Signal<Args...>::ConnectionGuard& Signal<Args...>::ConnectionGuard::operator=(ConnectionGuard&& connection)
{

View File

@ -0,0 +1,48 @@
#include <Nazara/Core/Signal.hpp>
#include <Catch/catch.hpp>
struct Incrementer
{
void increment(int* inc)
{
*inc += 1;
}
};
void increment(int* inc)
{
*inc += 1;
}
SCENARIO("Signal", "[CORE][SIGNAL]")
{
GIVEN("A signal")
{
Nz::Signal<int*> 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);
}
}
}
}