/* * This file is part of libgim. * * libgim is free software: you can redistribute it and/or modify it under the * terms of the GNU General Public License as published by the Free Software * Foundation, either version 3 of the License, or (at your option) any later * version. * * libgim is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with libgim. If not, see . * * Copyright 2011-2015 Danny Robson */ #ifndef __UTIL_SIGNAL_HPP #error #endif #include "debug.hpp" #include namespace util { /////////////////////////////////////////////////////////////////////////// template class C> 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 class C> signal::cookie::cookie (typename group::iterator _position, signal &_parent): m_position (_position), m_parent (_parent) { ; } //------------------------------------------------------------------------- template class C> signal::cookie::cookie (cookie &&rhs): m_position (rhs.m_position), m_parent (rhs.m_parent) { rhs.m_position = rhs.m_parent.m_children.end (); } //------------------------------------------------------------------------- template class C> signal::cookie::~cookie () { if (m_parent.m_children.end () != m_position) m_parent.disconnect (*this); } /////////////////////////////////////////////////////////////////////////// template class C> void signal::cookie::reset (callback &&cb) { *m_position = std::move (cb); } //------------------------------------------------------------------------- template class C> void signal::cookie::reset (void) { m_position = m_parent.m_children.end (); } /////////////////////////////////////////////////////////////////////////// template class C> signal::signal () { ; } //------------------------------------------------------------------------- template class C> signal::~signal () { CHECK (empty ()); } /////////////////////////////////////////////////////////////////////////// template class C> typename signal::cookie signal::connect (const callback &_cb) { return cookie ( m_children.insert ( m_children.end (), std::move (_cb) ), *this ); } //------------------------------------------------------------------------- template class C> typename signal::cookie signal::connect (callback &&_cb) { return cookie ( m_children.insert ( m_children.end (), std::move (_cb) ), *this ); } //------------------------------------------------------------------------- template class C> void signal::disconnect (cookie &c) { m_children.erase (c.m_position); c.m_position = m_children.end (); } //------------------------------------------------------------------------- /// Disconnect all callbacks template class C> void signal::clear (void) { m_children.clear (); } /////////////////////////////////////////////////////////////////////////// /// Returns the number of callbacks connected. template class C> unsigned int signal::size (void) const { return m_children.size (); } //------------------------------------------------------------------------- template class C> bool signal::empty (void) const { return m_children.empty (); } /////////////////////////////////////////////////////////////////////////// template class C> template typename signal::R signal::operator () (Args&&... tail) { if (m_children.empty ()) return R(); //auto i = m_children.cbegin (); //bool looping; C combiner; return combiner (m_children.begin (), m_children.end (), std::forward (tail)...); //do { // // Increment before we execute so that the caller is able to // // deregister themselves during execution. // auto current = i++; // looping = m_children.cend () != i; // (*current)(std::forward (tail)...); //} while (looping); } /////////////////////////////////////////////////////////////////////////// template value_signal::value_signal (T t): m_value (t) { ; } //------------------------------------------------------------------------- template value_signal::operator const T&() const { return m_value; } //------------------------------------------------------------------------- template value_signal& value_signal::operator= (const T &t) { m_value = t; (*this) (m_value); return *this; } }