change the way the Digxel mutator is invoked

this refactoring prepares a change to address
the problems with negative extended SMPTE Timecode
This commit is contained in:
Fischlurch 2011-01-22 14:04:43 +01:00
parent 14f233f83b
commit ac9e9a99df
4 changed files with 138 additions and 66 deletions

View file

@ -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<NUM(NUM)> _Mutator;
typedef Digxel<NUM,FMT> _Digxel;
typedef function<void(NUM)> _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<typename FUN, class THIS>
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<int,digxel::SignFormatter>
{
static int
just_the_sign (int val)
typedef Digxel<int, digxel::SignFormatter> _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; }
};

View file

@ -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

View file

@ -234,8 +234,7 @@ END
TEST "A Digxel (numeric component)" Digxel_test <<END
out-lit: empty____## +0.0 ##
out-lit: value____##-88.8 ##
out: without reformatting = .+sec
out: with reformatting = .+sec
out: timings\(\w+\)....*ns
return: 0
END

View file

@ -27,8 +27,9 @@
#include "lib/time/digxel.hpp"
#include "lib/util.hpp"
#include <iostream>
#include <cstdlib>
#include <iostream>
#include <boost/format.hpp>
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<double, 11>
{
@ -103,6 +75,47 @@ namespace test{
typedef Digxel<double, VerySpecialFormat> 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);
}