/* CONTROL-IMPL.hpp - time::control implementation building blocks Copyright (C) Lumiera.org 2011, Hermann Vosseler This program 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 2 of the License, or (at your option) any later version. This program 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 this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file control-impl.hpp ** Implementation building blocks for time modification and propagation. ** The time::Control element allows to impose modifications to a connected ** time value entity and at the same time publish the changes to registered ** listeners. Due to the various flavours of actual time value entities, this ** is a complex undertaking, which is implemented here based on policies and ** template metaprogramming. This header/include defines two building blocks: ** - the actual Mutator to apply the changes to the target entity ** - a Propagator to register listeners and forward the changes. ** ** # implementation technique ** ** The Mutator uses functor objects to encapsulate the actual modification ** operations. When attaching to a target time entity to be manipulated, these ** functor objects will be configured by binding them to the appropriate ** implementation function. And picking this actual implementation is done ** through a time::mutation::Policy element, using the concrete time entity ** types as template parameter. Thus, the actual implementation to be used ** is determined by the compiler, through the template specialisations ** contained in control-policy.hpp ** ** @note the header control-policy.hpp with the template specialisations ** is included way down, after the class definitions. This is done ** so for sake of readability ** ** @see TimeControl_test ** */ #ifndef LIB_TIME_CONTROL_IMPL_H #define LIB_TIME_CONTROL_IMPL_H #include "lib/error.hpp" #include "lib/time/mutation.hpp" #include "lib/time/timevalue.hpp" #include #include namespace lib { namespace time { namespace mutation { using std::function; /** * Implementation building block: impose changes to a Time element. * The purpose of the Mutator is to attach a target time entity, * which then will be subject to any received value changes, * offsets and grid nudging. The actual attachment is to be * performed in a subclass, by using the Mutation interface. * When attaching to a target, the Mutator will be outfitted * with a set of suitable functors, incorporating the specific * behaviour for the concrete combination of input changes * ("source values") and target object type. This works by * binding to the appropriate implementation functionality, * guided by a templated policy class. After installing * these functors, these decisions remains opaque and * encapsulated within the functor objects, so the * mutator object doesn't need to carry this * type information on the interface */ template class Mutator : public Mutation { typedef function ValueSetter; typedef function Ofsetter; typedef function Nudger; protected: mutable ValueSetter setVal_; mutable Ofsetter offset_; mutable Nudger nudge_; void ensure_isArmed() const { if (!setVal_) throw error::State("feeding time/value change " "while not (yet) connected to any target to change" ,error::LUMIERA_ERROR_UNCONNECTED); } template void bind_to (TAR& target) const; void unbind(); // using default construction and copy }; /** * Implementation building block: propagate changes to listeners. * The Propagator manages a set of callback signals, allowing to * propagate notifications for changed Time values. * * There are no specific requirements on the acceptable listeners, * besides exposing a function-call operator to feed the changed * time value to. Both Mutator and Propagator employ one primary * template parameter, which is the type of the time values * to be fed in and propagated. */ template class Propagator { typedef function ChangeSignal; typedef std::vector ListenerList; ListenerList listeners_; public: /** install notification receiver */ template void attach (SIG const& toNotify) { ChangeSignal newListener (std::ref(toNotify)); listeners_.push_back (newListener); } /** disconnect any observers */ void disconnect() { listeners_.clear(); } /** publish a change */ TI operator() (TI const& changedVal) const { typedef typename ListenerList::const_iterator Iter; Iter p = listeners_.begin(); Iter e = listeners_.end(); for ( ; p!=e; ++p ) (*p) (changedVal); return changedVal; } // using default construction and copy }; }}} // lib::time::mutation /* ===== Definition of actual operations ===== */ #include "lib/time/control-policy.hpp" template template void lib::time::mutation::Mutator::bind_to (TAR& target) const { using lib::time::mutation::Policy; setVal_ = Policy::buildChangeHandler (target); offset_ = Policy::buildChangeHandler (target); nudge_ = Policy::buildChangeHandler (target); } template void lib::time::mutation::Mutator::unbind() { setVal_ = ValueSetter(); offset_ = Ofsetter(); nudge_ = Nudger(); } #endif