diff --git a/src/lib/time/digxel.hpp b/src/lib/time/digxel.hpp index 95814bd37..53aac3456 100644 --- a/src/lib/time/digxel.hpp +++ b/src/lib/time/digxel.hpp @@ -195,6 +195,11 @@ namespace time { + using std::tr1::bind; + using std::tr1::function; + using std::tr1::placeholders::_1; + + /** * A number element for building structured numeric displays. * The purpose is to represent parts of a numeric format, like @@ -224,23 +229,35 @@ namespace time { FMT buffer_; NUM value_; - static NUM use_newValue_as_is (NUM n) { return n; } - typedef std::tr1::function _Mutator; + typedef Digxel _Digxel; + typedef function _Mutator; + + _Mutator mutator; ///< Functor for setting a new digxel value + public: - /** a functor to be applied on any new digxel value. + /** install an external functor to be applied on any new digxel value. * This allows individual instances to limit the possible digxel values, * or to update an compound value (e.g. a time comprised of hour, minute - * and second digxel elements). By default, new values can be set without - * any restrictions or side effects. + * and second digxel elements). The installed functor needs to accept + * a "this" pointer and actually perform any desired state change + * as sideeffect. The default is to accept any value as-is. + * @warning using a mutator creates significant overhead; + * measurements indicate a factor of 4 + * @see Digxel_test */ - _Mutator mutator; + template + void + installMutator (FUN mutate, THIS& self) + { + mutator = bind (mutate, &self, _1 ); + } Digxel () : buffer_() , value_ () - , mutator(use_newValue_as_is) + , mutator() { } // using the standard copy operations @@ -262,8 +279,10 @@ namespace time { operator= (NUM n) { if (n == value_) return; - NUM changedValue = mutator(n); - this->setValueRaw (changedValue); + if (mutator) + mutator (n); + else + setValueRaw (n); } void @@ -305,24 +324,22 @@ namespace time { class Signum : public Digxel { - static int - just_the_sign (int val) + typedef Digxel _Par; + + void + storeSign (int val) { - return val<0? -1:+1; + setValueRaw (val<0? -1:+1); } public: Signum() { setValueRaw(1); - mutator = just_the_sign; + installMutator (&Signum::storeSign, *this); } - void - operator= (int n) - { - this->setValueRaw (mutator(n)); - } + using _Par::operator=; friend int operator*= (Signum& s, int c) { s = c*s; return s; } }; diff --git a/src/lib/time/timecode.cpp b/src/lib/time/timecode.cpp index 7b33f6521..8774d9f1a 100644 --- a/src/lib/time/timecode.cpp +++ b/src/lib/time/timecode.cpp @@ -221,10 +221,10 @@ namespace time { inline void setupComponentNormalisation (SmpteTC * thisTC) { - thisTC->hours.mutator = bind (wrapHours, thisTC, _1 ); - thisTC->mins.mutator = bind (wrapMinutes, thisTC, _1 ); - thisTC->secs.mutator = bind (wrapSeconds, thisTC, _1 ); - thisTC->frames.mutator = bind (wrapFrames, thisTC, _1 ); +// thisTC->hours.mutator = bind (wrapHours, thisTC, _1 ); +// thisTC->mins.mutator = bind (wrapMinutes, thisTC, _1 ); +// thisTC->secs.mutator = bind (wrapSeconds, thisTC, _1 ); +// thisTC->frames.mutator = bind (wrapFrames, thisTC, _1 ); } }//(End)implementation details diff --git a/tests/40components.tests b/tests/40components.tests index 2b426a360..b22c6025d 100644 --- a/tests/40components.tests +++ b/tests/40components.tests @@ -234,8 +234,7 @@ END TEST "A Digxel (numeric component)" Digxel_test < #include +#include +#include using lumiera::error::LUMIERA_ERROR_ASSERTION; using util::isSameObject; @@ -66,35 +67,6 @@ namespace test{ /* === special Digxel configuration for this test === */ - double sum(0), - checksum(0); - - double - sideeffectSum (double val) - { - sum += val; - return val; - } - - double preval(0), newval(0); - - double - protocollingMutator (double val) - { - preval = newval; - newval = val; - return val; - } - - double - limitingMutator (double value2set) - { - return (+1 < value2set) ? 1.0 - : (-1 > value2set) ? -1.0 - : value2set; - } - - struct VerySpecialFormat : digxel::PrintfFormatter { @@ -103,6 +75,47 @@ namespace test{ typedef Digxel TestDigxel; + + double sum(0), + checksum(0); + + void + sideeffectSum (TestDigxel* digxel, double val) + { + sum += val; + digxel->setValueRaw (val); + } + + double preval(0), newval(0); + + void + protocollingMutator (TestDigxel* digxel, double val) + { + preval = newval; + newval = val; + digxel->setValueRaw (val); + } + + void + limitingMutator (TestDigxel* digxel, double value2set) + { + digxel->setValueRaw ((+1 < value2set) ? +1.0 + : (-1 > value2set) ? -1.0 + : value2set); + } + + void + trivialMutator (TestDigxel* digxel, double value2set) + { + digxel->setValueRaw (value2set); + } + + void + emptyMutator (TestDigxel*, double) + { + /* do nothing */ + } + }//(End)Test setup @@ -158,7 +171,7 @@ namespace test{ TestDigxel digi; // configure what the Digxel does on "mutation" - digi.mutator = sideeffectSum; + digi.installMutator (sideeffectSum, digi); CHECK (0 == digi); sum = checksum = 0; @@ -187,7 +200,7 @@ namespace test{ CHECK (12.3 == digi); // a special mutator to limit the value - digi.mutator = limitingMutator; + digi.installMutator (limitingMutator, digi); CHECK (12.3 == digi); digi = 12.3; CHECK (12.3 == digi); // triggered on real change only @@ -215,7 +228,7 @@ namespace test{ verifyAssignMutatingOperators () { TestDigxel digi; - digi.mutator = protocollingMutator; + digi.installMutator (protocollingMutator, digi); digi = 12.3; CHECK ( 0.0 == preval && 12.3 == newval); @@ -312,7 +325,7 @@ namespace test{ * we'll take some timings. * @warning the results of such tests could be unreliable, * but in this case here I saw a significant difference, - * with values of about 0.1sec / 0.7sec */ + * with values of about 10ns / 45ns */ void verifyDisplayCaching () { @@ -320,26 +333,69 @@ namespace test{ digi = 1; clock_t start(0), stop(0); - start = clock(); + boost::format resultDisplay("timings(%s)%|36T.|%4.0fns\n"); + +#define START_TIMINGS start=clock(); +#define DISPLAY_TIMINGS(ID)\ + stop = clock(); \ + uint ID = stop-start;\ + cout << resultDisplay % STRINGIFY (ID) % (double(ID)/CLOCKS_PER_SEC/TIMING_CNT*1e9) ; + + + START_TIMINGS + for (uint i=0; i < TIMING_CNT; ++i) + { + isOdd (i); + } + DISPLAY_TIMINGS (empty_loop) + + + START_TIMINGS for (uint i=0; i < TIMING_CNT; ++i) { digi = 1; isOdd (i); } - stop = clock(); - uint without_reformatting = stop - start; + DISPLAY_TIMINGS (without_reformatting) - start = clock(); + START_TIMINGS for (uint i=0; i < TIMING_CNT; ++i) { digi = isOdd (i); } - stop = clock(); - uint with_reformatting = stop - start; + DISPLAY_TIMINGS (with_reformatting) + + + digi.installMutator (emptyMutator, digi); + + START_TIMINGS + for (uint i=0; i < TIMING_CNT; ++i) + { + digi = isOdd (i); + } + DISPLAY_TIMINGS (with_empty_mutator) + + + digi.installMutator (trivialMutator, digi); + + START_TIMINGS + for (uint i=0; i < TIMING_CNT; ++i) + { + digi = isOdd (i); + } + DISPLAY_TIMINGS (with_trivial_mutator) + + + digi.installMutator (&TestDigxel::setValueRaw, digi); + + START_TIMINGS + for (uint i=0; i < TIMING_CNT; ++i) + { + digi = isOdd (i); + } + DISPLAY_TIMINGS (with_memfun_mutator) - cout << "without reformatting = "<< double(without_reformatting)/CLOCKS_PER_SEC <<"sec"<< endl; - cout << "with reformatting = "<< double(with_reformatting )/CLOCKS_PER_SEC <<"sec"<< endl; CHECK (without_reformatting < with_reformatting); }