Implementation: building a simple time grid
This commit is contained in:
parent
640d061de6
commit
04db5655f1
11 changed files with 285 additions and 60 deletions
|
|
@ -125,7 +125,8 @@ namespace lumiera {
|
|||
LUMIERA_ERROR_DECLARE (WRONG_TYPE); ///< runtime type mismatch
|
||||
LUMIERA_ERROR_DECLARE (ITER_EXHAUST); ///< end of sequence reached
|
||||
LUMIERA_ERROR_DECLARE (BOTTOM_VALUE); ///< invalid or NIL value
|
||||
LUMIERA_ERROR_DECLARE (UNCONNECTED); ///< missing connection
|
||||
LUMIERA_ERROR_DECLARE (UNCONNECTED); ///< missing connection
|
||||
LUMIERA_ERROR_DECLARE (UNIMPLEMENTED);///< unimplemented feature
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -82,7 +82,9 @@ namespace lumiera {
|
|||
LUMIERA_ERROR_DEFINE (WRONG_TYPE, "runtime type mismatch");
|
||||
LUMIERA_ERROR_DEFINE (ITER_EXHAUST, "end of sequence reached");
|
||||
LUMIERA_ERROR_DEFINE (BOTTOM_VALUE, "invalid or NIL value");
|
||||
LUMIERA_ERROR_DEFINE (UNCONNECTED, "missing connection");
|
||||
LUMIERA_ERROR_DEFINE (UNCONNECTED, "missing connection");
|
||||
LUMIERA_ERROR_DEFINE (UNIMPLEMENTED, "using a feature not yet implemented....");
|
||||
|
||||
|
||||
|
||||
} // namespace error
|
||||
|
|
|
|||
49
src/lib/time/display.hpp
Normal file
49
src/lib/time/display.hpp
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
DISPLAY.hpp - formatting of time values for display
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_TIME_DISPLAY_H
|
||||
#define LIB_TIME_DISPLAY_H
|
||||
|
||||
#include "lib/time/timecode.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
|
||||
|
||||
namespace lib {
|
||||
namespace time {
|
||||
|
||||
|
||||
/** writes time value, formatted as HH:MM:SS:mmm
|
||||
* @see lumiera_tmpbuf_print_time */
|
||||
inline std::ostream&
|
||||
operator<< (std::ostream& os, Time const& t)
|
||||
{
|
||||
return os << std::string(t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}} // lib::time
|
||||
#endif
|
||||
|
|
@ -30,6 +30,7 @@ extern "C" {
|
|||
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <boost/rational.hpp>
|
||||
|
||||
using std::string;
|
||||
|
||||
|
|
@ -37,6 +38,18 @@ using std::string;
|
|||
namespace lib {
|
||||
namespace time {
|
||||
|
||||
namespace {
|
||||
/** implementation detail: convert a rational number denoting fractionalSeconds
|
||||
* into the internal time scale used by GAVL and Lumiera internal time values.
|
||||
*/
|
||||
inline gavl_time_t
|
||||
rational2time (TimeFract const& fractionalSeconds)
|
||||
{
|
||||
return boost::rational_cast<gavl_time_t> (GAVL_TIME_SCALE * fractionalSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const Time Time::MAX ( TimeValue (+std::numeric_limits<gavl_time_t>::max()) );
|
||||
const Time Time::MIN ( TimeValue (-std::numeric_limits<gavl_time_t>::max()) );
|
||||
|
||||
|
|
@ -60,6 +73,15 @@ namespace time {
|
|||
{ }
|
||||
|
||||
|
||||
/** convenience constructor to build an Time value
|
||||
* from a fraction of seconds, given as rational number.
|
||||
* An example would be to the time unit of a framerate.
|
||||
*/
|
||||
Time::Time (TimeFract const& fractionalSeconds)
|
||||
: TimeValue(rational2time (fractionalSeconds))
|
||||
{ }
|
||||
|
||||
|
||||
/** displaying an internal Lumiera Time value
|
||||
* for diagnostic purposes or internal reporting.
|
||||
* @warning internal Lumiera time values refer to an
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#define LIB_TIME_TIMEVALUE_H
|
||||
|
||||
#include <boost/operators.hpp>
|
||||
#include <boost/rational.hpp>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
|
|
@ -182,6 +183,9 @@ namespace time {
|
|||
|
||||
/* ======= specific Time entities ==================== */
|
||||
|
||||
/** rational representation of fractional seconds */
|
||||
typedef boost::rational<gavl_time_t> TimeFract;
|
||||
|
||||
/**
|
||||
* Lumiera's internal time value datatype.
|
||||
* This is a TimeValue, but now more specifically denoting
|
||||
|
|
@ -219,6 +223,8 @@ namespace time {
|
|||
: TimeValue(calcResult)
|
||||
{ }
|
||||
|
||||
Time (TimeFract const& fractionalSeconds);
|
||||
|
||||
Time ( long millis
|
||||
, uint secs
|
||||
, uint mins =0
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ namespace asset {
|
|||
|
||||
namespace meta {
|
||||
|
||||
Descriptor::~Descriptor() { } // emit vtable here...
|
||||
Descriptor::~Descriptor() { } // emit VTable here...
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -54,8 +54,8 @@ namespace asset {
|
|||
* created as a side effect of calling the concrete Meta subclass ctor.
|
||||
*/
|
||||
template<class MA>
|
||||
P<MA>
|
||||
MetaFactory::operator() (EntryID<MA> elementIdentity)
|
||||
meta::Builder<MA>
|
||||
MetaFactory::operator () (EntryID<MA> elementIdentity)
|
||||
{
|
||||
UNIMPLEMENTED ("Meta-Factory");
|
||||
}
|
||||
|
|
@ -70,7 +70,7 @@ namespace asset {
|
|||
* created as a side effect of calling the concrete Meta subclass ctor.
|
||||
*/
|
||||
template<class MA>
|
||||
P<MA>
|
||||
meta::Builder<MA>
|
||||
MetaFactory::operator() (Descriptor const& prototype, EntryID<MA> elementIdentity)
|
||||
{
|
||||
UNIMPLEMENTED ("Meta-Factory");
|
||||
|
|
@ -96,10 +96,11 @@ namespace asset {
|
|||
namespace asset {
|
||||
|
||||
using meta::Descriptor;
|
||||
using meta::Builder;
|
||||
using meta::TimeGrid;
|
||||
|
||||
template P<TimeGrid> MetaFactory::operator() (EntryID<TimeGrid>);
|
||||
template Builder<TimeGrid> MetaFactory::operator() (EntryID<TimeGrid>);
|
||||
|
||||
template P<TimeGrid> MetaFactory::operator() (Descriptor const&, EntryID<TimeGrid>);
|
||||
template Builder<TimeGrid> MetaFactory::operator() (Descriptor const&, EntryID<TimeGrid>);
|
||||
|
||||
} // namespace asset
|
||||
|
|
|
|||
|
|
@ -22,14 +22,34 @@
|
|||
|
||||
|
||||
/** @file meta.hpp
|
||||
** Internal and organisational metadata. Some internally created data elements,
|
||||
** like automation data sets, inventory of session contents, can be exposed and
|
||||
** treated as specific Kind of Asset.
|
||||
** Internal and organisational metadata. Some internally created data elements
|
||||
** rather serve the purpose of controlling the way the application behaves, as
|
||||
** opposed to organising the \link struct.hpp structure \endlink of the data the
|
||||
** user works with. Lumiera exposes this self-referential control and customisation
|
||||
** aspects as a special kind of Asset. Examples being types, scales and quantisation
|
||||
** grids, decision rules, control data stores (automation data), annotations attached
|
||||
** to labels, inventory entities etc.
|
||||
**
|
||||
** For the different <i>Kinds</i> of Assets, we use sub-interfaces inheriting
|
||||
** from the general Asset interface. To be able to get asset::Meta instances
|
||||
** directly from the AssetManager, we define a specialisation of the Asset ID.
|
||||
**
|
||||
** \par using meta assets
|
||||
** The usage pattern of asset::Meta entities differs from the other assets,
|
||||
** insofar they aren't created as individual entries, rather added as part
|
||||
** of a larger scale configuration activity, or they are derived from category.
|
||||
** The latter fits in with a prototype-like approach; initially, the individual
|
||||
** entry just serves to keep track of a categorisation, while at some point,
|
||||
** such a link into a describing category may evolve into a local
|
||||
** differentiation of some settings (copy on modification).
|
||||
**
|
||||
** To cope with this special usage, the meta assets are defined to be immutable.
|
||||
** They are created from a descriptor, which stands for a category or sub-category
|
||||
** and can be another already existing asset::Meta (inheriting from meta::Descriptor)
|
||||
** Generally this yields a Builder object, which can be used for outfitting the new
|
||||
** or changed metadata entry, finally \em committing this builder to yield a new
|
||||
** asset::Meta (which, in case of a mutation, might superseede an existin one).
|
||||
**
|
||||
** @see asset.hpp explanation of assets in general
|
||||
** @see MetaFactory creating concrete asset::Meta instances
|
||||
**
|
||||
|
|
@ -71,6 +91,21 @@ namespace asset {
|
|||
public:
|
||||
virtual ~Descriptor(); ///< this is an ABC
|
||||
};
|
||||
|
||||
/**
|
||||
* Building and configuring a meta asset.
|
||||
* The finished elements are defined to be immutable,
|
||||
* thus, on creation or when changing / superseding a
|
||||
* meta asset, the client gets a special builder instance,
|
||||
* which is a value object for configuring the specific details
|
||||
* to set. When done, the client invokes a \c commit() function,
|
||||
* which yields a smart-ptr to the new meta asset.
|
||||
* Individual meta asset subclasses are bound to define a
|
||||
* specialisation of this Builder template, which will then be
|
||||
* instantiated and provided by the MetaFactory.
|
||||
*/
|
||||
template<class MA>
|
||||
struct Builder;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -116,10 +151,10 @@ namespace asset {
|
|||
typedef P<asset::Meta> PType;
|
||||
|
||||
template<class MA>
|
||||
P<MA> operator() (EntryID<MA> elementIdentity);
|
||||
meta::Builder<MA> operator() (EntryID<MA> elementIdentity);
|
||||
|
||||
template<class MA>
|
||||
P<MA> operator() (meta::Descriptor const& prototype, EntryID<MA> elementIdentity);
|
||||
meta::Builder<MA> operator() (meta::Descriptor const& prototype, EntryID<MA> elementIdentity);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -23,29 +23,94 @@
|
|||
|
||||
#include "proc/asset/meta/time-grid.hpp"
|
||||
#include "proc/asset/entry-id.hpp"
|
||||
#include "proc/assetmanager.hpp"
|
||||
//#include "lib/time/quantiser.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
#include "lib/time/display.hpp"
|
||||
//#include "lib/util.hpp"
|
||||
//#include "include/logging.h"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <string>
|
||||
|
||||
using boost::format;
|
||||
using boost::str;
|
||||
using std::string;
|
||||
|
||||
|
||||
namespace asset {
|
||||
namespace meta {
|
||||
|
||||
namespace error = lumiera::error;
|
||||
|
||||
namespace {
|
||||
|
||||
typedef TimeGrid::Builder Builder;
|
||||
|
||||
Asset::Ident
|
||||
deriveAssetIdentity (Builder const& setup)
|
||||
{
|
||||
EntryID<TimeGrid> wtf("wtf**ck"); //////////////////////TODO some real meat here
|
||||
return wtf.getIdent();
|
||||
}
|
||||
// Implementation details (still required???)
|
||||
}
|
||||
|
||||
|
||||
/** */
|
||||
TimeGrid::TimeGrid (Builder const& setup)
|
||||
: Meta (deriveAssetIdentity (setup))
|
||||
TimeGrid::TimeGrid (EntryID<TimeGrid> const& nameID)
|
||||
: Meta (nameID.getIdent())
|
||||
{ }
|
||||
|
||||
|
||||
using lib::time::Time;
|
||||
using lib::time::TimeValue;
|
||||
using lib::time::TimeSpan;
|
||||
using lib::time::Duration;
|
||||
using lib::time::Offset;
|
||||
|
||||
/**
|
||||
* TimeGrid implementation: a trivial time grid,
|
||||
* starting at a given point in time and using a
|
||||
* constant grid spacing
|
||||
*/
|
||||
class SimpleTimeGrid
|
||||
: public TimeGrid
|
||||
{
|
||||
TimeSpan timeBase_;
|
||||
|
||||
// TODO implement the TimeGrid API here
|
||||
|
||||
public:
|
||||
SimpleTimeGrid (Time start, Duration gridSpacing, EntryID<TimeGrid> const& name)
|
||||
: TimeGrid (name)
|
||||
, timeBase_(start,gridSpacing)
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
|
||||
/** Setup of a TimeGrid: validate the settings configured into this builder instance,
|
||||
* then decide on the implementation strategy for the time grid. Convert the given
|
||||
* frames per second into an appropriate gridSpacing time and build a suitable
|
||||
* name-ID to denote the TimeGrid-meta-Asset to be built.
|
||||
* @return shared_ptr holding onto the new asset::Meta, which has already been
|
||||
* registered with the AssetManager.
|
||||
* @throw error::Config in case of invalid frames-per-second. The AssetManager
|
||||
* might raise further exception when asset registration fails.
|
||||
* @todo currently (12/2010) the AssetManager is unable to detect duplicate assets.
|
||||
* Later on the intention is that in such cases, instead of creating a new grid
|
||||
* we'll silently return the already registered exisiting and equivalent grid.
|
||||
*/
|
||||
P<TimeGrid>
|
||||
Builder<TimeGrid>::commit()
|
||||
{
|
||||
if (predecessor_)
|
||||
throw error::Invalid("compound and variable time grids are a planned feature"
|
||||
, error::LUMIERA_ERROR_UNIMPLEMENTED);
|
||||
if (!fps_)
|
||||
throw error::Config ("attempt to build a TimeGrid with 0 frames per second");
|
||||
|
||||
Time spacing = 1 / fps_; // seconds per frame
|
||||
|
||||
format gridIdFormat("grid_%f_%s");
|
||||
string name = str(gridIdFormat % fps_ % origin_);
|
||||
EntryID<TimeGrid> nameID (name);
|
||||
TimeGrid& newGrid (*new SimpleTimeGrid(origin_, Offset(spacing), nameID));
|
||||
|
||||
return AssetManager::instance().wrap (newGrid);
|
||||
}
|
||||
|
||||
}} // namespace asset::meta
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@
|
|||
** Time grid specifications are integrated into Lumiera's framework
|
||||
** for meta assets, automation, configuration and similar metadata.
|
||||
**
|
||||
** \par using time grids
|
||||
** TimeGrid is an interface (ABC), but provides some actual factory
|
||||
** functions, which can be used as a convenience shortcut to fabricate
|
||||
** the kind of simple time grid used most often.
|
||||
**
|
||||
** @see MetaFactory creating concrete asset::Meta instances
|
||||
** @see time::Quantiser
|
||||
**
|
||||
|
|
@ -43,14 +48,14 @@
|
|||
#define ASSET_META_TIME_GRID_H
|
||||
|
||||
#include "proc/asset/meta.hpp"
|
||||
#include "lib/time/quantiser.hpp"
|
||||
#include "lib/time/timevalue.hpp"
|
||||
|
||||
|
||||
|
||||
namespace asset {
|
||||
namespace meta {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Interface: a grid and scale for time quantisation.
|
||||
* This meta-Asset describes a coordinate system or
|
||||
|
|
@ -61,17 +66,52 @@ namespace meta {
|
|||
{
|
||||
|
||||
public:
|
||||
struct Builder
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
// TODO define the TimeGrid API here
|
||||
|
||||
|
||||
protected:
|
||||
friend class Builder;
|
||||
|
||||
TimeGrid (Builder const& setup); //////////////TODO
|
||||
TimeGrid (EntryID<TimeGrid> const&);
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
using lib::time::Time;
|
||||
using lib::time::TimeValue;
|
||||
using lib::time::TimeFract;
|
||||
|
||||
|
||||
template<>
|
||||
struct Builder<TimeGrid>
|
||||
{
|
||||
TimeFract fps_;
|
||||
Time origin_;
|
||||
|
||||
/** when building a compound or variable grid,
|
||||
* the predecessor is the grid active \em before
|
||||
* the origin of this (local) grid.
|
||||
* @todo currently not supported (as of 12/2010)
|
||||
*/
|
||||
P<TimeGrid> predecessor_;
|
||||
|
||||
/**
|
||||
* initialise to blank (zero).
|
||||
* You need at least to set the framerate,
|
||||
* in order to create a usable TimeGrid
|
||||
*/
|
||||
Builder()
|
||||
: fps_(0)
|
||||
, origin_(TimeValue(0))
|
||||
, predecessor_()
|
||||
{ }
|
||||
|
||||
/** create a time grid
|
||||
* based on settings within this builder
|
||||
*/
|
||||
P<TimeGrid> commit();
|
||||
|
||||
};
|
||||
|
||||
}} // namespace asset::meta
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ namespace asset {
|
|||
IDErr (const char* eID, format fmt)
|
||||
: lumiera::error::Invalid(fmt.str(),eID) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
// ------pre-defined-common-error-cases---------------
|
||||
//
|
||||
|
|
@ -88,8 +88,8 @@ namespace asset {
|
|||
AssetManager::AssetManager ()
|
||||
: registry (Singleton<asset::DB>() ())
|
||||
{ }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** provide the unique ID for given Asset::Ident tuple */
|
||||
ID<Asset>
|
||||
|
|
@ -117,7 +117,7 @@ namespace asset {
|
|||
DB::Lock guard(®istry);
|
||||
TODO ("handle duplicate Registrations");
|
||||
P<KIND> smart_ptr (obj, &destroy);
|
||||
|
||||
|
||||
registry.put (asset_id, smart_ptr);
|
||||
return asset_id;
|
||||
}
|
||||
|
|
@ -155,9 +155,9 @@ namespace asset {
|
|||
return static_pointer_cast<KIND,Asset>
|
||||
(instance().registry.get (asset.id));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return true if the given id is registered in the internal asset DB
|
||||
*/
|
||||
|
|
@ -167,10 +167,10 @@ namespace asset {
|
|||
return ( registry.get (ID<Asset>(id)) );
|
||||
} // query most general Asset ID-kind and use implicit
|
||||
// conversion from smart-ptr to bool (test if empty)
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @return true if the given id is registered with the given Category
|
||||
* @return true if the given id is registered with the given Category
|
||||
*/
|
||||
bool
|
||||
AssetManager::known (IDA id, const Category& cat)
|
||||
|
|
@ -178,23 +178,23 @@ namespace asset {
|
|||
PAsset pA = registry.get (id);
|
||||
return ( pA && pA->ident.category.isWithin(cat));
|
||||
}
|
||||
|
||||
|
||||
|
||||
namespace { // details implementing AssetManager::remove
|
||||
|
||||
|
||||
void
|
||||
recursive_call (AssetManager* instance, PAsset& pA)
|
||||
{
|
||||
instance->remove (pA->getID());
|
||||
}
|
||||
|
||||
|
||||
function<void(PAsset&)>
|
||||
detach_child_recursively () ///< @return a functor recursively invoking remove(child)
|
||||
detach_child_recursively () ///< @return a functor recursively invoking remove(child)
|
||||
{
|
||||
return bind( &recursive_call, &AssetManager::instance(), _1 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* remove the given asset from the internal DB
|
||||
* <i>together with all its dependents</i>
|
||||
|
|
@ -203,11 +203,11 @@ namespace asset {
|
|||
AssetManager::remove (IDA id)
|
||||
{
|
||||
PAsset asset = getAsset (id);
|
||||
for_each (asset->dependants, detach_child_recursively()); /////
|
||||
for_each (asset->dependants, detach_child_recursively());
|
||||
asset->unlink();
|
||||
registry.del(id);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
list<PcAsset>
|
||||
|
|
@ -218,7 +218,7 @@ namespace asset {
|
|||
res.sort();
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace asset
|
||||
|
||||
|
|
@ -229,15 +229,16 @@ namespace asset {
|
|||
/* explicit template instantiations for various Asset Kinds */
|
||||
/************************************************************/
|
||||
|
||||
#include "proc/asset/media.hpp"
|
||||
#include "proc/asset/clip.hpp"
|
||||
#include "proc/asset/proc.hpp"
|
||||
#include "proc/asset/struct.hpp"
|
||||
#include "proc/asset/pipe.hpp"
|
||||
#include "proc/asset/meta.hpp"
|
||||
#include "proc/asset/procpatt.hpp"
|
||||
#include "proc/asset/timeline.hpp"
|
||||
#include "proc/asset/sequence.hpp"
|
||||
#include "proc/asset/media.hpp"
|
||||
#include "proc/asset/clip.hpp"
|
||||
#include "proc/asset/proc.hpp"
|
||||
#include "proc/asset/struct.hpp"
|
||||
#include "proc/asset/pipe.hpp"
|
||||
#include "proc/asset/meta.hpp"
|
||||
#include "proc/asset/procpatt.hpp"
|
||||
#include "proc/asset/timeline.hpp"
|
||||
#include "proc/asset/sequence.hpp"
|
||||
#include "proc/asset/meta/time-grid.hpp"
|
||||
|
||||
|
||||
namespace asset {
|
||||
|
|
@ -260,5 +261,8 @@ namespace asset {
|
|||
template P<Timeline> AssetManager::wrap (const Timeline& asset);
|
||||
template P<Sequence> AssetManager::wrap (const Sequence& asset);
|
||||
|
||||
using meta::TimeGrid;
|
||||
template P<TimeGrid> AssetManager::wrap (const TimeGrid& asset);
|
||||
|
||||
|
||||
} // namespace asset
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ namespace test{
|
|||
TimeValue zero;
|
||||
TimeValue five(5);
|
||||
|
||||
TimeSpan interval (Time(org), Duration(Offset (org,five)));
|
||||
TimeSpan interval (Time(org), Duration(Offset (org,five))); /////////////TODO need more convenient constructors
|
||||
|
||||
// the time span behaves like a time
|
||||
CHECK (org == interval);
|
||||
|
|
|
|||
Loading…
Reference in a new issue