WIP test-driven dreaming... inventing a "Digxel" entity

This commit is contained in:
Fischlurch 2011-01-04 03:50:33 +01:00
parent 607c8a2338
commit 6638120ec2
3 changed files with 351 additions and 0 deletions

41
src/lib/time/digxel.cpp Normal file
View 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
View 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

View 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