Documentation for Signal
Former-commit-id: 8c69830fe9e23ec85ced5f29ce43c96ea26298eb
This commit is contained in:
parent
1d5518b0d3
commit
fe12806c6b
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue