diff --git a/signal.cpp b/signal.cpp index 3eed439f..f29fd2a8 100644 --- a/signal.cpp +++ b/signal.cpp @@ -21,4 +21,4 @@ #include "signal.hpp" // Instance something probably useful here so that we generate early compile/link errors. -template class util::signal ; +template class util::signal ; diff --git a/signal.hpp b/signal.hpp index f25355fc..881492c9 100644 --- a/signal.hpp +++ b/signal.hpp @@ -14,52 +14,36 @@ * You should have received a copy of the GNU General Public License * along with libgim. If not, see . * - * Copyright 2011-2013 Danny Robson + * Copyright 2011-2015 Danny Robson */ #ifndef __UTIL_SIGNAL_HPP #define __UTIL_SIGNAL_HPP -#include "debug.hpp" #include "nocopy.hpp" -#include -#include #include +#include +#include namespace util { - template + template class signal { public: - //typedef Ret (*callback_function)(Args...); - typedef std::function callback_object; + using R = std::result_of; + using callback = std::function; - protected: - typedef std::list group; - group m_children; - - public: - typedef typename group::iterator cookie; - struct scoped_cookie : public nocopy { - cookie m_cookie; - signal& m_parent; - - scoped_cookie (cookie _cookie, signal &_parent); - scoped_cookie (scoped_cookie &&rhs); - ~scoped_cookie (); - - void renew (callback_object &&cb); - void release (void); - }; + struct cookie; public: signal (); + ~signal (); /// Add a callback to list. - cookie connect (const callback_object &_cb); - scoped_cookie scoped_connect (const callback_object &_cb); + cookie connect (const callback&); + + void disconnect (const cookie&); - void disconnect (const cookie _cb); /// Disconnect all callbacks void clear (void); @@ -67,8 +51,14 @@ namespace util { unsigned int size (void) const; bool empty (void) const; - /// Execute all callbacks, ignoring the return parameters. Does not combine results. - void operator () (Args... tail); + /// Execute all callbacks, ignoring the return parameters. Does + /// not combine results. + template + void operator () (Args&&... tail); + + private: + typedef std::list group; + group m_children; }; } diff --git a/signal.ipp b/signal.ipp index d1d701b2..e1b4bfae 100644 --- a/signal.ipp +++ b/signal.ipp @@ -14,102 +14,144 @@ * You should have received a copy of the GNU General Public License * along with libgim. If not, see . * - * Copyright 2011-2013 Danny Robson + * Copyright 2011-2015 Danny Robson */ #ifndef __UTIL_SIGNAL_HPP #error #endif +#include "debug.hpp" + +#include + namespace util { - template - signal::scoped_cookie::scoped_cookie (cookie _cookie, - signal &_parent): - m_cookie (_cookie), + /////////////////////////////////////////////////////////////////////////// + template + struct signal::cookie : public nocopy { + cookie (typename group::iterator, signal &parent); + cookie (cookie &&rhs); + ~cookie (); + + void reset (callback &&cb); + void reset (void); + + typename group::iterator m_position; + signal &m_parent; + }; + + + /////////////////////////////////////////////////////////////////////////// + template + signal::cookie::cookie (typename group::iterator _position, + signal &_parent): + m_position (_position), m_parent (_parent) { ; } - template - signal::scoped_cookie::scoped_cookie (scoped_cookie &&rhs): - m_cookie (rhs.m_cookie), + //------------------------------------------------------------------------- + template + signal::cookie::cookie (cookie &&rhs): + m_position (rhs.m_position), m_parent (rhs.m_parent) { - rhs.m_cookie = rhs.m_parent.m_children.end (); + rhs.m_position = rhs.m_parent.m_children.end (); } - template - signal::scoped_cookie::~scoped_cookie () { - if (m_parent.m_children.end () != m_cookie) - m_parent.disconnect (m_cookie); + //------------------------------------------------------------------------- + template + signal::cookie::~cookie () + { + if (m_parent.m_children.end () != m_position) + m_parent.disconnect (*this); } - template + /////////////////////////////////////////////////////////////////////////// + template void - signal::scoped_cookie::renew (callback_object &&cb) - { *m_cookie = std::move (cb); } + signal::cookie::reset (callback &&cb) + { + *m_position = std::move (cb); + } - template + //------------------------------------------------------------------------- + template void - signal::scoped_cookie::release (void) - { m_cookie = m_parent.m_children.end (); } + signal::cookie::reset (void) + { + m_position = m_parent.m_children.end (); + } - template - signal::signal () + /////////////////////////////////////////////////////////////////////////// + template + signal::signal () { ; } - template - typename signal::cookie - signal::connect (const callback_object &_cb) - { return m_children.insert (m_children.end (), _cb); } + //------------------------------------------------------------------------- + template + signal::~signal () + { + CHECK (empty ()); + } + + /////////////////////////////////////////////////////////////////////////// + template + typename signal::cookie + signal::connect (const callback &_cb) + { + return cookie (m_children.insert (m_children.end (), _cb), *this); + } - template - typename signal::scoped_cookie - signal::scoped_connect (const callback_object &_cb) - { return scoped_cookie (connect (_cb), *this); } - - - /// Add a callback to the list. - //const cookie - //connect (const callback_function &_cb) - // { return m_children.insert (m_children.end (), _cb); } - - - template + //------------------------------------------------------------------------- + template void - signal::disconnect (const cookie _cb) - { m_children.erase (_cb); } + signal::disconnect (const cookie &c) + { + m_children.erase (c.m_position); + } + //------------------------------------------------------------------------- /// Disconnect all callbacks - template + template void - signal::clear (void) - { m_children.clear (); } + signal::clear (void) + { + m_children.clear (); + } + /////////////////////////////////////////////////////////////////////////// /// Returns the number of callbacks connected. - template + template unsigned int - signal::size (void) const - { return m_children.size (); } + signal::size (void) const + { + return m_children.size (); + } - template + //------------------------------------------------------------------------- + template bool - signal::empty (void) const - { return m_children.empty (); } + signal::empty (void) const + { + return m_children.empty (); + } - template + /////////////////////////////////////////////////////////////////////////// + template + template void - signal::operator () (Args... tail) { + signal::operator () (Args&&... tail) { if (m_children.empty ()) return; @@ -117,11 +159,12 @@ namespace util { bool looping; do { - // Increment before we execute so that the caller is able to deregister during execution. + // Increment before we execute so that the caller is able to + // deregister during execution. auto current = i++; looping = m_children.cend () != i; - (*current)(tail...); + (*current)(std::forward (tail)...); } while (looping); } } diff --git a/test/signal.cpp b/test/signal.cpp index cabc8512..e3adad33 100644 --- a/test/signal.cpp +++ b/test/signal.cpp @@ -1,54 +1,69 @@ #include -#include "../signal.hpp" -#include "../debug.hpp" +#include "signal.hpp" +#include "debug.hpp" +#include "raii.hpp" + +//----------------------------------------------------------------------------- void -increment_uint (unsigned int &val) - { ++val; } - - -void -test_null (void) { - util::signal void_signal; +test_null (void) +{ + util::signal void_signal; void_signal (); } +/////////////////////////////////////////////////////////////////////////////// void -test_single (void) { - unsigned int val = 0; - util::signal void_signal; +increment_uint (unsigned int &val) +{ + ++val; +} - void_signal.connect (increment_uint); + +//----------------------------------------------------------------------------- +void +test_single (void) +{ + unsigned int val = 0; + util::signal void_signal; + + auto raii = void_signal.connect (increment_uint); void_signal (val); CHECK_EQ (val, 1); } +//----------------------------------------------------------------------------- void -test_double (void) { +test_double (void) +{ unsigned int val = 0; - util::signal void_signal; + util::signal void_signal; - void_signal.connect (increment_uint); - void_signal.connect (increment_uint); + auto raii = void_signal.connect (increment_uint); + auto raii = void_signal.connect (increment_uint); void_signal (val); CHECK_EQ (val, 2); } +/////////////////////////////////////////////////////////////////////////////// void -test_linking_pointers (void) { - util::signal ptr_signal; - ptr_signal (NULL); +test_linking_pointers (void) +{ + util::signal ptr_signal; + ptr_signal (nullptr); } +/////////////////////////////////////////////////////////////////////////////// int -main (int, char **) { +main (int, char **) +{ test_null (); test_single (); test_double ();