/* * 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 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::cookie::cookie (cookie &&rhs): m_position (rhs.m_position), m_parent (rhs.m_parent) { rhs.m_position = rhs.m_parent.m_children.end (); } //------------------------------------------------------------------------- template signal::cookie::~cookie () { if (m_parent.m_children.end () != m_position) m_parent.disconnect (*this); } /////////////////////////////////////////////////////////////////////////// template void signal::cookie::reset (callback &&cb) { *m_position = std::move (cb); } //------------------------------------------------------------------------- template void signal::cookie::reset (void) { m_position = m_parent.m_children.end (); } /////////////////////////////////////////////////////////////////////////// template signal::signal () { ; } //------------------------------------------------------------------------- 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 void signal::disconnect (const cookie &c) { m_children.erase (c.m_position); } //------------------------------------------------------------------------- /// Disconnect all callbacks template void signal::clear (void) { m_children.clear (); } /////////////////////////////////////////////////////////////////////////// /// Returns the number of callbacks connected. template unsigned int signal::size (void) const { return m_children.size (); } //------------------------------------------------------------------------- template bool signal::empty (void) const { return m_children.empty (); } /////////////////////////////////////////////////////////////////////////// template template void signal::operator () (Args&&... tail) { if (m_children.empty ()) return; auto i = m_children.cbegin (); bool looping; do { // Increment before we execute so that the caller is able to // deregister 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 (std::forward (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; } }