Add more special formatters and Digxel testcases

The Digxel implementation draft can be considered complete now
This commit is contained in:
Fischlurch 2011-01-06 03:45:29 +01:00
parent 8e90b3d5dc
commit c85f7e0715
6 changed files with 212 additions and 86 deletions

View file

@ -1,38 +0,0 @@
/*
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/time/digxel.hpp"
namespace lib {
namespace time {
/** */
}} // lib::time

View file

@ -35,21 +35,23 @@
** \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.
** and is implicitly convertible back to the underlying numeric type (usually int or double).
**
** 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.
** but the result will be just truncated, so passing only sane values 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 \em 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.
** To support in-place modification, the digxel stores a mutation signal (functor). This
** functor will be invoked, whenever a new value gets assigned. The actual functor is free
** to cause side effects; the value returned from this functor will be the new value to set.
** If not configured, the default implementation just accepts the given value unaltered. Usually
** this mutation functor should invoke some internal recalculations, maybe 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
@ -69,16 +71,15 @@
#include <boost/operators.hpp>
#include <boost/lexical_cast.hpp>
#include <tr1/functional>
#include <cstdlib> ///////////TODO
#include <cmath>
#include <string>
#include <cmath>
using std::string;
namespace lib {
namespace time {
using std::string;
namespace digxel {
using util::cStr;
@ -86,27 +87,13 @@ namespace time {
using boost::lexical_cast;
typedef const char* CBuf;
template<typename NUM>
struct ValTrait;
template<>
struct ValTrait<int>
{
static int asInt (int val) { return val; }
static double asDouble (int val) { return val; }
};
template<>
struct ValTrait<double>
{
static int asInt (double val) { return std::floor(0.5+val); } ///< in accordance with Lumiera's time handling RfC
static double asDouble (double val) { return val; }
};
/**
* Default / base implementation for Digxel formatting.
* This formatter holds an inline buffer of limited size,
* receiving and caching the textual representation
*/
template<typename NUM, size_t len>
class PrintfFormatter
{
@ -124,7 +111,7 @@ namespace time {
}
void clear() { printbuffer_[0] = '\0'; }
bool empty() { return ! bool(*printbuffer_); }
bool empty() { return '\0' == *printbuffer_; }
size_t
maxlen() const
@ -147,6 +134,11 @@ namespace time {
}
};
/**
* default configured Formatter implementations
* for some of the basic numeric types
*/
template<typename NUM>
struct Formatter;
@ -154,8 +146,7 @@ namespace time {
struct Formatter<int>
: PrintfFormatter<int, 6>
{
Formatter() : PrintfFormatter<int,6>("%5d") { }
Formatter() : PrintfFormatter<int,6>("%3d") { }
};
template<>
@ -163,25 +154,46 @@ namespace time {
: PrintfFormatter<double, 7>
{
Formatter() : PrintfFormatter<double,7>("%06.3f") { }
};
/* == other specialised Formatters == */
struct SexaFormatter
: PrintfFormatter<int, 4>
{
SexaFormatter() : PrintfFormatter<int,4>("%02d") { }
};
struct HexaFormatter
: PrintfFormatter<uint, 2>
{
HexaFormatter() : PrintfFormatter<uint,2>("%02X") { }
};
} //(End) digxel configuration namespace
/**
* 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
* e.g. the sexagesimal "digits" of a timecode display. A Digxel
* - is customised by template parameters to a specific number format
* - requires that any number set must not overflow the format buffer
* - requires that any given number must not overflow the format buffer
* - can receive new numbers by assignment
* - stores and these given value numerically
* - will then format these numbers and cache the formatted representation
* - can store and invoke a mutation functor
*
* - can store and invoke a mutation functor to pre-process values on setting
*
* @note comparisons are assumed to be not performance relevant
* @param NUM numeric type to be used for the value
* @param FMT a formatter and buffer holder type
* @see digxel::Formatter default printf based formatter
* @see lib::time::TCode
* @todo WIP-WIP-WIP
* @see Digxel_test
*
*/
template< typename NUM
, class FMT = digxel::Formatter<NUM>
@ -208,7 +220,7 @@ namespace time {
Digxel ()
: buffer_()
, value_()
, value_ ()
, mutator(use_newValue_as_is)
{ }
@ -219,6 +231,7 @@ namespace time {
size_t maxlen() const { return buffer_.maxlen(); }
digxel::CBuf
show() const
{
@ -229,7 +242,7 @@ namespace time {
void
operator= (NUM n)
{
NUM changedValue = mutator(n);
NUM changedValue = mutator(n);
this->setValueRaw (changedValue);
}
@ -248,13 +261,14 @@ namespace time {
//---Supporting-totally_ordered---------
bool operator< (Digxel const& o) const { return value_ < NUM(o); }
bool operator== (Digxel const& o) const { return value_ == NUM(o); }
// bool operator== (NUM n) const { return value_ == n ; }
// bool operator< (NUM n) const { return value_ < n ; }
// bool operator> (NUM n) const { return value_ > n ; }
};
/* == predefined Digxel configurations == */
typedef Digxel< int, digxel::SexaFormatter> SexaDigit; ///< for displaying time components (sexagesimal)
typedef Digxel<uint, digxel::HexaFormatter> HexaDigit; ///< for displaying a hex byte
}} // lib::time
#endif

View file

@ -32,6 +32,7 @@
//#include <boost/operators.hpp>
#include <vector>
#include <string>
#include <cmath>
namespace lib {
@ -39,6 +40,29 @@ namespace time {
LUMIERA_ERROR_DECLARE (UNKNOWN_GRID); ///< referring to an undefined grid or scale in value quantisation
namespace { // stashed here for later
template<typename NUM>
struct ValTrait;
template<>
struct ValTrait<int>
{
static int asInt (int val) { return val; }
static double asDouble (int val) { return val; }
};
template<>
struct ValTrait<double>
{
static int asInt (double val) { return std::floor(0.5+val); } ///< in accordance with Lumiera's time handling RfC
static double asDouble (double val) { return val; }
};
}
/**
* Facility to create grid-aligned time values.
*

View file

@ -231,6 +231,26 @@ return: 0
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
return: 0
END
TEST "Digxel standard configurations" DigxelConfigurations_test <<END
out: .+Digxel.+Formatter.+--empty-- 0--\(val=123\)--123\|
out: .+Digxel.+Formatter.+--empty--00.000--\(val=123.457\)--123.457
out: .+Digxel.+SexaFormatter.+--empty--00--\(val=42\)--42
out: .+Digxel.+SexaFormatter.+--empty--00--\(val=-5\)---5
out: .+Digxel.+HexaFormatter.+--empty--00--\(val=12\)--0C
out: .+Digxel.+HexaFormatter.+--empty--00--\(val=111\)--6F
return: 0
END
TEST "Duck typing support" DuckDetector_test <<END
out: HasNested_Core<PropperGander> : Yes
out: HasNested_Core<Propaganda> : No

View file

@ -0,0 +1,105 @@
/*
DigxelConfigurations(Test) - verify predefined standard Digxel configurations
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/display.hpp"
#include "lib/time/digxel.hpp"
#include "lib/error.hpp"
#include "lib/util.hpp"
#include <iostream>
#include <cstdlib>
using lumiera::error::LUMIERA_ERROR_ASSERTION;
using util::isSameObject;
using lib::test::showType;
using std::rand;
using std::cout;
using std::endl;
namespace lib {
namespace time{
namespace test{
/***********************************************************************
* @test verify correctness of the predefined standard Digxels.
* Some widely used standard configurations, including
* - default Digxel for int and double values
* - sexagesimal Digxel
* - hex byte Digxel
* - ...more to come
* @todo cover any newly added Digxel configurations.
*/
class DigxelConfigurations_test : public Test
{
virtual void
run (Arg)
{
verifyConfiguration<Digxel<int> > (123);
verifyConfiguration<Digxel<double> > (123.4567);
verifyConfiguration<SexaDigit > (42);
verifyConfiguration<SexaDigit > (-5);
verifyConfiguration<HexaDigit > (0xc);
verifyConfiguration<HexaDigit > (0x6f);
}
template<class DIX, typename VAL>
void
verifyConfiguration (VAL testval)
{
DIX digxel;
CHECK (0 == digxel);
cout << showType(digxel) << "--empty--"<<digxel;
digxel = testval;
cout << "--(val="<<testval<<")--"<<digxel;
// verify buffer overrun protection
digxel = 123456789.12345;
string formatted;
#if false ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT
VERIFY_ERROR (ASSERTION, formatted = digxel.show() ); // should trigger assertion
formatted = digxel.show(); // second time doesn't reformat
CHECK (formatted.length() == digxel.maxlen());
cout << "--(clipped)--"<< digxel;
#endif ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT
cout <<"|"<< endl;
}
};
/** Register this test class... */
LAUNCHER (DigxelConfigurations_test, "unit common");
}}} // namespace lib::time::test

View file

@ -30,6 +30,7 @@
#include <iostream>
#include <cstdlib>
using lumiera::error::LUMIERA_ERROR_ASSERTION;
using util::isSameObject;
using std::rand;
using std::cout;
@ -247,7 +248,7 @@ namespace test{
string formatted;
#if false ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT
VERIFY_ERROR (ASSERTION, formatted = digi.show() ); // should trigger assertion
formatted = digi.show(); // second time doesn't reformat
formatted = digi.show(); // second time doesn't reformat
#endif ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT
CHECK (formatted.length() <= digi.maxlen());