diff --git a/src/include/play-facade.h b/src/include/play-facade.h index 33429323b..bc8fa26e9 100644 --- a/src/include/play-facade.h +++ b/src/include/play-facade.h @@ -45,11 +45,11 @@ -namespace proc { - namespace play { - - class PlayProcess; -} } +namespace proc { +namespace play { + + class PlayProcess; +}} namespace lumiera { diff --git a/src/lib/access-casted.hpp b/src/lib/access-casted.hpp index 9f51110f8..a54aec853 100644 --- a/src/lib/access-casted.hpp +++ b/src/lib/access-casted.hpp @@ -34,6 +34,7 @@ ** e.g. throwing an exception instead of creating a NULL value. ** ** @see lumiera::WrapperPtr usage example to access a variant record + ** @see lib::InPlaceAnyHolder usage example to access a subclass in embedded storage ** */ diff --git a/src/lib/meta/function-erasure.hpp b/src/lib/meta/function-erasure.hpp index 6e04effc2..40acfa46c 100644 --- a/src/lib/meta/function-erasure.hpp +++ b/src/lib/meta/function-erasure.hpp @@ -22,6 +22,7 @@ /** @file function-erasure.hpp + ** Generic holder for functor objects, concealing the concrete function type. ** When working with generic function objects and function pointers typed to ** arbitrary signatures, often there is the necessity to hold onto such a functor ** while hiding the actual signature behind an common interface ("type erasure"). diff --git a/src/lib/opaque-holder.hpp b/src/lib/opaque-holder.hpp index 3cc52a607..646c24b45 100644 --- a/src/lib/opaque-holder.hpp +++ b/src/lib/opaque-holder.hpp @@ -219,7 +219,7 @@ namespace lib { char content_[siz]; void* ptr() { return &content_; } - virtual ~Buffer() {} + virtual ~Buffer() {} ///< this is an ABC with VTable virtual bool isValid() const =0; virtual bool empty() const =0; virtual BaseP getBase() const =0; diff --git a/src/lib/time/control.hpp b/src/lib/time/control.hpp index 87bd271f2..26c827d7e 100644 --- a/src/lib/time/control.hpp +++ b/src/lib/time/control.hpp @@ -60,12 +60,14 @@ #include "lib/error.hpp" #include "lib/time/mutation.hpp" +#include "lib/time/timevalue.hpp" //#include "lib/symbol.hpp" //#include //#include //#include #include +#include //#include @@ -75,13 +77,192 @@ namespace time { //using lib::Symbol; //using std::string; //using lib::Literal; - using std::tr1::function; + //LUMIERA_ERROR_DECLARE (INVALID_MUTATION); ///< Changing a time value in this way was not designated + namespace mutation { + + using std::tr1::placeholders::_1; + using std::tr1::function; + using std::tr1::bind; + using std::tr1::ref; + + + + /** + * Implementation building block: impose changes to a Time element. + * The Mutator supports attaching a target time entity (through + * the Mutation interface), which then will be subject to any + * received value changes, offsets and grid nudging. + * + * @todo WIP-WIP-WIP + */ + template + class Mutator + : public Mutation + { + typedef function ValueSetter; + typedef function Ofsetter; + typedef function Nudger; + + static TI imposeValueChange(TimeValue& target, TI const&); + static TI imposeOffset (TimeValue& target, Offset const&); + static TI imposeNudge (TimeValue& target, int); + + template + struct MutationPolicy; + + protected: + mutable ValueSetter setVal_; + mutable Ofsetter offset_; + mutable Nudger nudge_; + + void + ensure_isArmed() + { + if (!setVal_) + throw error::State("feeding time/value change " + "while not (yet) connected to any target to change" + ,error::LUMIERA_ERROR_UNCONNECTED); + } + + public: + // using default construction and copy + + template + void bind_to (TAR& target) const; + + void unbind(); + + }; + + + template + TI + Mutator::imposeValueChange (TimeValue& target, TI const& newVal) + { + return TI (Mutation::imposeChange (target,newVal)); + } + template + TI + Mutator::imposeOffset (TimeValue& target, Offset const& off) + { + return TI (Mutation::imposeChange (target, TimeVar(target)+off)); + } + template + TI + Mutator::imposeNudge (TimeValue& target, int off_by_steps) + { + return TI (Mutation::imposeChange (target, TimeVar(target)+Time(FSecs(off_by_steps)))); + } + + + template + template + struct Mutator::MutationPolicy + { + static function + buildChangeHandler (TAR& target) + { + return bind (Mutator::imposeValueChange, ref(target), _1 ); + } + }; + + template + template + struct Mutator::MutationPolicy + { + static function + buildChangeHandler (TAR& target) + { + return bind (Mutator::imposeOffset, ref(target), _1 ); + } + }; + + template + template + struct Mutator::MutationPolicy + { + static function + buildChangeHandler (TAR& target) + { + return bind (Mutator::imposeNudge, ref(target), _1 ); + } + }; + + + template + template + void + Mutator::bind_to (TAR& target) const + { + setVal_ = MutationPolicy ::buildChangeHandler (target); + offset_ = MutationPolicy::buildChangeHandler (target); + nudge_ = MutationPolicy ::buildChangeHandler (target); + } + + template + void + Mutator::unbind() + { + setVal_ = ValueSetter(); + offset_ = Ofsetter(); + nudge_ = Nudger(); + } + + + + /** + * Implementation building block: propagate changes to listeners. + * The Propagator manages a set of callback signals, allowing to + * propagate notifications for changed Time values. + * + * @todo WIP-WIP-WIP + */ + template + class Propagator + { + typedef function ChangeSignal; + typedef std::vector ListenerList; + + ListenerList listeners_; + + public: + /** install notification receiver */ + template + void + attach (SIG const& toNotify) + { + ChangeSignal newListener (ref(toNotify)); + listeners_.push_back (newListener); + } + + /** disconnect any observers */ + void + disconnnect() + { + 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; + } + }; + } + /** - * Interface: controller-element for retrieving and + * Frontend/Interface: controller-element for retrieving and * changing running time values * * @see time::Mutation @@ -90,28 +271,100 @@ namespace time { */ template class Control - : public Mutation + : public mutation::Mutator { - public: - typedef function TimeSignal; + mutation::Propagator notifyListeners_; + virtual void change (Duration&) const; + virtual void change (TimeSpan&) const; + virtual void change (QuTime&) const; + + public: void operator() (TI const&); void operator() (Offset const&); - void operator() (uint); + void operator() (int); - /** install a callback functor to be invoked - * to notify for any changes to the observed - * time entity */ - void connectChangeNotification (TimeSignal const&); + + /** install a callback functor to be invoked as notification + * for any changes imposed onto the observed time entity. + * @param toNotify object with \c operator()(TI const&) */ + template + void connectChangeNotification (SIG const& toNotify); /** disconnect from observed entity and * cease any change notification */ void disconnnect(); - }; + /* === implementation === */ + + template + void + Control::operator () (TI const& newValue) + { + this->ensure_isArmed(); + notifyListeners_( + this->setVal_(newValue)); + } + + template + void + Control::operator () (Offset const& adjustment) + { + this->ensure_isArmed(); + notifyListeners_( + this->offset_(adjustment)); + } + + template + void + Control::operator () (int offset_by_steps) + { + this->ensure_isArmed(); + notifyListeners_( + this->nudge_(offset_by_steps)); + } + + + template + void + Control::disconnnect() + { + notifyListeners_.disconnect(); + this->unbind(); + } + + template + template + void + Control::connectChangeNotification (SIG const& toNotify) + { + notifyListeners_.attach (toNotify); + } + + template + void + Control::change (Duration& targetDuration) const + { + this->bind_to (targetDuration); + } + + template + void + Control::change (TimeSpan& targetInterval) const + { + this->bind_to (targetInterval); + } + + template + void + Control::change (QuTime& targetQuTime) const + { + this->bind_to (targetQuTime); + } + }} // lib::time #endif diff --git a/src/lib/time/mutation.cpp b/src/lib/time/mutation.cpp index cd2b205c3..d96c96419 100644 --- a/src/lib/time/mutation.cpp +++ b/src/lib/time/mutation.cpp @@ -54,10 +54,10 @@ namespace time { * and thus is allowed to influence the basic * value stored in each time entity */ - void + TimeValue& Mutation::imposeChange (TimeValue& target, TimeValue const& valueToSet) { - target = valueToSet; + return target = valueToSet; } diff --git a/src/lib/time/mutation.hpp b/src/lib/time/mutation.hpp index b05fcaacc..bbd3f9fe9 100644 --- a/src/lib/time/mutation.hpp +++ b/src/lib/time/mutation.hpp @@ -112,7 +112,7 @@ namespace time { static EncapsulatedMutation nudge (int adjustment, Symbol gridID); protected: - static void imposeChange (TimeValue&, TimeValue const&); + static TimeValue& imposeChange (TimeValue&, TimeValue const&); }; diff --git a/tests/lib/time/time-control-test.cpp b/tests/lib/time/time-control-test.cpp index 5b4784835..356139872 100644 --- a/tests/lib/time/time-control-test.cpp +++ b/tests/lib/time/time-control-test.cpp @@ -76,11 +76,12 @@ namespace test{ class TestListener : boost::noncopyable { + mutable ScopedHolder received_; public: void - operator() (TI const& changeValue) + operator() (TI const& changeValue) const { received_.clear(); received_.create (changeValue);