WIP test-driven dreaming... inventing a "Digxel" entity
This commit is contained in:
parent
607c8a2338
commit
6638120ec2
3 changed files with 351 additions and 0 deletions
41
src/lib/time/digxel.cpp
Normal file
41
src/lib/time/digxel.cpp
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
Timecode - implementation of fixed grid aligned time specifications
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2010, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
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.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "lib/lumitime.hpp"
|
||||
#include "lib/time/timecode.hpp"
|
||||
#include "lib/time/timequant.hpp"
|
||||
#include "lib/time/formats.hpp"
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace time {
|
||||
|
||||
|
||||
/** */
|
||||
|
||||
|
||||
|
||||
}} // lib::time
|
||||
|
||||
106
src/lib/time/digxel.hpp
Normal file
106
src/lib/time/digxel.hpp
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/*
|
||||
TIMECODE.hpp - grid aligned and fixed format time specifications
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2010, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
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 digxel.hpp
|
||||
** A self-contained numeric element for building structured numeric displays.
|
||||
** Within the GUI of an editing application, we got to build several display widgets
|
||||
** to show numeric values in a structured fashion, like Colours or Timecode. While the
|
||||
** actual formats of such display elements vary largely, the common property is that
|
||||
** they use an underlying \em format to build the numbers out of individual numeric elements.
|
||||
** For a timecode display these are for example the sexagesimal (base 60) "digits" of the
|
||||
** common human readable time representation. A "Digxel" is an abstract element with specific
|
||||
** properties to support building such display widgets. It doesn't contain any GUI code, but
|
||||
** can be wrapped up to build a custom widget.
|
||||
**
|
||||
** \par properties of a "Digxel"
|
||||
**
|
||||
** Semantically, it's a number or number component. It holds an internal numeric representation
|
||||
** and is implicitly convertible both to integrals and floating point numbers. This implicit
|
||||
** conversion is a compromise to support generic processing.
|
||||
**
|
||||
** But at the same time, a Digxel has a definite textual format and the ability to present
|
||||
** its numeric value formatted accordingly. To this end, the contract \em requires that
|
||||
** numeric data pushed to the Digxel be kept within such limits to prevent exceeding the
|
||||
** embedded formatting buffer. There is an assertion in debug mode, and a range check,
|
||||
** but the result will be just truncated, so this is clearly the caller's responsibility.
|
||||
** Digxel might be considered an implementation support class, and performance is important
|
||||
** to some limited degree; especially, formatted values will be cached.
|
||||
**
|
||||
** To support in-place modification, the digxel stores a mutation signal (functor) and exposes
|
||||
** a special \c mutate(newVal) function, which invokes this stored functor, if defined. Usually
|
||||
** this should invoke some internal recalculations, resulting in a new value being pushed to
|
||||
** the Digxel for display.
|
||||
**
|
||||
** \par configuration
|
||||
** the Digxel template can be configured to some degree to adjust the stored numeric data
|
||||
** and the actual format to be applied
|
||||
**
|
||||
** @see timecode.hpp typical usage example
|
||||
**
|
||||
*/
|
||||
|
||||
#ifndef LIB_TIME_DIGXEL_H
|
||||
#define LIB_TIME_DIGXEL_H
|
||||
|
||||
#include "lib/error.hpp"
|
||||
|
||||
//#include <boost/operators.hpp>
|
||||
#include <cstdlib> ////////////////////TODO
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace time {
|
||||
|
||||
using std::string;
|
||||
|
||||
|
||||
/**
|
||||
* A number element for building structured numeric displays.
|
||||
* The purpose is to represent parts of a numeric format, like
|
||||
* e.g. the sexagesimal "digits" of a timecode display. Digxel
|
||||
* - is customised by template parameters to a specific number format
|
||||
* - requires that any number set must not overflow the format buffer
|
||||
* - can receive new numbers by assignment
|
||||
* - will then format these numbers and cache the formatted representation
|
||||
* - can store and invoke a mutation functor
|
||||
*
|
||||
* @param TODO
|
||||
* @see lib::time::TCode
|
||||
* @todo WIP-WIP-WIP
|
||||
*/
|
||||
template<class FMT>
|
||||
class Digxel
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
string describe() const;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}} // lib::time
|
||||
#endif
|
||||
204
tests/lib/time/digxel-test.cpp
Normal file
204
tests/lib/time/digxel-test.cpp
Normal file
|
|
@ -0,0 +1,204 @@
|
|||
/*
|
||||
Digxel(Test) - cover behaviour of a generic number-element holder
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2011, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
||||
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.
|
||||
|
||||
* *****************************************************/
|
||||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "lib/time/digxel.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
//#include <boost/lexical_cast.hpp>
|
||||
//#include <boost/algorithm/string/join.hpp>
|
||||
#include <boost/lambda/lambda.hpp>
|
||||
#include <iostream> //TODO
|
||||
#include <cstdlib>
|
||||
|
||||
//using boost::lexical_cast;
|
||||
//using util::isnil;
|
||||
//using util::contains;
|
||||
using util::isSameObject;
|
||||
using std::rand;
|
||||
using std::cout;/////////TODO
|
||||
using std::endl;
|
||||
|
||||
//using boost::algorithm::join;
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace time{
|
||||
namespace test{
|
||||
|
||||
namespace { // Test data
|
||||
|
||||
// Placeholder to mark the function argument in a "lambda-expression"
|
||||
boost::lambda::placeholder1_type _1_;
|
||||
|
||||
const uint REPEAT = 40;
|
||||
const uint RAND_RANGE = 100;
|
||||
const uint RAND_DENOM = 3;
|
||||
|
||||
inline double
|
||||
randomFrac()
|
||||
{
|
||||
double arbitrary = (rand() % RAND_RANGE);
|
||||
arbitrary /= (1 + rand() % RAND_DENOM);
|
||||
return arbitrary;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* @test verify correct behaviour of an display "Digxel":
|
||||
* A self-contained numeric element to support building displays.
|
||||
* - build a Digxel
|
||||
* - set a value
|
||||
* - retrieve formatted display
|
||||
* - assign to invoke the setter-functor
|
||||
*/
|
||||
class Digxel_test : public Test
|
||||
{
|
||||
virtual void
|
||||
run (Arg arg)
|
||||
{
|
||||
checkSimpleUsage (ref);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
checkSimpleUsage ()
|
||||
{
|
||||
TestDigxel digi;
|
||||
CHECK (0 == digi);
|
||||
CHECK ("## 0 ##" == digi.show());
|
||||
|
||||
digi = 88;
|
||||
CHECK (88 == digi);
|
||||
CHECK ("## 88.0 ##" == digi.show());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
checkMutation ()
|
||||
{
|
||||
TestDigxel digi;
|
||||
|
||||
uint sum(0), checksum(0);
|
||||
|
||||
// configure what the Digxel does on "mutation"
|
||||
digi.mutator = ( var(sum) += _1_ );
|
||||
|
||||
CHECK (0 == digi);
|
||||
for (uint i=0; i < REPEAT; ++i)
|
||||
{
|
||||
double arbitrary = randomFrac();
|
||||
checksum += arbitrary;
|
||||
|
||||
digi.mutate (arbitrary); // invoke the mutation functor
|
||||
|
||||
CHECK (sum == checksum, "divergence after adding %f in iteration %d", arbitrary, i);
|
||||
CHECK (0 == digi); // the value itself is not touched
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
checkDefaultMutator ()
|
||||
{
|
||||
TestDigxel digi;
|
||||
|
||||
CHECK (0 == digi);
|
||||
digi.mutate(12.3);
|
||||
CHECK (12.3 == digi);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
checkCopy ()
|
||||
{
|
||||
TestDigxel d1;
|
||||
|
||||
double someValue = randomFrac();
|
||||
|
||||
d1 = someValue;
|
||||
CHECK (d1 == someValue);
|
||||
|
||||
TextDigxel d2(d1);
|
||||
CHECK (d2 == someValue);
|
||||
CHECK (!isSameObject (d1, d2));
|
||||
|
||||
d1 = randomFrac();
|
||||
CHECK (d1 != d2);
|
||||
CHECK (d2 == someValue);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
checkDisplayOverrun ()
|
||||
{
|
||||
TestDigxel digi;
|
||||
digi = 123456789.12345678;
|
||||
|
||||
string formatted (digi.show());
|
||||
CHECK (formatted.length() <= digi.maxlen());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
verifyDisplayCaching ()
|
||||
{
|
||||
TestDigxel digi;
|
||||
digi = 1;
|
||||
|
||||
clock_t start, stop;
|
||||
start = clock();
|
||||
for (uint i=0; i < TIMING_CNT; ++i)
|
||||
{
|
||||
val odd = i % 2;
|
||||
digi = 1;
|
||||
}
|
||||
stop = clock();
|
||||
uint without_reformatting = stop - start;
|
||||
|
||||
|
||||
start = clock();
|
||||
for (uint i=0; i < TIMING_CNT; ++i)
|
||||
{
|
||||
val odd = i % 2;
|
||||
digi = odd;
|
||||
}
|
||||
stop = clock();
|
||||
uint with_reformatting = stop - start;
|
||||
|
||||
cout << "without = "<< without_reformatting << endl;
|
||||
cout << "with = "<< with_reformatting << endl;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (Digxel_test, "unit common");
|
||||
|
||||
|
||||
|
||||
}}} // namespace lib::time::test
|
||||
Loading…
Reference in a new issue