Merge Fixture datastructure and Testsuite work
This commit is contained in:
commit
4410830f72
78 changed files with 10392 additions and 1401 deletions
4091
doc/devel/draw/Builder.Fixture-1.svg
Normal file
4091
doc/devel/draw/Builder.Fixture-1.svg
Normal file
File diff suppressed because it is too large
Load diff
|
After Width: | Height: | Size: 217 KiB |
3333
doc/devel/draw/Builder.SegmentationSteps-1.svg
Normal file
3333
doc/devel/draw/Builder.SegmentationSteps-1.svg
Normal file
File diff suppressed because it is too large
Load diff
|
After Width: | Height: | Size: 179 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
|
@ -132,6 +132,12 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( proc, progress);
|
|||
NOBUG_CPP_DEFINE_FLAG_PARENT ( command, proc);
|
||||
/** progress log for session datastructure */
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( session, proc);
|
||||
/** progress log for the builder and build process */
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( builder, proc);
|
||||
/** progress log for running the engine */
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( engine, proc);
|
||||
/** progress log for play- and render subsystem */
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( play, proc);
|
||||
/** progress log for the gui */
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( gui, progress);
|
||||
/** progress log for the support lib */
|
||||
|
|
@ -158,13 +164,13 @@ NOBUG_CPP_DEFINE_FLAG_PARENT ( config, logging);
|
|||
|
||||
/** base flag for software testing */
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( test, logging);
|
||||
/** base flag for syncronization logging */
|
||||
/** base flag for synchronisation logging */
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( sync, logging); // do we need subsections here? backend_mutex_sync proc_mutex_sync etc?
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( mutex_sync, sync); //locking/unlocking mutexes
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( cond_sync, sync); //waiting and signalling condition vars
|
||||
/** base flag for memory related logging */
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( memory, logging);
|
||||
/** memory busines of the proc layer */
|
||||
/** proc layer memory handling */
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( proc_mem, memory);
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( mobject_mem, proc_mem);
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT ( builder_mem, proc_mem);
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@
|
|||
#include "lib/error.hpp"
|
||||
#include "lib/sync-classlock.hpp"
|
||||
#include "lib/scoped-holder.hpp"
|
||||
#include "lib/scopedholdertransfer.hpp"
|
||||
#include "lib/scoped-holder-transfer.hpp"
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@
|
|||
#include <string>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/format.hpp> /////////////////////////////////////////TICKET #166 Oh RLY ... need to do away with this
|
||||
|
||||
#include "lib/symbol.hpp"
|
||||
|
||||
|
|
@ -64,7 +64,7 @@ namespace lumiera {
|
|||
{
|
||||
public:
|
||||
explicit Query (string const& predicate="") : string(predicate) {}
|
||||
explicit Query (format& pattern) : string(str(pattern)) {}
|
||||
// explicit Query (format& pattern) : string(str(pattern)) {} //////////////TICKET #166 outch... that needs to disappear
|
||||
|
||||
const string asKey() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
SCOPEDHOLDERVECTOR.hpp - using ScopedHolder within a STL vector
|
||||
SCOPED-HOLDER-TRANSFER.hpp - using ScopedHolder within a STL vector
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, Hermann Vosseler <Ichthyostega@web.de>
|
||||
|
|
@ -22,8 +22,8 @@
|
|||
|
||||
|
||||
|
||||
#ifndef LIB_SCOPEDHOLDERVECTOR_H
|
||||
#define LIB_SCOPEDHOLDERVECTOR_H
|
||||
#ifndef LIB_SCOPEDHOLDER_TRANSFER_H
|
||||
#define LIB_SCOPEDHOLDER_TRANSFER_H
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include <memory>
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
** friend function.
|
||||
**
|
||||
** @see scoped-holder-test.cpp
|
||||
** @see scopedholdertransfer.hpp use in std::vector
|
||||
** @see scoped-holder-transfer.hpp use in std::vector
|
||||
** @see AllocationCluster usage example
|
||||
** @see scoped-ptrvect.hpp simple pointer-holding collection
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -171,7 +171,7 @@ namespace lib {
|
|||
|
||||
|
||||
private:
|
||||
/** @internal element access, including null check */
|
||||
/** @internal element access, including range and null check */
|
||||
T*
|
||||
get (size_type i)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@
|
|||
|
||||
#include "lib/symbol.hpp"
|
||||
#include "lib/query.hpp"
|
||||
#include "proc/asset/entry-id.hpp"
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
|
|
@ -47,7 +48,7 @@ namespace lumiera {
|
|||
|
||||
|
||||
/**
|
||||
*
|
||||
* TODO write type comment
|
||||
*/
|
||||
struct StreamType : boost::noncopyable
|
||||
{
|
||||
|
|
@ -72,6 +73,8 @@ namespace lumiera {
|
|||
class ImplFacade;
|
||||
class ImplConstraint;
|
||||
|
||||
typedef asset::EntryID<StreamType> ID;
|
||||
|
||||
|
||||
Prototype const& prototype;
|
||||
ImplFacade * implType; /////////////TODO: really by ptr???
|
||||
|
|
@ -149,9 +152,9 @@ namespace lumiera {
|
|||
* and use it to create a new framebuffer */
|
||||
virtual DataBuffer* createFrame () const =0;
|
||||
|
||||
/** similarily create a impl type which complies to this constraint
|
||||
/** Similarly create a impl type which complies to this constraint
|
||||
* as well as to the additional constraints (e.g. frame size).
|
||||
* Create a new framebuffer of the resutling type */
|
||||
* Create a new frame buffer of the resulting type */
|
||||
virtual DataBuffer* createFrame (ImplConstraint const& furtherConstraints) const =0;
|
||||
|
||||
//TODO: do we need functions to represent and describe this constraint?
|
||||
|
|
|
|||
|
|
@ -109,7 +109,8 @@ liblumiprocmobjectbuilder_la_SOURCES = \
|
|||
$(liblumiprocmobjectbuilder_la_srcdir)/assembler.cpp \
|
||||
$(liblumiprocmobjectbuilder_la_srcdir)/conmanager.cpp \
|
||||
$(liblumiprocmobjectbuilder_la_srcdir)/nodecreatortool.cpp \
|
||||
$(liblumiprocmobjectbuilder_la_srcdir)/segmentationtool.cpp \
|
||||
$(liblumiprocmobjectbuilder_la_srcdir)/segmentation.cpp \
|
||||
$(liblumiprocmobjectbuilder_la_srcdir)/segmentation-tool.cpp \
|
||||
$(liblumiprocmobjectbuilder_la_srcdir)/toolfactory.cpp
|
||||
|
||||
|
||||
|
|
@ -219,7 +220,8 @@ noinst_HEADERS += \
|
|||
$(liblumiproc_la_srcdir)/mobject/builder/assembler.hpp \
|
||||
$(liblumiproc_la_srcdir)/mobject/builder/buildertool.hpp \
|
||||
$(liblumiproc_la_srcdir)/mobject/builder/conmanager.hpp \
|
||||
$(liblumiproc_la_srcdir)/mobject/builder/segmentationtool.hpp \
|
||||
$(liblumiproc_la_srcdir)/mobject/builder/segmentation.hpp \
|
||||
$(liblumiproc_la_srcdir)/mobject/builder/segmentation-tool.hpp \
|
||||
$(liblumiproc_la_srcdir)/mobject/builder/toolfactory.hpp \
|
||||
$(liblumiproc_la_srcdir)/mobject/builderfacade.hpp \
|
||||
$(liblumiproc_la_srcdir)/mobject/explicitplacement.hpp \
|
||||
|
|
|
|||
|
|
@ -103,11 +103,13 @@ namespace asset {
|
|||
template<class KIND>
|
||||
class ID
|
||||
{
|
||||
HashVal hash_;
|
||||
public:
|
||||
const HashVal hash;
|
||||
ID (HashVal id) : hash(id) {}
|
||||
ID (const KIND& asset) : hash(asset.getID()) {}
|
||||
operator HashVal() const { return hash; }
|
||||
ID (HashVal id) : hash_(id) {}
|
||||
ID (const KIND& asset) : hash_(asset.getID()) {}
|
||||
operator HashVal() const { return hash_; }
|
||||
|
||||
static ID INVALID;
|
||||
};
|
||||
|
||||
class DB;
|
||||
|
|
@ -303,53 +305,59 @@ namespace asset {
|
|||
|
||||
|
||||
|
||||
/* ====== ordering of Assets and Asset-Pointers ====== */
|
||||
|
||||
/** ordering of Assets is based on the ordering
|
||||
* of Ident tuples, which are supposed to be unique.
|
||||
* By using our customised lumiera::P as smart ptr,
|
||||
* comparison on P<Asset> ptrs will be automatically
|
||||
* forwarded to the Asset comparison operators.
|
||||
* @note version info is irrelevant */
|
||||
inline int
|
||||
Asset::Ident::compare (Asset::Ident const& oi) const
|
||||
{
|
||||
int res;
|
||||
if (0 != (res=category.compare (oi.category))) return res;
|
||||
if (0 != (res=org.compare (oi.org))) return res;
|
||||
return name.compare (oi.name);
|
||||
}
|
||||
|
||||
|
||||
/** promote subtype-ptr to PAsset, e.g. for comparing */
|
||||
template<class A>
|
||||
inline const PcAsset
|
||||
pAsset (shared_ptr<A> const& subPtr)
|
||||
{
|
||||
return static_pointer_cast<const Asset,A> (subPtr);
|
||||
}
|
||||
|
||||
|
||||
/** type trait for detecting a shared-ptr-to-asset */
|
||||
template <class X>
|
||||
struct is_pAsset : boost::false_type {};
|
||||
|
||||
template <class A>
|
||||
struct is_pAsset<shared_ptr<A> >
|
||||
: boost::is_base_of<Asset, A> {};
|
||||
|
||||
|
||||
/** convenient for debugging */
|
||||
inline string str (PcAsset const& a)
|
||||
{
|
||||
if (a)
|
||||
return string (*a.get());
|
||||
else
|
||||
return "Asset(NULL)";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* ====== ordering of Assets and Asset-Pointers ====== */
|
||||
|
||||
/** ordering of Assets is based on the ordering
|
||||
* of Ident tuples, which are supposed to be unique.
|
||||
* By using our customised lumiera::P as smart ptr,
|
||||
* comparison on P<Asset> ptrs will be automatically
|
||||
* forwarded to the Asset comparison operators.
|
||||
* @note version info is irrelevant */
|
||||
inline int
|
||||
Asset::Ident::compare (Asset::Ident const& oi) const
|
||||
{
|
||||
int res;
|
||||
if (0 != (res=category.compare (oi.category))) return res;
|
||||
if (0 != (res=org.compare (oi.org))) return res;
|
||||
return name.compare (oi.name);
|
||||
}
|
||||
|
||||
|
||||
/** promote subtype-ptr to PAsset, e.g. for comparing */
|
||||
template<class A>
|
||||
inline const PcAsset
|
||||
pAsset (shared_ptr<A> const& subPtr)
|
||||
{
|
||||
return static_pointer_cast<const Asset,A> (subPtr);
|
||||
}
|
||||
|
||||
|
||||
/** type trait for detecting a shared-ptr-to-asset */
|
||||
template <class X>
|
||||
struct is_pAsset : boost::false_type {};
|
||||
|
||||
template <class A>
|
||||
struct is_pAsset<shared_ptr<A> >
|
||||
: boost::is_base_of<Asset, A> {};
|
||||
|
||||
|
||||
/** marker constant denoting a NIL asset */
|
||||
template<class KIND>
|
||||
ID<KIND> ID<KIND>::INVALID = ID(0);
|
||||
|
||||
|
||||
/** convenient for debugging */
|
||||
inline string str (PcAsset const& a)
|
||||
{
|
||||
if (a)
|
||||
return string (*a.get());
|
||||
else
|
||||
return "Asset(NULL)";
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace asset
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -241,7 +241,7 @@ namespace asset {
|
|||
}
|
||||
|
||||
friend ostream& operator<< (ostream& os, EntryID const& id) { return os << string(id); }
|
||||
friend bool operator< (EntryID const& i1, EntryID const& i2) { return i1.getSym() < i2.getSym(); }
|
||||
friend bool operator< (EntryID const& i1, EntryID const& i2) { return i1.getSym() < i2.getSym(); }
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ namespace asset {
|
|||
* default wiring.
|
||||
*/
|
||||
Pipe::Pipe ( const Asset::Ident& idi
|
||||
, string const& streamID
|
||||
, string const& streamID ////////////////////////////////////////TICKET #648
|
||||
, PProcPatt& wiring
|
||||
, string shortName
|
||||
, string longName
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
#include "proc/asset/struct.hpp"
|
||||
#include "proc/asset/procpatt.hpp"
|
||||
#include "lib/streamtype.hpp"
|
||||
|
||||
#include <string>
|
||||
|
||||
|
|
@ -34,6 +35,7 @@
|
|||
namespace asset {
|
||||
|
||||
using lumiera::P;
|
||||
using lumiera::StreamType;
|
||||
using std::string;
|
||||
|
||||
class Pipe;
|
||||
|
|
@ -45,7 +47,16 @@ namespace asset {
|
|||
{
|
||||
public:
|
||||
ID (HashVal id);
|
||||
ID (const Pipe&);
|
||||
ID (Pipe const&);
|
||||
ID (PPipe const&);
|
||||
|
||||
/** allows a Pipe-ID to stand in for a full Pipe Asset
|
||||
* @throw error::Invalid when there is no corresponding Pipe */
|
||||
operator PPipe() const;
|
||||
|
||||
/** allows to fetch the StreamType directly just from a Pipe-ID
|
||||
* @throw error::Invalid when there is no corresponding Pipe */
|
||||
StreamType::ID streamType() const;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -59,7 +70,7 @@ namespace asset {
|
|||
: public Struct
|
||||
{
|
||||
PProcPatt wiringTemplate_;
|
||||
const string streamID_; ///< @todo just a placeholder for now 10/10
|
||||
StreamType::ID streamID_; ////////////////////////////////////////TICKET #648
|
||||
|
||||
public:
|
||||
string shortDesc;
|
||||
|
|
@ -78,7 +89,7 @@ namespace asset {
|
|||
|
||||
public:
|
||||
string const& getPipeID() const { return ident.name; }
|
||||
string const& getStreamID() const { return streamID_; }
|
||||
StreamType::ID getStreamID() const { return streamID_; } ////////////////////////////////////////TICKET #648
|
||||
PProcPatt const& getProcPatt() const { return wiringTemplate_; }
|
||||
|
||||
|
||||
|
|
@ -95,9 +106,21 @@ namespace asset {
|
|||
|
||||
// catch up with postponed definition of ID<Struct> ctors...
|
||||
//
|
||||
inline ID<Pipe>::ID(HashVal id) : ID<Struct> (id) {};
|
||||
inline ID<Pipe>::ID(Pipe const& pipe) : ID<Struct> (pipe.getID()) {};
|
||||
inline ID<Pipe>::ID(HashVal id) : ID<Struct> (id) {};
|
||||
inline ID<Pipe>::ID(Pipe const& pipe) : ID<Struct> (pipe.getID()) {};
|
||||
inline ID<Pipe>::ID(PPipe const& pipe) : ID<Struct> (pipe->getID()) {};
|
||||
|
||||
inline
|
||||
ID<Pipe>::operator PPipe() const
|
||||
{
|
||||
return Pipe::lookup(*this);
|
||||
}
|
||||
|
||||
inline StreamType::ID
|
||||
ID<Pipe>::streamType() const
|
||||
{
|
||||
return Pipe::lookup(*this)->getStreamID();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ namespace session {
|
|||
class Clip;
|
||||
|
||||
}}
|
||||
namespace lumiera {
|
||||
class StreamType;
|
||||
}
|
||||
|
||||
namespace asset{
|
||||
|
||||
|
|
@ -104,6 +107,12 @@ namespace asset{
|
|||
static Symbol catFolder() { return "pipes";}
|
||||
static Symbol idSymbol() { return "pipe"; }
|
||||
};
|
||||
template<> struct StructTraits<lumiera::StreamType>
|
||||
{
|
||||
static Symbol namePrefix() { return "type"; }
|
||||
static Symbol catFolder() { return "stream-types";}
|
||||
static Symbol idSymbol() { return "stype"; }
|
||||
};
|
||||
template<> struct StructTraits<const ProcPatt>
|
||||
{
|
||||
static Symbol namePrefix() { return "patt"; }
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ namespace asset {
|
|||
normaliseID (pipeID);
|
||||
normaliseID (streamID);
|
||||
static format descriptor("pipe(%s), stream(%s).");
|
||||
Pipe* pP = impl_->fabricate (Query<Pipe> (descriptor % pipeID % streamID));
|
||||
Pipe* pP = impl_->fabricate (Query<Pipe> (str(descriptor % pipeID % streamID)));
|
||||
return AssetManager::instance().wrap (*pP);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -79,6 +79,14 @@ namespace control {
|
|||
}
|
||||
|
||||
|
||||
/** */
|
||||
StreamType const&
|
||||
STypeManager::getType (StreamType::ID stID)
|
||||
{
|
||||
UNIMPLEMENTED ("get type just by symbolic ID (query defaults manager)");
|
||||
}
|
||||
|
||||
|
||||
StreamType const&
|
||||
STypeManager::getType (StreamType::Prototype const& protoType)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ namespace control {
|
|||
* just a symbolic ID. Effectively this queries a default */
|
||||
StreamType const& getType (Symbol sTypeID) ;
|
||||
|
||||
StreamType const& getType (StreamType::ID stID) ;
|
||||
|
||||
/** build or retrieve a complete StreamType implementing the given Prototype */
|
||||
StreamType const& getType (StreamType::Prototype const& protoType) ;
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
/** @file styperegistry.hpp
|
||||
** This is part of the \i implementation of the stream type manager (include).
|
||||
** Only used in stypemanager.cpp and accompaning unit tests.
|
||||
** Only used in stypemanager.cpp and accompanying unit tests.
|
||||
**
|
||||
** @see control::STypeManager
|
||||
** @see lumiera::StreamType
|
||||
|
|
@ -62,7 +62,7 @@ namespace control {
|
|||
|
||||
|
||||
/**
|
||||
* @internal Helper for organizing preconfigured default objects.
|
||||
* @internal Helper for organising preconfigured default objects.
|
||||
* Maintaines a collection of objects known or encountered as "default"
|
||||
* for a given type. This collection is ordered by "degree of constriction",
|
||||
* which is implemented by counting the number of predicates in the query
|
||||
|
|
|
|||
|
|
@ -24,10 +24,10 @@
|
|||
#include "proc/engine/renderengine.hpp"
|
||||
|
||||
namespace engine {
|
||||
|
||||
|
||||
|
||||
|
||||
/** */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace engine
|
||||
|
|
|
|||
|
|
@ -32,19 +32,26 @@
|
|||
using std::list;
|
||||
|
||||
|
||||
namespace engine
|
||||
{
|
||||
|
||||
|
||||
namespace engine {
|
||||
|
||||
|
||||
/**
|
||||
* @todo this is planned to become the frontend
|
||||
* to the render node network, which can be considered
|
||||
* at the lower end of the middle layer; the actual
|
||||
* render operations are mostly implemented by the backend
|
||||
* ////////TODO WIP as of 12/2010
|
||||
*/
|
||||
class RenderEngine : public RenderGraph
|
||||
{
|
||||
public:
|
||||
///// TODO: find out about the public operations
|
||||
// note: the play controller lives in the backend
|
||||
|
||||
// note: the play controller lives in the proc-layer,
|
||||
// but is a subsystem separate of the sesison.
|
||||
|
||||
private:
|
||||
list<RenderGraph> renderSegments;
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // namespace engine
|
||||
|
|
|
|||
|
|
@ -26,17 +26,17 @@
|
|||
#include "proc/state.hpp"
|
||||
|
||||
namespace lumiera {
|
||||
|
||||
|
||||
/** storage for the unique node-ID counter */
|
||||
ulong NodeID::currID (0);
|
||||
}
|
||||
|
||||
|
||||
namespace engine {
|
||||
|
||||
|
||||
/** */
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace engine
|
||||
|
|
|
|||
|
|
@ -29,25 +29,27 @@
|
|||
|
||||
|
||||
|
||||
namespace engine
|
||||
{
|
||||
|
||||
namespace engine {
|
||||
|
||||
class ExitNode;
|
||||
|
||||
|
||||
/**
|
||||
* @todo likely to be reworked into the engine backbone /////////////TODO WIP as of 12/2010
|
||||
*/
|
||||
class RenderGraph
|
||||
{
|
||||
protected:
|
||||
ExitNode * output;
|
||||
|
||||
|
||||
/** begin of the timerange covered by this RenderGraph */
|
||||
lumiera::Time start;
|
||||
|
||||
|
||||
/**end (exclusive) of the timerange */
|
||||
lumiera::Time end;
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace engine
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
|
||||
|
||||
namespace mobject {
|
||||
|
||||
|
||||
class Buildable;
|
||||
|
||||
namespace builder {
|
||||
|
|
@ -105,7 +105,7 @@ namespace mobject {
|
|||
* as we simply store a pointer within the BuilderTool instance.
|
||||
*/
|
||||
class BuilderTool
|
||||
: public lumiera::visitor::Tool<void, InvokeCatchAllFunction>
|
||||
: public lumiera::visitor::Tool<void, InvokeCatchAllFunction>
|
||||
{
|
||||
lumiera::WrapperPtr currentWrapper_;
|
||||
|
||||
|
|
@ -172,7 +172,9 @@ namespace mobject {
|
|||
|
||||
using lumiera::typelist::Types; // convenience for the users of "Applicable"
|
||||
|
||||
} // namespace mobject::builder
|
||||
}// namespace mobject::builder
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -185,8 +187,15 @@ namespace mobject {
|
|||
|
||||
|
||||
|
||||
namespace builder { // to be found by ADL
|
||||
namespace builder {
|
||||
|
||||
/** to be picked up by ADL: redirect tool invocation for double dispatch.
|
||||
* The purpose of this function is to apply a visitor, while the actual target
|
||||
* is managed by a generic wrapper (smart-ptr). This template function serves
|
||||
* to generate forwarding functions, which pass on the \c apply() call to the
|
||||
* actual embedded target, while passing on the fully wrapped object for later
|
||||
* referral and usage too.
|
||||
*/
|
||||
template<typename WRA>
|
||||
inline Buildable::ReturnType
|
||||
apply (BuilderTool& tool, WRA& wrappedTargetObj)
|
||||
|
|
@ -195,8 +204,7 @@ namespace mobject {
|
|||
wrappedTargetObj->apply (tool); // dispatch to suitable treat() function
|
||||
tool.forgetWrapper();
|
||||
}
|
||||
|
||||
} // namespace mobject::builder
|
||||
|
||||
} // namespace mobject
|
||||
|
||||
}} // namespace mobject::builder
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,25 +24,14 @@
|
|||
#ifndef MOBJECT_BUILDER_COMMON_H
|
||||
#define MOBJECT_BUILDER_COMMON_H
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "include/logging.h"
|
||||
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
namespace builder {
|
||||
|
||||
|
||||
// TODO NOBUG_DECLARE_FLAG (builder_mem);
|
||||
|
||||
|
||||
} // namespace builder
|
||||
|
||||
} // namespace mobject
|
||||
}} // namespace mobject::builder
|
||||
#endif
|
||||
|
||||
/*
|
||||
// Local Variables:
|
||||
// mode: C
|
||||
// c-file-style: "gnu"
|
||||
// indent-tabs-mode: nil
|
||||
// End:
|
||||
*/
|
||||
|
|
|
|||
81
src/proc/mobject/builder/fixture-change-detector.hpp
Normal file
81
src/proc/mobject/builder/fixture-change-detector.hpp
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
/*
|
||||
FIXTURE-CHANGE-DETECTOR.hpp - isolating changed segments and tainted processes
|
||||
|
||||
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 fixture-change-detector.hpp
|
||||
** Work out the part of the Fixture changed by a build process.
|
||||
** This facility helps to deal with ongoing render/playback processes, which might be
|
||||
** affected by the results of a build process. It's comprised of two distinct parts:
|
||||
** - a comparison tool allowing to spot equal and changed segments when considering
|
||||
** the old and the new version of the fixture before/after a build process.
|
||||
** - a registration service to establish a relation between play/render processes
|
||||
** and specific segments of the fixture.
|
||||
** Together, these allow to identify those ongoing processes which need to be cancelled
|
||||
** or restarted, because their results might be tainted by the changes induced by the
|
||||
** build process. Typically, these detection process runs just before commiting the
|
||||
** newly built fixture datastructure.
|
||||
**
|
||||
** @todo WIP-WIP-WIP as of 12/2010
|
||||
**
|
||||
** @see Fixture
|
||||
** @see ModelPort
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PROC_MOBJECT_BUILDER_FIXTURE_CHANGE_DETECTOR_H
|
||||
#define PROC_MOBJECT_BUILDER_FIXTURE_CHANGE_DETECTOR_H
|
||||
|
||||
#include "lib/error.hpp"
|
||||
//#include "lib/optional-ref.hpp"
|
||||
#include "proc/asset/pipe.hpp"
|
||||
//#include "proc/asset/struct.hpp"
|
||||
//#include "proc/mobject/model-port.hpp"
|
||||
|
||||
//#include <map>
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
|
||||
using asset::ID;
|
||||
using asset::Pipe;
|
||||
//using asset::Struct;
|
||||
|
||||
//LUMIERA_ERROR_DECLARE (DUPLICATE_MODEL_PORT); ///< Attempt to define a new model port with an pipe-ID already denoting an existing port
|
||||
|
||||
|
||||
/**
|
||||
* TODO type comment
|
||||
*/
|
||||
class FixtureChangeDetector
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
typedef ID<Pipe> PID;
|
||||
// typedef ID<Struct> StID;
|
||||
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}} // namespace mobject::builder
|
||||
#endif
|
||||
302
src/proc/mobject/builder/model-port-registry.cpp
Normal file
302
src/proc/mobject/builder/model-port-registry.cpp
Normal file
|
|
@ -0,0 +1,302 @@
|
|||
/*
|
||||
ModelPortRegistry - creating and organising and accessing model ports
|
||||
|
||||
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 model-port-registry.cpp
|
||||
** Implementation details of model port descriptors and references.
|
||||
** Essentially the handling of the ModelPortRegistry datastructure is
|
||||
** kept an opaque implementation detail and confined entirely within
|
||||
** this translation unit. Both the client interface (ModelPort) and
|
||||
** the management interface (ModelPortRegistry) are backed by this
|
||||
** common translation unit.
|
||||
**
|
||||
** @see OutputDesignation
|
||||
** @see OutputMapping
|
||||
** @see Timeline
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "include/logging.h"
|
||||
#include "lib/sync-classlock.hpp"
|
||||
#include "proc/mobject/builderfacade.hpp"
|
||||
#include "proc/mobject/model-port.hpp"
|
||||
#include "proc/mobject/builder/model-port-registry.hpp"
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
|
||||
namespace error = lumiera::error;
|
||||
|
||||
|
||||
typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor;
|
||||
typedef lib::ClassLock<ModelPortRegistry> LockRegistry;
|
||||
|
||||
|
||||
/** storage for the link to the global
|
||||
Registry instance currently in charge */
|
||||
lib::OptionalRef<ModelPortRegistry> ModelPortRegistry::theGlobalRegistry;
|
||||
|
||||
|
||||
|
||||
/** globally deactivate access to model ports */
|
||||
void
|
||||
ModelPortRegistry::shutdown ()
|
||||
{
|
||||
INFO (builder, "disabling ModelPort registry....");
|
||||
LockRegistry global_lock;
|
||||
theGlobalRegistry.clear();
|
||||
}
|
||||
|
||||
|
||||
/** switch the implicit link to \em the global ModelPort registry
|
||||
* to point to the given implementation instance. Typically used
|
||||
* within the Builder subsystem lifecycle methods, or for
|
||||
* temporarily exchanging the registry for unit tests
|
||||
* @return the registry instance previously in use or \c NULL
|
||||
*/
|
||||
ModelPortRegistry*
|
||||
ModelPortRegistry::setActiveInstance (ModelPortRegistry& newRegistry)
|
||||
{
|
||||
LockRegistry global_lock;
|
||||
ModelPortRegistry *previous = theGlobalRegistry.isValid()?
|
||||
&( theGlobalRegistry()) : 0;
|
||||
INFO_IF (!previous, builder, "activating new ModelPort registry.");
|
||||
WARN_IF ( previous, builder, "switching ModelPort registry instance.");
|
||||
theGlobalRegistry.link_to (newRegistry);
|
||||
return previous;
|
||||
}
|
||||
|
||||
|
||||
/** access the globally valid registry instance.
|
||||
* @throw error::State if this global registry is
|
||||
* already closed or not yet initialised. */
|
||||
ModelPortRegistry&
|
||||
ModelPortRegistry::globalInstance()
|
||||
{
|
||||
LockRegistry global_lock;
|
||||
if (theGlobalRegistry.isValid())
|
||||
return theGlobalRegistry();
|
||||
|
||||
throw error::State ("global model port registry is not accessible"
|
||||
, LUMIERA_ERROR_BUILDER_LIFECYCLE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** does the <i>transaction currently being built</i>
|
||||
* already contain a model port registration for the given ID?
|
||||
* @note this does \em not query registration state of the
|
||||
* global registry; use #isRegistered for that...*/
|
||||
bool
|
||||
ModelPortRegistry::contains (ID<Pipe> key) const
|
||||
{
|
||||
return bool(key)
|
||||
&& util::contains (transaction_, key);
|
||||
}
|
||||
|
||||
|
||||
/** @return true if the given pipe-ID actually denotes an
|
||||
* existing, connected and usable model port.
|
||||
* @note reflects the state of the publicly visible
|
||||
* model port registry, \em not any model ports
|
||||
* being registered within a pending transaction
|
||||
* (ongoing build process). */
|
||||
bool
|
||||
ModelPortRegistry::isRegistered (ID<Pipe> key) const
|
||||
{
|
||||
return bool(key)
|
||||
&& util::contains (currentReg_, key);
|
||||
}
|
||||
|
||||
|
||||
/** basic access operation: access the descriptor
|
||||
* of a currently valid model port.
|
||||
* @note no locking (but #accessDescriptor does lock!)
|
||||
* @throw error::Logic if accessing a non registered port
|
||||
* @throw error::State if accessing an invalid / disconnected port
|
||||
*/
|
||||
MPDescriptor
|
||||
ModelPortRegistry::get (ID<Pipe> key) const
|
||||
{
|
||||
if (!key)
|
||||
throw error::State ("This model port is disconnected or NIL"
|
||||
, LUMIERA_ERROR_UNCONNECTED_MODEL_PORT);
|
||||
if (!isRegistered (key))
|
||||
throw error::Logic ("Model port was never registered, or got unregistered meanwhile."
|
||||
,LUMIERA_ERROR_INVALID_MODEL_PORT);
|
||||
|
||||
MPTable::const_iterator pos = currentReg_.find (key);
|
||||
ASSERT (pos != currentReg_.end());
|
||||
ASSERT (pos->second.isValid());
|
||||
return pos->second;
|
||||
}
|
||||
|
||||
|
||||
/** access \em the globally valid model port for the given pipe.
|
||||
* This (static) function locks and accesses the global model port registry
|
||||
* to fetch the descriptor record. Typically invoked by client code
|
||||
* through the ModelPort frontend
|
||||
* @throw error::State when registry is down or the model port is disconnected
|
||||
* @throw error::Logic when the given key wasn't registered for a model port */
|
||||
MPDescriptor
|
||||
ModelPortRegistry::accessDescriptor (ID<Pipe> key)
|
||||
{
|
||||
LockRegistry global_lock;
|
||||
return theGlobalRegistry().get(key);
|
||||
}
|
||||
|
||||
|
||||
/* === Mutations === */
|
||||
|
||||
/** create and register a new model port entry,
|
||||
* within the pending transaction */
|
||||
MPDescriptor
|
||||
ModelPortRegistry::definePort (ID<Pipe> pipe, ID<Struct> element_exposing_this_port)
|
||||
{
|
||||
LockRegistry global_lock;
|
||||
if (contains (pipe))
|
||||
throw error::Logic ("attempt to register a model port with a pipe-ID, "
|
||||
"which has already been used to register a "
|
||||
"model port within this transaction (build process)."
|
||||
, LUMIERA_ERROR_DUPLICATE_MODEL_PORT);
|
||||
return (transaction_[pipe] = ModelPortDescriptor(pipe, element_exposing_this_port));
|
||||
}
|
||||
|
||||
|
||||
/** remove a model port entry from the pending transaction */
|
||||
void
|
||||
ModelPortRegistry::remove (PID key)
|
||||
{
|
||||
LockRegistry global_lock;
|
||||
transaction_.erase (key);
|
||||
}
|
||||
|
||||
|
||||
/** schedule removal of all registry contents.
|
||||
* When the currently pending transaction is committed,
|
||||
* all registered model ports will be removed */
|
||||
void
|
||||
ModelPortRegistry::clear()
|
||||
{
|
||||
LockRegistry global_lock;
|
||||
transaction_.clear();
|
||||
}
|
||||
|
||||
|
||||
/** transactional switch for new/modified model ports.
|
||||
* Promote the registered model ports from the currently
|
||||
* pending transaction to become the globally valid model ports
|
||||
* @note automatically starts a new transaction, initialised
|
||||
* with the now published mappings.
|
||||
*/
|
||||
void
|
||||
ModelPortRegistry::commit()
|
||||
{
|
||||
LockRegistry global_lock;
|
||||
MPTable newTransaction(transaction_);
|
||||
TRACE (builder, "committing new ModelPort list....");
|
||||
swap (currentReg_, transaction_);
|
||||
swap (transaction_, newTransaction);
|
||||
}
|
||||
|
||||
|
||||
/** discard current transaction.
|
||||
* The global port registration thus
|
||||
* remains unaltered. */
|
||||
void
|
||||
ModelPortRegistry::rollback()
|
||||
{
|
||||
LockRegistry global_lock;
|
||||
TRACE (builder, "discarding changes to ModelPort list (rollback)....");
|
||||
MPTable newTransaction(currentReg_);
|
||||
swap (transaction_, newTransaction);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LUMIERA_ERROR_DEFINE (DUPLICATE_MODEL_PORT, "Attempt to define a new model port with an pipe-ID already denoting an existing port");
|
||||
|
||||
}// namespace builder
|
||||
|
||||
|
||||
|
||||
|
||||
LUMIERA_ERROR_DEFINE (INVALID_MODEL_PORT, "Referral to unknown model port");
|
||||
LUMIERA_ERROR_DEFINE (UNCONNECTED_MODEL_PORT, "Attempt to operate on an existing but unconnected model port");
|
||||
|
||||
|
||||
ModelPort::ModelPort (ID<asset::Pipe> refID)
|
||||
: id_(refID)
|
||||
{
|
||||
builder::ModelPortRegistry::accessDescriptor (refID);
|
||||
}
|
||||
|
||||
|
||||
/** check if the global model port registration
|
||||
* contains a mapping for the given pipe-ID*/
|
||||
bool
|
||||
ModelPort::exists (ID<asset::Pipe> key)
|
||||
{
|
||||
return builder::ModelPortRegistry::globalInstance().isRegistered (key);
|
||||
}
|
||||
|
||||
|
||||
/** access the Pipe (ID) of the global model port registered
|
||||
* with the ID underlying this model port.
|
||||
* @throw error::Logic if no model port is registered for this Pipe-ID
|
||||
*/
|
||||
ID<asset::Pipe>
|
||||
ModelPort::pipe() const
|
||||
{
|
||||
ENSURE (this->id_ == builder::ModelPortRegistry::accessDescriptor(this->id_).id());
|
||||
|
||||
return builder::ModelPortRegistry::accessDescriptor(this->id_).id();
|
||||
}
|
||||
|
||||
|
||||
/** access the timeline (or similar structural element) holding
|
||||
* a global pipe which corresponds to this model port
|
||||
* @throw error::Logic if no model port is registered for this Pipe-ID
|
||||
*/
|
||||
ID<asset::Struct>
|
||||
ModelPort::holder() const
|
||||
{
|
||||
return builder::ModelPortRegistry::accessDescriptor(this->id_).holder();
|
||||
}
|
||||
|
||||
|
||||
/** convenience shortcut to access the stream type
|
||||
* associated with the pipe-ID corresponding to this model port.
|
||||
* @note no check if this model port actually is valid
|
||||
* @throw error::Invalid in case of unknown/unregistered Pipe-ID
|
||||
*/
|
||||
StreamType::ID
|
||||
ModelPort::streamType() const
|
||||
{
|
||||
return this->id_.streamType();
|
||||
}
|
||||
|
||||
|
||||
|
||||
} // namespace mobject
|
||||
181
src/proc/mobject/builder/model-port-registry.hpp
Normal file
181
src/proc/mobject/builder/model-port-registry.hpp
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
MODEL-PORT-REGISTRY.hpp - creating and organising and accessing model ports
|
||||
|
||||
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 model-port-registry.hpp
|
||||
** Mutation and management facility for model ports within the builder.
|
||||
** Model ports denote the points where output might possibly be produced.
|
||||
** While client code accesses model ports only as immutable descriptors handled
|
||||
** through an (opaque) reference, the builder is in charge of detecting and organising
|
||||
** any (new) model ports arising as the result of the build process. Changes to the set
|
||||
** of current model ports are to be activated with an atomic <i>transactional switch.</i>
|
||||
**
|
||||
** builder::ModelPortRegistry thus acts as management interface and factory for model ports.
|
||||
** A given instance of this registry can be promoted to be "the" model port registry reflecting
|
||||
** the current active model ports. Within the Lumiera application, the builder subsystem cares
|
||||
** for setting up such a registry, while all other parts of the system just access the current
|
||||
** model ports through the mobject::ModelPort frontend.
|
||||
**
|
||||
** @note the locking is rather coarse grained; basically we're using just one
|
||||
** single global lock for all ModelPortRegistry instances and all access/mutations,
|
||||
** as well as for accessing the globally valid Registry through the ModelPort frontend.
|
||||
** Assumed that usually there is just one Registry maintained by the builder, this is
|
||||
** likely to be sufficient.
|
||||
**
|
||||
** @see ModelPort
|
||||
** @see OutputDesignation
|
||||
** @see ModelPortRegistry_test
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PROC_MOBJECT_BUILDER_MODEL_PORT_REGISTRY_H
|
||||
#define PROC_MOBJECT_BUILDER_MODEL_PORT_REGISTRY_H
|
||||
|
||||
#include "lib/error.hpp"
|
||||
#include "lib/optional-ref.hpp"
|
||||
#include "proc/asset/pipe.hpp"
|
||||
#include "proc/asset/struct.hpp"
|
||||
#include "proc/mobject/model-port.hpp"
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
|
||||
using asset::ID;
|
||||
using asset::Pipe;
|
||||
using asset::Struct;
|
||||
|
||||
LUMIERA_ERROR_DECLARE (DUPLICATE_MODEL_PORT); ///< Attempt to define a new model port with an pipe-ID already denoting an existing port
|
||||
|
||||
|
||||
/**
|
||||
* Management facility for tracking model ports.
|
||||
* ModelPort handles are exposed as frontend for usage
|
||||
* by client code. Model ports are discovered by the builder
|
||||
* when re-creating the low-level model; during such an ongoing
|
||||
* build process, newly discovered ports are accumulated within
|
||||
* a transaction, which then gets committed atomically when the
|
||||
* new model is complete and ready for use.
|
||||
*/
|
||||
class ModelPortRegistry
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
typedef ID<Pipe> PID;
|
||||
typedef ID<Struct> StID;
|
||||
|
||||
public:
|
||||
|
||||
/** @internal record to describe a model port */
|
||||
struct ModelPortDescriptor;
|
||||
|
||||
|
||||
static void shutdown ();
|
||||
|
||||
static ModelPortRegistry*
|
||||
setActiveInstance (ModelPortRegistry& newRegistry);
|
||||
|
||||
static ModelPortRegistry&
|
||||
globalInstance();
|
||||
|
||||
static ModelPortDescriptor const&
|
||||
accessDescriptor (PID);
|
||||
|
||||
|
||||
ModelPortDescriptor const&
|
||||
definePort (PID pipe, StID element_exposing_this_port);
|
||||
|
||||
bool contains (PID) const;
|
||||
bool isRegistered (PID) const;
|
||||
|
||||
ModelPortDescriptor const&
|
||||
get (PID) const;
|
||||
|
||||
|
||||
void remove (PID);
|
||||
void clear();
|
||||
|
||||
|
||||
/** activate pending model port changes.
|
||||
* Any accumulated changes and newly defined model ports
|
||||
* are promoted to become part of the current active configuration
|
||||
* with a single atomic (transactional) switch.
|
||||
*/
|
||||
void commit();
|
||||
|
||||
/** discard pending changes.
|
||||
* Silently drop model port definition changes since the last commit.
|
||||
*/
|
||||
void rollback();
|
||||
|
||||
|
||||
private:
|
||||
static lib::OptionalRef<ModelPortRegistry> theGlobalRegistry;
|
||||
|
||||
typedef std::map<PID, ModelPortDescriptor> MPTable;
|
||||
|
||||
MPTable currentReg_;
|
||||
MPTable transaction_;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** ModelPortDescriptor records are used as actual storage
|
||||
* within the model port registration table; they are immutable
|
||||
* value objects and never exposed to client code directly.
|
||||
*/
|
||||
class ModelPortRegistry::ModelPortDescriptor
|
||||
{
|
||||
PID id_;
|
||||
StID holder_;
|
||||
|
||||
protected:
|
||||
ModelPortDescriptor (PID pipe, StID element_exposing_this_port)
|
||||
: id_(pipe)
|
||||
, holder_(element_exposing_this_port)
|
||||
{ }
|
||||
|
||||
friend class ModelPortRegistry;
|
||||
|
||||
public:
|
||||
ModelPortDescriptor()
|
||||
: id_(PID::INVALID)
|
||||
, holder_(StID::INVALID)
|
||||
{ }
|
||||
|
||||
// default copy operations permitted
|
||||
|
||||
bool
|
||||
isValid() const
|
||||
{
|
||||
return bool(id_);
|
||||
}
|
||||
|
||||
const PID id() const { return id_; }
|
||||
const StID holder() const { return holder_; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
}} // namespace mobject::builder
|
||||
#endif
|
||||
|
|
@ -21,7 +21,7 @@
|
|||
* *****************************************************/
|
||||
|
||||
|
||||
#include "proc/mobject/builder/segmentationtool.hpp"
|
||||
#include "proc/mobject/builder/segmentation-tool.hpp"
|
||||
|
||||
|
||||
using mobject::Buildable;
|
||||
|
|
@ -30,52 +30,50 @@ using mobject::session::Effect;
|
|||
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
|
||||
/////////////////////////////////TICKET #414
|
||||
|
||||
namespace builder {
|
||||
|
||||
SegmentationTool::SegmentationTool(mobject::session::Fixture&)
|
||||
{
|
||||
UNIMPLEMENTED ("create new SegmentationTool");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SegmentationTool::treat (Buildable& something)
|
||||
{
|
||||
UNIMPLEMENTED ("??? when partitioning timeline");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SegmentationTool::treat (Clip& clip)
|
||||
{
|
||||
UNIMPLEMENTED ("consider clip when partitioning timeline");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SegmentationTool::treat (Effect& effect)
|
||||
{
|
||||
UNIMPLEMENTED ("note applied effect when partitioning timeline");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SegmentationTool::onUnknown (Buildable& target)
|
||||
{
|
||||
UNIMPLEMENTED ("catch-all when partitioning timeline");
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SegmentationTool::empty() const
|
||||
{
|
||||
UNIMPLEMENTED ("detect an empty segmentation");
|
||||
}
|
||||
|
||||
|
||||
} // namespace mobject::builder
|
||||
|
||||
} // namespace mobject
|
||||
/////////////////////////////////TICKET #414
|
||||
|
||||
|
||||
SegmentationTool::SegmentationTool(mobject::session::Fixture&)
|
||||
{
|
||||
UNIMPLEMENTED ("create new SegmentationTool");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SegmentationTool::treat (Buildable& something)
|
||||
{
|
||||
UNIMPLEMENTED ("??? when partitioning timeline");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SegmentationTool::treat (Clip& clip)
|
||||
{
|
||||
UNIMPLEMENTED ("consider clip when partitioning timeline");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SegmentationTool::treat (Effect& effect)
|
||||
{
|
||||
UNIMPLEMENTED ("note applied effect when partitioning timeline");
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
SegmentationTool::onUnknown (Buildable& target)
|
||||
{
|
||||
UNIMPLEMENTED ("catch-all when partitioning timeline");
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
SegmentationTool::empty() const
|
||||
{
|
||||
UNIMPLEMENTED ("detect an empty segmentation");
|
||||
}
|
||||
|
||||
|
||||
}} // namespace mobject::builder
|
||||
78
src/proc/mobject/builder/segmentation-tool.hpp
Normal file
78
src/proc/mobject/builder/segmentation-tool.hpp
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
SEGMENTATION-TOOL.hpp - Tool for creating a partitioning of the current timeline
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, 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 MOBJECT_BUILDER_SEGMENTATION_TOOL_H
|
||||
#define MOBJECT_BUILDER_SEGMENTATION_TOOL_H
|
||||
|
||||
|
||||
#include "proc/mobject/builder/applicable-builder-target-types.hpp"
|
||||
|
||||
#include "proc/mobject/session/segmentation.hpp"
|
||||
#include "proc/mobject/session/fixture.hpp" //////TODO really on the header??
|
||||
|
||||
|
||||
#include <list>
|
||||
using std::list;
|
||||
|
||||
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
|
||||
|
||||
/**
|
||||
* Tool implementation for deriving a partitioning of the current
|
||||
* timeline, such that each Segment has a constant configuration.
|
||||
* "Constant" means here, that any remaining changes over time
|
||||
* can be represented by automation solely, without the need
|
||||
* to change the node connections.
|
||||
*/
|
||||
class SegmentationTool
|
||||
: public ApplicableBuilderTargetTypes<SegmentationTool>
|
||||
{
|
||||
|
||||
public:
|
||||
SegmentationTool (session::Fixture &) ;
|
||||
|
||||
void treat (mobject::session::Clip& clip) ;
|
||||
void treat (mobject::session::Effect& effect) ;
|
||||
|
||||
void treat (mobject::Buildable& something) ;
|
||||
|
||||
void onUnknown (Buildable& target) ; /////////TODO why doesn't the treat(Buildable) function shadow this??
|
||||
|
||||
bool empty() const;
|
||||
|
||||
private:
|
||||
typedef mobject::session::Segment Segment;
|
||||
|
||||
/** Partitioning of the Timeline to be created by this tool. */
|
||||
//session::Segmentation& segments_;
|
||||
///////////////////////////////////////////TODO: either put it inline, or use a scopend_ptr!!!!!!!!!!
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
}} // namespace mobject::builder
|
||||
#endif
|
||||
85
src/proc/mobject/builder/segmentation.cpp
Normal file
85
src/proc/mobject/builder/segmentation.cpp
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
Segmentation - partitioning the effective timeline
|
||||
|
||||
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 segmentation.cpp
|
||||
** Implementation details of fixture data structures.
|
||||
**
|
||||
** /////TODO file comment necessary?
|
||||
**
|
||||
** @see mobject::session::Fixture
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#include "lib/error.hpp"
|
||||
//#include "include/logging.h"
|
||||
//#include "lib/sync-classlock.hpp"
|
||||
//#include "proc/mobject/builderfacade.hpp"
|
||||
#include "proc/mobject/builder/segmentation.hpp"
|
||||
#include "proc/mobject/builder/fixture-change-detector.hpp"
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
|
||||
namespace error = lumiera::error;
|
||||
|
||||
|
||||
// typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor;
|
||||
|
||||
|
||||
/** storage for the link to the global
|
||||
Registry instance currently in charge */
|
||||
// lib::OptionalRef<ModelPortRegistry> ModelPortRegistry::theGlobalRegistry;
|
||||
|
||||
|
||||
/** access the globally valid registry instance.
|
||||
* @throw error::State if this global registry is
|
||||
* already closed or not yet initialised. */
|
||||
//ModelPortRegistry&
|
||||
//ModelPortRegistry::globalInstance()
|
||||
//{
|
||||
// LockRegistry global_lock;
|
||||
// if (theGlobalRegistry.isValid())
|
||||
// return theGlobalRegistry();
|
||||
//
|
||||
// throw error::State ("global model port registry is not accessible"
|
||||
// , LUMIERA_ERROR_BUILDER_LIFECYCLE);
|
||||
//}
|
||||
|
||||
|
||||
|
||||
/** */
|
||||
// bool
|
||||
// ModelPortRegistry::contains (ID<Pipe> key) const
|
||||
// {
|
||||
// return bool(key)
|
||||
// && util::contains (transaction_, key);
|
||||
// }
|
||||
|
||||
|
||||
|
||||
//LUMIERA_ERROR_DEFINE (DUPLICATE_MODEL_PORT, "Attempt to define a new model port with an pipe-ID already denoting an existing port");
|
||||
|
||||
|
||||
|
||||
}}// namespace mobject::builder
|
||||
87
src/proc/mobject/builder/segmentation.hpp
Normal file
87
src/proc/mobject/builder/segmentation.hpp
Normal file
|
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
SEGMENTATION.hpp - partitioning the effective timeline
|
||||
|
||||
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 segmentation.hpp
|
||||
** Part of the Fixture datastructure to manage time segments of constant structure.
|
||||
** The Fixture is result of the build process and separation between high-level and
|
||||
** low-level model. It's kind of an effective resulting timeline, and split into segments
|
||||
** of constant wiring structure: whenever the processing nodes need to be wired differently
|
||||
** for some timespan, we start a new segment of the timeline. This might be for the duration
|
||||
** of a clip, or just for the duration of a transition, when the pipes of both clips need to
|
||||
** be wired up in parallel.
|
||||
**
|
||||
** @see Fixture
|
||||
** @see ModelPort
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PROC_MOBJECT_BUILDER_SEGMENTATION_H
|
||||
#define PROC_MOBJECT_BUILDER_SEGMENTATION_H
|
||||
|
||||
#include "lib/error.hpp"
|
||||
//#include "lib/optional-ref.hpp"
|
||||
#include "proc/asset/pipe.hpp"
|
||||
//#include "proc/asset/struct.hpp"
|
||||
//#include "proc/mobject/model-port.hpp"
|
||||
|
||||
//#include <map>
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
|
||||
using asset::ID;
|
||||
using asset::Pipe;
|
||||
//using asset::Struct;
|
||||
|
||||
//LUMIERA_ERROR_DECLARE (DUPLICATE_MODEL_PORT); ///< Attempt to define a new model port with an pipe-ID already denoting an existing port
|
||||
|
||||
|
||||
/**
|
||||
* TODO type comment
|
||||
*/
|
||||
class Segment
|
||||
: boost::noncopyable
|
||||
{
|
||||
|
||||
typedef ID<Pipe> PID;
|
||||
// typedef ID<Struct> StID;
|
||||
|
||||
public:
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* TODO type comment
|
||||
*/
|
||||
class Segmentation
|
||||
{
|
||||
|
||||
public:
|
||||
};
|
||||
|
||||
|
||||
|
||||
}} // namespace mobject::builder
|
||||
#endif
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
/*
|
||||
SEGMENTATIONTOOL.hpp - Tool for creating a partitioning of the current timeline
|
||||
|
||||
Copyright (C) Lumiera.org
|
||||
2008, 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 MOBJECT_BUILDER_SEGMENTATIONTOOL_H
|
||||
#define MOBJECT_BUILDER_SEGMENTATIONTOOL_H
|
||||
|
||||
|
||||
#include "proc/mobject/builder/applicable-builder-target-types.hpp"
|
||||
|
||||
#include "proc/mobject/session/segmentation.hpp"
|
||||
#include "proc/mobject/session/fixture.hpp" //////TODO really on the header??
|
||||
|
||||
|
||||
#include <list>
|
||||
using std::list;
|
||||
|
||||
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
|
||||
|
||||
/**
|
||||
* Tool implementation for deriving a partitioning of the current
|
||||
* timeline, such that each Segment has a constant configuration.
|
||||
* "Constant" means here, that any remaining changes over time
|
||||
* can be represented by automation solely, without the need
|
||||
* to change the node connections.
|
||||
*/
|
||||
class SegmentationTool
|
||||
: public ApplicableBuilderTargetTypes<SegmentationTool>
|
||||
{
|
||||
|
||||
public:
|
||||
SegmentationTool (session::Fixture &) ;
|
||||
|
||||
void treat (mobject::session::Clip& clip) ;
|
||||
void treat (mobject::session::Effect& effect) ;
|
||||
|
||||
void treat (mobject::Buildable& something) ;
|
||||
|
||||
void onUnknown (Buildable& target) ; /////////TODO why doesn't the treat(Buildable) function shadow this??
|
||||
|
||||
bool empty() const;
|
||||
|
||||
private:
|
||||
typedef mobject::session::Segment Segment;
|
||||
|
||||
/** Partitioning of the Timeline to be created by this tool. */
|
||||
//session::Segmentation& segments_;
|
||||
///////////////////////////////////////////TODO: either put it inline, or use a scopend_ptr!!!!!!!!!!
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace mobject::builder
|
||||
|
||||
} // namespace mobject
|
||||
#endif
|
||||
|
|
@ -25,7 +25,7 @@
|
|||
#define MOBJECT_BUILDER_TOOLFACTORY_H
|
||||
|
||||
#include "proc/mobject/session/fixture.hpp"
|
||||
#include "proc/mobject/builder/segmentationtool.hpp"
|
||||
#include "proc/mobject/builder/segmentation-tool.hpp"
|
||||
#include "proc/mobject/builder/nodecreatortool.hpp"
|
||||
#include "proc/mobject/builder/mould.hpp"
|
||||
#include "proc/engine/rendergraph.hpp"
|
||||
|
|
|
|||
|
|
@ -26,12 +26,7 @@
|
|||
|
||||
namespace mobject {
|
||||
|
||||
namespace builder {
|
||||
using ::NOBUG_FLAG(memory);
|
||||
NOBUG_CPP_DEFINE_FLAG_PARENT(buildermem, memory);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Main Operation of the Builder:
|
||||
* create a render engine for a given part of the timeline
|
||||
|
|
@ -41,7 +36,10 @@ namespace mobject {
|
|||
{
|
||||
//////////////////////TODO
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
LUMIERA_ERROR_DEFINE (BUILDER_LIFECYCLE, "Builder activated while in non operational state");
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace mobject
|
||||
|
|
|
|||
|
|
@ -30,8 +30,9 @@
|
|||
|
||||
|
||||
namespace mobject {
|
||||
|
||||
|
||||
|
||||
LUMIERA_ERROR_DECLARE (BUILDER_LIFECYCLE); ///< Builder activated while in non operational state
|
||||
|
||||
/**
|
||||
* Provides unified access to the builder functionality.
|
||||
* While individual components of the builder subsystem may be called
|
||||
|
|
@ -44,12 +45,14 @@ namespace mobject {
|
|||
/**
|
||||
* Main Operation of the Builder:
|
||||
* create a render engine for a given part of the timeline
|
||||
* @deprecated thats a placeholder! the real invocation is now
|
||||
* in the course of being worked out ////////////TODO 12/2010
|
||||
*/
|
||||
engine::RenderEngine & buildEngine () ;
|
||||
// TODO: allocation, GC??????
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
} // namespace mobject
|
||||
#endif
|
||||
|
|
|
|||
152
src/proc/mobject/model-port.hpp
Normal file
152
src/proc/mobject/model-port.hpp
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
/*
|
||||
MODEL-PORT.hpp - point to pull output data from the model
|
||||
|
||||
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 model-port.hpp
|
||||
** Organising the output data calculation possibilities.
|
||||
** Model ports are conceptual entities, denoting the points where output might
|
||||
** possibly be produced. There is an actual representation, a collection of small
|
||||
** descriptor objects managed by the Fixture and organised within the registry
|
||||
** datastructure. Thus, while the actual ModelPort descriptor entities are located
|
||||
** within and managed by the Fixture -- model port as a concept spans the high-level
|
||||
** and low-level view. A model port can be associated both to a pipe within a timeline
|
||||
** in the HighLevelModel, as well as to denote a set of corresponding exit nodes within
|
||||
** the segments of the render nodes network. Model ports are keyed by Pipe-ID and thus
|
||||
** are bound to be unique within the application.
|
||||
**
|
||||
** A model port is rather derived than configured; it emerges during the build process
|
||||
** when a pipe claims an OutputDesignation and some other entity actually uses this
|
||||
** designation as a target, either directly or indirectly. This match of provision
|
||||
** and usage is detected by the Builder and produces an entry in the fixture's
|
||||
** ModelPortTable. Because of the 1:1 association with a pipe, each model port
|
||||
** has an associated StreamType.
|
||||
**
|
||||
** Because model ports are discovered this way, dynamically during the build process,
|
||||
** at some point there is a <i>transactional switch</i> to promote the new configuration
|
||||
** to become the valid current model port configuration. After that switch, model ports
|
||||
** are immutable.
|
||||
**
|
||||
** Model ports are to be accessed, enumerated and grouped in various ways, because
|
||||
** each port belongs to a specific timeline and is used to produce data of a single
|
||||
** StreamType solely. But all those referrals, searching and grouping happens only
|
||||
** after the build process has discovered all model ports currently available.
|
||||
** Thus actually the ModelPort elements handed out to client code are just
|
||||
** smart-handles, accessing a global ModelPortRegistry behind the scenes.
|
||||
** Validity of these handles will be checked on each access. The actual
|
||||
** model port descriptors are owned and managed by the fixture;
|
||||
** @todo they might bulk allocated in a similar manner than the
|
||||
** ProcNode and WiringDescriptor objects are.
|
||||
**
|
||||
** @see ModelPortRegistry_test abstract usage example
|
||||
** @see ModelPortRegistry management interface
|
||||
** @see OutputDesignation
|
||||
** @see OutputMapping
|
||||
** @see Timeline
|
||||
*/
|
||||
|
||||
|
||||
#ifndef PROC_MOBJECT_MODEL_PORT_H
|
||||
#define PROC_MOBJECT_MODEL_PORT_H
|
||||
|
||||
#include "proc/asset/pipe.hpp"
|
||||
#include "lib/bool-checkable.hpp"
|
||||
#include "lib/streamtype.hpp"
|
||||
|
||||
namespace mobject {
|
||||
|
||||
LUMIERA_ERROR_DECLARE (INVALID_MODEL_PORT); ///< Referral to unknown model port
|
||||
LUMIERA_ERROR_DECLARE (UNCONNECTED_MODEL_PORT); ///< Attempt to operate on an existing but unconnected model port
|
||||
|
||||
|
||||
using asset::ID;
|
||||
using lumiera::StreamType;
|
||||
|
||||
|
||||
/**
|
||||
* Handle denoting a point within the model,
|
||||
* where actually output data can be pulled.
|
||||
* ModelPort is a frontend to be used by clients.
|
||||
* These ModelPort handle objects may be copied and stored
|
||||
* at will, but their validity will be verified on each access.
|
||||
* Actually, the Builder will discover any model ports and
|
||||
* maintain a ModelPortRegistry behind the scenes.
|
||||
*
|
||||
* Each model port corresponds to a (global) pipe within a
|
||||
* specific Timeline ("holder"); consequently each such port is also
|
||||
* bound to produce data of a specific StreamType (as defined by
|
||||
* the corresponding pipe). A model port may be in \em unconnected
|
||||
* state, which can be checked through \c bool conversion. While
|
||||
* the ModelPort handles are value objects, the identity of the
|
||||
* underlying model port (descriptor) is given by the
|
||||
* corresponding pipe-ID, thus effectively resulting
|
||||
* in a global namespace for model ports.
|
||||
*
|
||||
* @see builder::ModelPortRegistry management interface
|
||||
* @see ModelPortRegistry_test abstract usage example
|
||||
*/
|
||||
class ModelPort
|
||||
: public lib::BoolCheckable<ModelPort>
|
||||
{
|
||||
ID<asset::Pipe> id_;
|
||||
|
||||
public:
|
||||
ModelPort() ///< \em unconnected model port
|
||||
: id_(ID<asset::Pipe>::INVALID)
|
||||
{ }
|
||||
|
||||
ModelPort (ID<asset::Pipe> refID); ///< @note conversion from pipe-ID
|
||||
|
||||
// using default copy operations
|
||||
|
||||
|
||||
static bool exists (ID<asset::Pipe>);
|
||||
|
||||
ID<asset::Pipe> pipe() const;
|
||||
ID<asset::Struct> holder() const;
|
||||
StreamType::ID streamType() const;
|
||||
|
||||
bool
|
||||
isValid() const
|
||||
{
|
||||
return exists (this->id_);
|
||||
}
|
||||
|
||||
|
||||
friend bool
|
||||
operator== (ModelPort const& mp1, ModelPort const& mp2)
|
||||
{
|
||||
return mp1.id_ == mp2.id_;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!= (ModelPort const& mp1, ModelPort const& mp2)
|
||||
{
|
||||
return mp1.id_ != mp2.id_;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // namespace mobject
|
||||
#endif
|
||||
|
|
@ -152,6 +152,7 @@ namespace session {
|
|||
closeSessionInterface()
|
||||
{ /////////////////////// TICKET #699
|
||||
INFO (session, "closing session interfaces.");
|
||||
TODO ("actually close session interfaces :) and don't babble in the log when NOT closing anything...");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,22 @@ PLANNED "BuildSegment_test" BuildSegment_test <<END
|
|||
END
|
||||
|
||||
|
||||
PLANNED "detecting Fixture changes" FixtureChangeDetector_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "ModelPort registry" ModelPortRegistry_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
TEST "Output pipe mapping" OutputMapping_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
||||
PLANNED "Segmentation datastructure" SegmentationDatastructure_test <<END
|
||||
return: 0
|
||||
END
|
||||
|
||||
|
|
|
|||
|
|
@ -73,6 +73,9 @@ test_components_SOURCES = \
|
|||
$(testcomponents_srcdir)/proc/engine/node-source-test.cpp \
|
||||
$(testcomponents_srcdir)/proc/mobject/builder/buildertooltest.cpp \
|
||||
$(testcomponents_srcdir)/proc/mobject/builder/buildsegmenttest.cpp \
|
||||
$(testcomponents_srcdir)/proc/mobject/builder/model-port-registry-test.cpp \
|
||||
$(testcomponents_srcdir)/proc/mobject/builder/fixture-change-detector-test.cpp \
|
||||
$(testcomponents_srcdir)/proc/mobject/builder/segmentation-datastructure-test.cpp\
|
||||
$(testcomponents_srcdir)/proc/mobject/controller/rendersegmenttest.cpp \
|
||||
$(testcomponents_srcdir)/proc/mobject/mobject-interface-test.cpp \
|
||||
$(testcomponents_srcdir)/proc/mobject/mobject-ref-test.cpp \
|
||||
|
|
|
|||
|
|
@ -42,13 +42,13 @@ using std::string;
|
|||
using std::cout;
|
||||
|
||||
|
||||
namespace asset
|
||||
{
|
||||
namespace test
|
||||
{
|
||||
namespace asset {
|
||||
namespace test {
|
||||
|
||||
using mobject::Session;
|
||||
using lumiera::Query;
|
||||
using lumiera::query::normaliseID;
|
||||
using lumiera::StreamType;
|
||||
|
||||
|
||||
|
||||
|
|
@ -88,7 +88,7 @@ namespace asset
|
|||
CHECK (thePipe);
|
||||
CHECK (thePipe->getProcPatt());
|
||||
CHECK (thePipe->getPipeID() == pID_sane);
|
||||
CHECK (thePipe->getStreamID() == sID);
|
||||
CHECK (thePipe->getStreamID() == StreamType::ID(sID));
|
||||
CHECK (thePipe->shortDesc == pID_sane);
|
||||
|
||||
Asset::Ident idi = thePipe->ident;
|
||||
|
|
@ -147,7 +147,7 @@ namespace asset
|
|||
string sID = pipe1->getStreamID(); // sort of a "default stream type"
|
||||
PPipe pipe3 = Pipe::query ("stream("+sID+")");
|
||||
CHECK (pipe3);
|
||||
CHECK (pipe3->getStreamID() == sID);
|
||||
CHECK (pipe3->getStreamID() == StreamType::ID(sID));
|
||||
CHECK (pipe3->getProcPatt() == Session::current->defaults (Query<const ProcPatt>("stream("+sID+")")));
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,74 +35,70 @@ using util::isnil;
|
|||
using std::string;
|
||||
|
||||
|
||||
namespace asset
|
||||
{
|
||||
namespace test
|
||||
namespace asset {
|
||||
namespace test {
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* @test creating several Assets and checking object identity,
|
||||
* detection of duplicates and version handling.
|
||||
* @see proc_interface::AssetManager#reg
|
||||
*/
|
||||
class IdentityOfAssets_test : public Test
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* @test creating several Assets and checking object identity,
|
||||
* detection of duplicates and version handling.
|
||||
* @see proc_interface::AssetManager#reg
|
||||
*/
|
||||
class IdentityOfAssets_test : public Test
|
||||
{
|
||||
virtual void run(Arg arg)
|
||||
{
|
||||
createDuplicate();
|
||||
|
||||
if (!isnil (arg))
|
||||
dumpAssetManager();
|
||||
TRACE (asset_mem, "leaving IdentityOfAssets_test::run()");
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef shared_ptr<asset::Media> PM;
|
||||
|
||||
/** @test produce an ID clash.
|
||||
* documents the current behaviour of the code as of 9/07
|
||||
* @todo this test is expected to break when the detection
|
||||
* of duplicate registrations is implemented.
|
||||
*/
|
||||
void createDuplicate()
|
||||
{
|
||||
PM mm1 = asset::Media::create ("testfile1.mov", VIDEO);
|
||||
|
||||
Asset::Ident idi (mm1->ident); // duplicate Ident record
|
||||
PM mm1X = asset::Media::create (idi); // note: we actually don't call any ctor
|
||||
CHECK (mm1 == mm1X); // instead, we got mm1 back.
|
||||
|
||||
PM mm2 = asset::Media::create (idi,"testfile2.mov");
|
||||
|
||||
CHECK (mm1->getID() == mm2->getID()); // different object, same hash
|
||||
|
||||
AssetManager& aMang = AssetManager::instance();
|
||||
CHECK (aMang.getAsset (mm1->getID()) == mm2); // record of mm1 was replaced by mm2
|
||||
CHECK (aMang.getAsset (mm2->getID()) == mm2);
|
||||
|
||||
CHECK (aMang.known (mm1->getID()));
|
||||
CHECK (aMang.known (mm2->getID()));
|
||||
CHECK (mm1->ident.name == "testfile1");
|
||||
CHECK (mm2->ident.name == "testfile1");
|
||||
CHECK (mm1->getFilename() == "testfile1.mov");
|
||||
CHECK (mm2->getFilename() == "testfile2.mov");
|
||||
|
||||
|
||||
TRACE (asset_mem, "leaving test method scope");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (IdentityOfAssets_test, "unit asset");
|
||||
|
||||
|
||||
|
||||
} // namespace test
|
||||
|
||||
} // namespace asset
|
||||
virtual void run(Arg arg)
|
||||
{
|
||||
createDuplicate();
|
||||
|
||||
if (!isnil (arg))
|
||||
dumpAssetManager();
|
||||
TRACE (asset_mem, "leaving IdentityOfAssets_test::run()");
|
||||
}
|
||||
|
||||
|
||||
|
||||
typedef shared_ptr<asset::Media> PM;
|
||||
|
||||
/** @test produce an ID clash.
|
||||
* documents the current behaviour of the code as of 9/07
|
||||
* @todo this test is expected to break when the detection
|
||||
* of duplicate registrations is implemented.
|
||||
*/
|
||||
void createDuplicate()
|
||||
{
|
||||
PM mm1 = asset::Media::create ("testfile1.mov", VIDEO);
|
||||
|
||||
Asset::Ident idi (mm1->ident); // duplicate Ident record
|
||||
PM mm1X = asset::Media::create (idi); // note: we actually don't call any ctor
|
||||
CHECK (mm1 == mm1X); // instead, we got mm1 back.
|
||||
|
||||
PM mm2 = asset::Media::create (idi,"testfile2.mov");
|
||||
|
||||
CHECK (mm1->getID() == mm2->getID()); // different object, same hash
|
||||
|
||||
AssetManager& aMang = AssetManager::instance();
|
||||
CHECK (aMang.getAsset (mm1->getID()) == mm2); // record of mm1 was replaced by mm2
|
||||
CHECK (aMang.getAsset (mm2->getID()) == mm2);
|
||||
|
||||
CHECK (aMang.known (mm1->getID()));
|
||||
CHECK (aMang.known (mm2->getID()));
|
||||
CHECK (mm1->ident.name == "testfile1");
|
||||
CHECK (mm2->ident.name == "testfile1");
|
||||
CHECK (mm1->getFilename() == "testfile1.mov");
|
||||
CHECK (mm2->getFilename() == "testfile2.mov");
|
||||
|
||||
|
||||
TRACE (asset_mem, "leaving test method scope");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (IdentityOfAssets_test, "unit asset");
|
||||
|
||||
|
||||
|
||||
}} // namespace asset::test
|
||||
|
|
|
|||
|
|
@ -36,29 +36,29 @@
|
|||
|
||||
namespace control {
|
||||
namespace test {
|
||||
|
||||
|
||||
|
||||
|
||||
using lib::Symbol;
|
||||
using std::tr1::function;
|
||||
using std::rand;
|
||||
|
||||
|
||||
|
||||
|
||||
namespace { // test data and helpers...
|
||||
|
||||
|
||||
Symbol TEST_CMD = "test.command1.handling";
|
||||
HandlingPattern::ID TEST_PATTERN = HandlingPattern::DUMMY;
|
||||
}
|
||||
|
||||
|
||||
typedef shared_ptr<CommandImpl> PCommandImpl;
|
||||
typedef HandlingPattern const& HaPatt;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/**********************************************************************************
|
||||
* @test operate and verify a simple dummy command handling pattern.
|
||||
* @note this test covers mainly the behaviour of a handling pattern as a concept,
|
||||
* not so much the behaviour of the (standard) handling pattern implementations.
|
||||
*
|
||||
*
|
||||
* @see HandlingPattern
|
||||
* @see BasicHandlingPattern
|
||||
* @see command.hpp
|
||||
|
|
@ -66,28 +66,28 @@ namespace test {
|
|||
*/
|
||||
class HandlingPatternBasics_test : public Test
|
||||
{
|
||||
|
||||
|
||||
uint cnt_inst;
|
||||
|
||||
|
||||
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
CommandRegistry& registry = CommandRegistry::instance();
|
||||
CHECK (®istry);
|
||||
|
||||
|
||||
cnt_inst = registry.instance_count();
|
||||
|
||||
|
||||
{
|
||||
PCommandImpl pCom = buildTestCommand(registry);
|
||||
checkExec (pCom);
|
||||
checkUndo (pCom);
|
||||
}
|
||||
|
||||
|
||||
CHECK (cnt_inst == registry.instance_count());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** create a command implementation frame usable for tests.
|
||||
* This simulates what normally happens within a CommandDef.
|
||||
* The created CommandImpl isn't registered, and thus will
|
||||
|
|
@ -96,74 +96,74 @@ namespace test {
|
|||
PCommandImpl
|
||||
buildTestCommand (CommandRegistry& registry)
|
||||
{
|
||||
|
||||
|
||||
typedef void Sig_oper(int);
|
||||
typedef long Sig_capt(int);
|
||||
typedef void Sig_undo(int,long);
|
||||
|
||||
|
||||
function<Sig_oper> o_Fun (command1::operate);
|
||||
function<Sig_capt> c_Fun (command1::capture);
|
||||
function<Sig_undo> u_Fun (command1::undoIt);
|
||||
|
||||
|
||||
CHECK (o_Fun && c_Fun && u_Fun);
|
||||
|
||||
|
||||
// when the CommandDef is complete, it issues the
|
||||
// allocation call to the registry behind the scenes....
|
||||
|
||||
|
||||
PCommandImpl pImpl = registry.newCommandImpl(o_Fun,c_Fun,u_Fun);
|
||||
CHECK (pImpl);
|
||||
CHECK (*pImpl);
|
||||
return pImpl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
checkExec (PCommandImpl com)
|
||||
{
|
||||
CHECK (com);
|
||||
CHECK (!com->canExec());
|
||||
|
||||
|
||||
typedef Types<int> ArgType;
|
||||
const int ARGU (1 + rand() % 1000);
|
||||
Tuple<ArgType> tuple(ARGU);
|
||||
TypedArguments<Tuple<ArgType> > arg(tuple);
|
||||
com->setArguments(arg);
|
||||
|
||||
|
||||
CHECK (com->canExec());
|
||||
CHECK (!com->canUndo());
|
||||
command1::check_ = 0;
|
||||
|
||||
|
||||
HaPatt patt = HandlingPattern::get(TEST_PATTERN);
|
||||
ExecResult res = patt.invoke(*com, TEST_CMD);
|
||||
|
||||
|
||||
CHECK (res);
|
||||
CHECK (ARGU == command1::check_);
|
||||
CHECK (com->canUndo());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
checkUndo (PCommandImpl com)
|
||||
{
|
||||
CHECK (com);
|
||||
CHECK (com->canExec());
|
||||
CHECK (com->canUndo());
|
||||
|
||||
|
||||
CHECK (command1::check_ > 0);
|
||||
|
||||
|
||||
HaPatt ePatt = HandlingPattern::get(TEST_PATTERN);
|
||||
HaPatt uPatt = ePatt.howtoUNDO();
|
||||
ExecResult res = uPatt.invoke(*com, TEST_CMD);
|
||||
|
||||
|
||||
CHECK (res);
|
||||
CHECK (command1::check_ == 0);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (HandlingPatternBasics_test, "function controller");
|
||||
|
||||
|
||||
|
||||
|
||||
}} // namespace control::test
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ namespace test {
|
|||
|
||||
MemHolder mementoHolder (undo_func,cap_func);
|
||||
|
||||
CHECK (sizeof(MemHolder) <= sizeof(int) // storage for the memento
|
||||
CHECK (sizeof(MemHolder) <= sizeof(int) // storage for the memento
|
||||
+ 2 * sizeof(function<void()>) // storage for the 2 undecorated functors
|
||||
+ ALIGNMENT);
|
||||
|
||||
|
|
@ -160,10 +160,10 @@ namespace test {
|
|||
CHECK (m22 != m11);
|
||||
CHECK (m22 != m12);
|
||||
CHECK (m22 != m21);
|
||||
|
||||
|
||||
MemHolder m22x (m22); // clone copy
|
||||
CHECK (!m22x);
|
||||
CHECK (m22 == m22x); // same functions, no state --> equal
|
||||
CHECK (m22 == m22x); // same functions, no state --> equal
|
||||
|
||||
testVal = 0;
|
||||
m22x.tieCaptureFunc() (1 + (rand() % 9)); // produce a random memento value != 0
|
||||
|
|
|
|||
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
FixtureChangeDetector(Test) - detecting segmentation differences
|
||||
|
||||
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/test/run.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "proc/mobject/builder/fixture-change-detector.hpp"
|
||||
#include "proc/asset/timeline.hpp"
|
||||
#include "proc/asset/pipe.hpp"
|
||||
#include "lib/query.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
namespace test {
|
||||
|
||||
// using util::isSameObject;
|
||||
// using util::isnil;
|
||||
//
|
||||
using asset::Pipe;
|
||||
using asset::PPipe;
|
||||
using asset::Struct;
|
||||
using asset::Timeline;
|
||||
using asset::PTimeline;
|
||||
using lumiera::Query;
|
||||
//
|
||||
typedef asset::ID<Pipe> PID;
|
||||
typedef asset::ID<Struct> TID;
|
||||
//
|
||||
// typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor;
|
||||
|
||||
|
||||
namespace { // test environment
|
||||
|
||||
inline PID
|
||||
getPipe (string id)
|
||||
{
|
||||
return Pipe::query("id("+id+")");
|
||||
}
|
||||
|
||||
inline TID
|
||||
getTimeline (string id)
|
||||
{
|
||||
return asset::Struct::retrieve (Query<Timeline> ("id("+id+")"))->getID();
|
||||
}
|
||||
|
||||
struct TestContext
|
||||
{
|
||||
|
||||
/** setup */
|
||||
TestContext()
|
||||
{ }
|
||||
|
||||
/** tear-down */
|
||||
~TestContext()
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************************************************************
|
||||
* @test TODO blubb
|
||||
*
|
||||
* @see mobject::builder::FixtureChangeDetector
|
||||
*/
|
||||
class FixtureChangeDetector_test : public Test
|
||||
{
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
TestContext ctx;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fabricating_ModelPorts ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (FixtureChangeDetector_test, "unit builder");
|
||||
|
||||
|
||||
|
||||
}}} // namespace mobject::builder::test
|
||||
|
|
@ -0,0 +1,275 @@
|
|||
/*
|
||||
ModelPortRegistry(Test) - verify handling of model ports
|
||||
|
||||
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/test/run.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "proc/mobject/builder/model-port-registry.hpp"
|
||||
#include "proc/asset/timeline.hpp"
|
||||
#include "proc/asset/pipe.hpp"
|
||||
#include "lib/query.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
namespace test {
|
||||
|
||||
using util::isSameObject;
|
||||
using util::isnil;
|
||||
|
||||
using asset::Pipe;
|
||||
using asset::PPipe;
|
||||
using asset::Struct;
|
||||
using asset::Timeline;
|
||||
using asset::PTimeline;
|
||||
using lumiera::Query;
|
||||
|
||||
typedef asset::ID<Pipe> PID;
|
||||
typedef asset::ID<Struct> TID;
|
||||
|
||||
typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor;
|
||||
|
||||
|
||||
namespace { // test environment
|
||||
|
||||
inline PID
|
||||
getPipe (string id)
|
||||
{
|
||||
return Pipe::query("id("+id+")");
|
||||
}
|
||||
|
||||
inline TID
|
||||
getTimeline (string id)
|
||||
{
|
||||
return asset::Struct::retrieve (Query<Timeline> ("id("+id+")"))->getID();
|
||||
}
|
||||
|
||||
struct TestContext
|
||||
{
|
||||
ModelPortRegistry registry_;
|
||||
ModelPortRegistry* previous_;
|
||||
|
||||
/** setup */
|
||||
TestContext()
|
||||
: registry_()
|
||||
, previous_(ModelPortRegistry::setActiveInstance (registry_))
|
||||
{ }
|
||||
|
||||
/** tear-down */
|
||||
~TestContext()
|
||||
{
|
||||
if (previous_)
|
||||
ModelPortRegistry::setActiveInstance (*previous_);
|
||||
else
|
||||
ModelPortRegistry::shutdown();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************************************************************
|
||||
* @test create a standalone model port registry to verify the behaviour of
|
||||
* model ports, accessed through reference handles. This test provides an
|
||||
* example setup detached from the real usage situation within the builder.
|
||||
* The ModelPortRegistry management interface is used to create and track a
|
||||
* set of model ports, to be made visible by an atomic, transactional switch.
|
||||
* The access for client code through the ModelPort frontend is then verified.
|
||||
*
|
||||
* @see mobject::ModelPort
|
||||
* @see mobject::builder::ModelPortRegistry
|
||||
*/
|
||||
class ModelPortRegistry_test : public Test
|
||||
{
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
TestContext ctx;
|
||||
|
||||
fabricating_ModelPorts (ctx.registry_);
|
||||
accessing_ModelPorts();
|
||||
transactionalSwitch (ctx.registry_);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fabricating_ModelPorts (ModelPortRegistry& registry)
|
||||
{
|
||||
/* == some Assets to play with == */
|
||||
PID pipeA = getPipe ("pipeA");
|
||||
PID pipeB = getPipe ("pipeB");
|
||||
TID someTimeline = getTimeline ("some_test_Timeline");
|
||||
|
||||
// start out with defining some new model ports......
|
||||
MPDescriptor p1 = registry.definePort (pipeA, someTimeline);
|
||||
MPDescriptor p2 = registry.definePort (pipeB, someTimeline);
|
||||
|
||||
CHECK (registry.contains (pipeA));
|
||||
CHECK (registry.contains (pipeB));
|
||||
|
||||
VERIFY_ERROR (DUPLICATE_MODEL_PORT, registry.definePort(pipeB, someTimeline) );
|
||||
CHECK (registry.contains (pipeB));
|
||||
|
||||
CHECK (pipeA == p1.id());
|
||||
CHECK (pipeB == p2.id());
|
||||
CHECK (someTimeline == p1.holder());
|
||||
CHECK (someTimeline == p2.holder());
|
||||
|
||||
registry.commit();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
accessing_ModelPorts ()
|
||||
{
|
||||
PID pipeA = getPipe ("pipeA");
|
||||
PID pipeB = getPipe ("pipeB");
|
||||
PID pipeWC = getPipe ("WCpipe");
|
||||
|
||||
ModelPort mp1(pipeA);
|
||||
ModelPort mp2(pipeB);
|
||||
|
||||
VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort unbefitting(pipeWC) );
|
||||
|
||||
ModelPort mp1x(pipeA); // can be created multiple times
|
||||
ModelPort mp2x(mp1x); // can be copied at will
|
||||
ModelPort mpNull; // can be default constructed (->unconnected)
|
||||
|
||||
CHECK (mp1);
|
||||
CHECK (mp2);
|
||||
CHECK (mp1x);
|
||||
CHECK (!mpNull); // bool check verifies setup and connected state
|
||||
|
||||
CHECK ( ModelPort::exists (pipeA)); // this is the same check, but invoked just with an pipe-ID
|
||||
CHECK ( ModelPort::exists (pipeB));
|
||||
CHECK (!ModelPort::exists (pipeWC));
|
||||
|
||||
CHECK (mp1 == mp1x);
|
||||
CHECK (!isSameObject (mp1, mp1x));
|
||||
CHECK (mp1 != mp2);
|
||||
CHECK (mp2 != mp1);
|
||||
CHECK (mp1 != mpNull);
|
||||
CHECK (mp2 != mpNull);
|
||||
|
||||
CHECK (mp1.pipe() == pipeA);
|
||||
CHECK (mp2.pipe() == pipeB);
|
||||
CHECK (mp1x.pipe() == pipeA);
|
||||
VERIFY_ERROR (UNCONNECTED_MODEL_PORT, mpNull.pipe()); // any further operations on an unconnected port will throw
|
||||
VERIFY_ERROR (UNCONNECTED_MODEL_PORT, mpNull.holder());
|
||||
|
||||
CHECK (mp1.streamType() == pipeA.streamType());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
transactionalSwitch (ModelPortRegistry& registry)
|
||||
{
|
||||
PID pipeA = getPipe ("pipeA");
|
||||
PID pipeB = getPipe ("pipeB");
|
||||
PID pipeWC = getPipe ("WCpipe");
|
||||
|
||||
CHECK ( ModelPort::exists (pipeB));
|
||||
CHECK (!ModelPort::exists (pipeWC));
|
||||
|
||||
CHECK (ModelPort::exists (pipeA));
|
||||
CHECK (registry.contains (pipeA));
|
||||
registry.remove (pipeA);
|
||||
CHECK (!registry.contains (pipeA)); // removed from the current (pending) transaction
|
||||
CHECK ( ModelPort::exists (pipeA)); // but not yet publicly visible
|
||||
|
||||
// now create a new and differing definition of port A
|
||||
TID anotherTimeline = getTimeline ("another_test_Timeline");
|
||||
MPDescriptor p1 = registry.definePort (pipeA, anotherTimeline);
|
||||
CHECK (registry.contains (pipeA));
|
||||
CHECK (anotherTimeline == p1.holder());
|
||||
CHECK (ModelPort(pipeA).holder() != anotherTimeline);
|
||||
|
||||
registry.remove (pipeB); // some more wired definitions
|
||||
registry.definePort (pipeWC, anotherTimeline);
|
||||
CHECK (!registry.contains (pipeB));
|
||||
CHECK ( registry.contains (pipeWC));
|
||||
CHECK ( ModelPort::exists (pipeB));
|
||||
CHECK (!ModelPort::exists (pipeWC));
|
||||
CHECK ( registry.isRegistered (pipeB)); // this is the same as ModelPort::exists
|
||||
CHECK (!registry.isRegistered (pipeWC)); //
|
||||
// Note: pending transaction not yet committed
|
||||
ModelPort portA(pipeA); // ...... thus the changes aren't reflected to client code
|
||||
ModelPort portB(pipeB);
|
||||
VERIFY_ERROR (INVALID_MODEL_PORT, ModelPort ineptly(pipeWC));
|
||||
CHECK (portA);
|
||||
CHECK (portB);
|
||||
CHECK (portA.pipe() == pipeA);
|
||||
CHECK (portB.pipe() == pipeB);
|
||||
CHECK (portA.holder() != anotherTimeline);
|
||||
|
||||
registry.commit();
|
||||
CHECK ( ModelPort::exists (pipeA)); // now all our changes got publicly visible
|
||||
CHECK (!ModelPort::exists (pipeB));
|
||||
CHECK ( ModelPort::exists (pipeWC));
|
||||
CHECK ( portA);
|
||||
CHECK (!portB);
|
||||
CHECK (portA.holder() == anotherTimeline);
|
||||
CHECK (portA.pipe() == pipeA);
|
||||
VERIFY_ERROR (INVALID_MODEL_PORT, portB.pipe());
|
||||
|
||||
ModelPort pwc(pipeWC); // now clients may also use the now officially promoted new port
|
||||
CHECK (pwc);
|
||||
CHECK (pwc.pipe() == pipeWC);
|
||||
CHECK (pwc.holder() == anotherTimeline);
|
||||
|
||||
// Next: doing several changes,
|
||||
// but finally *not* committing them...
|
||||
CHECK ( registry.contains (pipeA));
|
||||
CHECK (!registry.contains (pipeB));
|
||||
CHECK ( registry.contains (pipeWC));
|
||||
registry.remove (pipeA);
|
||||
registry.clear(); // remove everything from the pending transaction
|
||||
CHECK (!registry.contains (pipeA));
|
||||
CHECK (!registry.contains (pipeB));
|
||||
CHECK (!registry.contains (pipeWC));
|
||||
|
||||
registry.definePort (pipeB, anotherTimeline);
|
||||
CHECK ( registry.contains (pipeB));
|
||||
CHECK (!portB); // not committed and thus not visible
|
||||
CHECK (portA);
|
||||
CHECK (pwc);
|
||||
|
||||
registry.rollback();
|
||||
CHECK ( registry.contains (pipeA)); // no effect to the officialy visible state
|
||||
CHECK (!registry.contains (pipeB));
|
||||
CHECK ( registry.contains (pipeWC));
|
||||
|
||||
VERIFY_ERROR(INVALID_MODEL_PORT, registry.get(pipeB) );
|
||||
CHECK (!portB);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (ModelPortRegistry_test, "unit session builder");
|
||||
|
||||
|
||||
|
||||
}}} // namespace mobject::builder::test
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
/*
|
||||
SegmentationDatastructure(Test) - verify basic properties of the Segmentation
|
||||
|
||||
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/test/run.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "proc/mobject/builder/fixture-change-detector.hpp"
|
||||
#include "proc/asset/timeline.hpp"
|
||||
#include "proc/asset/pipe.hpp"
|
||||
#include "lib/query.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
|
||||
namespace mobject {
|
||||
namespace builder {
|
||||
namespace test {
|
||||
|
||||
// using util::isSameObject;
|
||||
// using util::isnil;
|
||||
//
|
||||
using asset::Pipe;
|
||||
using asset::PPipe;
|
||||
using asset::Struct;
|
||||
using asset::Timeline;
|
||||
using asset::PTimeline;
|
||||
using lumiera::Query;
|
||||
//
|
||||
typedef asset::ID<Pipe> PID;
|
||||
typedef asset::ID<Struct> TID;
|
||||
//
|
||||
// typedef ModelPortRegistry::ModelPortDescriptor const& MPDescriptor;
|
||||
|
||||
|
||||
namespace { // test environment
|
||||
|
||||
inline PID
|
||||
getPipe (string id)
|
||||
{
|
||||
return Pipe::query("id("+id+")");
|
||||
}
|
||||
|
||||
inline TID
|
||||
getTimeline (string id)
|
||||
{
|
||||
return asset::Struct::retrieve (Query<Timeline> ("id("+id+")"))->getID();
|
||||
}
|
||||
|
||||
struct TestContext
|
||||
{
|
||||
|
||||
/** setup */
|
||||
TestContext()
|
||||
{ }
|
||||
|
||||
/** tear-down */
|
||||
~TestContext()
|
||||
{
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*********************************************************************************
|
||||
* @test TODO blubb
|
||||
*
|
||||
* @see mobject::builder::FixtureChangeDetector
|
||||
*/
|
||||
class SegmentationDatastructure_test : public Test
|
||||
{
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
TestContext ctx;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
fabricating_ModelPorts ()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (SegmentationDatastructure_test, "unit builder");
|
||||
|
||||
|
||||
|
||||
}}} // namespace mobject::builder::test
|
||||
|
|
@ -45,19 +45,19 @@ using std::endl;
|
|||
|
||||
namespace mobject {
|
||||
namespace test {
|
||||
|
||||
|
||||
namespace { // shortcut for checking use-counts
|
||||
|
||||
|
||||
bool
|
||||
checkUseCount (size_t cnt, uint additional=0)
|
||||
{
|
||||
static uint base_count=0;
|
||||
if (!additional) // called for init
|
||||
base_count = cnt;
|
||||
|
||||
|
||||
return cnt == base_count + additional;
|
||||
}
|
||||
|
||||
|
||||
template<class REF>
|
||||
bool
|
||||
checkUseCount (REF const& ref, uint additional)
|
||||
|
|
@ -65,17 +65,17 @@ namespace test {
|
|||
return checkUseCount(ref.use_count(), additional);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
using lumiera::Time;
|
||||
using session::Clip;
|
||||
using session::PMedia;
|
||||
|
||||
|
||||
using session::SessionServiceMockIndex;
|
||||
using session::PPIdx;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* @test properties and behaviour of the external reference-mechanism for
|
||||
* MObjects placed into the session. We create a simple, simulated
|
||||
|
|
@ -88,49 +88,49 @@ namespace test {
|
|||
*/
|
||||
class MObjectRef_test : public Test
|
||||
{
|
||||
|
||||
|
||||
typedef Placement<MObject> PMObj;
|
||||
typedef Placement<Clip> PClip;
|
||||
typedef TestPlacement<TestSubMO1> PSub1;
|
||||
|
||||
|
||||
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
|
||||
|
||||
// create data simulating a "Session"
|
||||
PMObj testClip1 = asset::Media::create("test-1", asset::VIDEO)->createClip();
|
||||
PMObj testClip2 = asset::Media::create("test-2", asset::VIDEO)->createClip();
|
||||
|
||||
|
||||
// set up a tie to fixed start positions (i.e. "properties of placement")
|
||||
testClip1.chain(Time(10));
|
||||
testClip2.chain(Time(20));
|
||||
|
||||
|
||||
CHECK (testClip1->isValid());
|
||||
CHECK (testClip2->isValid());
|
||||
CHECK (2 == testClip1.use_count()); // one by the placement and one by the clip-Asset
|
||||
CHECK (2 == testClip2.use_count());
|
||||
|
||||
|
||||
|
||||
|
||||
// Prepare an (test)Index
|
||||
PPIdx index = SessionServiceMockIndex::install();
|
||||
PMO& root = index->getRoot();
|
||||
|
||||
|
||||
// Add the Clips to "session" (here: dummy index)
|
||||
PMObj::ID clip1ID = index->insert (testClip1, root);
|
||||
PMObj::ID clip2ID = index->insert (testClip2, root);
|
||||
CHECK (2 == index->size());
|
||||
|
||||
|
||||
// use the IDs returned on insertion to fetch
|
||||
// language references to the placement instance within the index
|
||||
// we'll use these language refs as base to create MObejctRef handles.
|
||||
PMObj& pClip1 = index->find(clip1ID);
|
||||
PMObj& pClip2 = index->find(clip2ID);
|
||||
|
||||
CHECK (3 == pClip1.use_count()); // clip-Asset, original placement, new placement in index
|
||||
|
||||
CHECK (3 == pClip1.use_count()); // clip-Asset, original placement, new placement in index
|
||||
CHECK (3 == pClip2.use_count());
|
||||
checkUseCount(pClip1.use_count()); // set ref point for later checks
|
||||
|
||||
|
||||
// extract various kinds of IDs and refs
|
||||
PMObj & rP1 (pClip1);
|
||||
PMObj const& rP2 (pClip2);
|
||||
|
|
@ -140,8 +140,8 @@ namespace test {
|
|||
///////////////////////////////////////////TODO: check the C-API representation here
|
||||
PlacementRef<Clip> ref1 (id1);
|
||||
PlacementRef<MObject> ref2 (pClip2);
|
||||
|
||||
|
||||
|
||||
|
||||
// -----Tests------------------
|
||||
checkBuildMObjectRef (rP1, &pClip1);
|
||||
checkBuildMObjectRef (rP2, &pClip2);
|
||||
|
|
@ -151,12 +151,12 @@ namespace test {
|
|||
///////////////////////////////////////////TODO: check the C-API representation here
|
||||
checkBuildMObjectRef (ref1, &pClip1);
|
||||
checkBuildMObjectRef (ref2, &pClip2);
|
||||
|
||||
|
||||
checkComparison(rP1,rP2);
|
||||
checkLifecycle (rP1,rP2);
|
||||
checkTypeHandling (luid);
|
||||
// -----Tests------------------
|
||||
|
||||
|
||||
// verify clean state
|
||||
index->remove (pClip1);
|
||||
index->remove (pClip2); // note: this invalidates pClip1 and pClip2;
|
||||
|
|
@ -168,24 +168,24 @@ namespace test {
|
|||
CHECK (2 == testClip2.use_count());
|
||||
index.reset();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename REF>
|
||||
void
|
||||
checkBuildMObjectRef (REF& refObj, void* placementAdr)
|
||||
{
|
||||
MORef<Clip> rMO;
|
||||
CHECK (!rMO); // still empty (not bound)
|
||||
CHECK (!rMO); // still empty (not bound)
|
||||
CHECK (0==rMO.use_count());
|
||||
cout << string(rMO) << endl; /////////////////////TICKET #527
|
||||
cout << showSizeof(rMO) << endl;
|
||||
|
||||
|
||||
// activate by binding to provided ref
|
||||
rMO.activate(refObj);
|
||||
CHECK (rMO); // now bound
|
||||
cout << string(rMO) << endl; /////////////////////TICKET #527
|
||||
|
||||
|
||||
// access MObject (Clip API)
|
||||
// cout << rMO->operator string() << endl; /////////////////////TICKET #428
|
||||
PMedia media = rMO->getMedia();
|
||||
|
|
@ -193,45 +193,45 @@ namespace test {
|
|||
Time mediaLength = media->getLength();
|
||||
CHECK (Time(0) < mediaLength);
|
||||
CHECK (rMO->isValid());
|
||||
|
||||
|
||||
// access the Placement-API
|
||||
CHECK (checkUseCount(rMO, 1)); // now rMO shares ownership with the Placement --> use-count += 1
|
||||
CHECK (Time(0) < rMO.getStartTime()); // (internally, this resolves to an ExplicitPlacement) /////////TICKET #332
|
||||
CHECK (checkUseCount(rMO, 1)); // now rMO shares ownership with the Placement --> use-count += 1
|
||||
CHECK (Time(0) < rMO.getStartTime()); // (internally, this resolves to an ExplicitPlacement) /////////TICKET #332
|
||||
CHECK ( rMO.isCompatible<MObject>());
|
||||
CHECK ( rMO.isCompatible<Clip>());
|
||||
CHECK (!rMO.isCompatible<TestSubMO1>());
|
||||
Time start = rMO.getStartTime();
|
||||
|
||||
|
||||
// re-link to the Placement (note we get the Clip API!)
|
||||
Placement<Clip> & refP = rMO.getPlacement();
|
||||
CHECK (refP.isValid());
|
||||
CHECK (refP.use_count() == rMO.use_count());
|
||||
CHECK (checkUseCount(refP, 1)); // use count not changed
|
||||
CHECK (&refP == placementAdr); // actually denotes the address of the original Placement in the "session"
|
||||
CHECK (checkUseCount(refP, 1)); // use count not changed
|
||||
CHECK (&refP == placementAdr); // actually denotes the address of the original Placement in the "session"
|
||||
cout << string(refP) << endl;
|
||||
|
||||
|
||||
ExplicitPlacement exPla = refP.resolve();
|
||||
CHECK (exPla.time == start); // recovered Placement resolves to the same time as provided by the proxied API
|
||||
CHECK (checkUseCount(refP, 2)); // but now we've indeed created an additional owner (exPla)
|
||||
CHECK (exPla.time == start); // recovered Placement resolves to the same time as provided by the proxied API
|
||||
CHECK (checkUseCount(refP, 2)); // but now we've indeed created an additional owner (exPla)
|
||||
CHECK (checkUseCount(rMO, 2));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
checkComparison (PMO const& p1, PMO const& p2)
|
||||
{
|
||||
PlacementRef<Clip> pRef1 (p1);
|
||||
PlacementRef<MObject> pRef2 (p2);
|
||||
|
||||
|
||||
MORef<MObject> rM;
|
||||
MORef<Clip> rC;
|
||||
|
||||
|
||||
rM.activate (p1);
|
||||
rC.activate (p2);
|
||||
CHECK (rM && rC);
|
||||
CHECK (!(rM == rC) && !(rC == rM));
|
||||
CHECK ( (rM != rC) && (rC != rM));
|
||||
|
||||
|
||||
// mixed comparisons
|
||||
CHECK ( (rM == pRef1) && (pRef1 == rM));
|
||||
CHECK ( (rC == pRef2) && (pRef2 == rC));
|
||||
|
|
@ -241,7 +241,7 @@ namespace test {
|
|||
CHECK ( (rC != pRef1) && (pRef1 != rC));
|
||||
CHECK (!(rM == pRef2) && !(pRef2 == rM));
|
||||
CHECK (!(rC == pRef1) && !(pRef1 == rC));
|
||||
|
||||
|
||||
CHECK ( (rM == p1.getID()) );
|
||||
CHECK ( (rC == p2.getID()) );
|
||||
CHECK (!(rM != p1.getID()) );
|
||||
|
|
@ -250,125 +250,125 @@ namespace test {
|
|||
CHECK ( (rC != p1.getID()) );
|
||||
CHECK (!(rM == p2.getID()) );
|
||||
CHECK (!(rC == p1.getID()) );
|
||||
|
||||
|
||||
|
||||
|
||||
rC.activate (pRef1);
|
||||
CHECK ( (rM == rC) && (rC == rM));
|
||||
CHECK (!(rM != rC) && !(rC != rM));
|
||||
|
||||
|
||||
CHECK ( (rC == pRef1) && (pRef1 == rC));
|
||||
CHECK (!(rC != pRef1) && !(pRef1 != rC));
|
||||
CHECK ( (rC != pRef2) && (pRef2 != rC));
|
||||
CHECK (!(rC == pRef2) && !(pRef2 == rC));
|
||||
|
||||
|
||||
CHECK ( (rC == p1.getID()) );
|
||||
CHECK (!(rC != p1.getID()) );
|
||||
CHECK ( (rC != p2.getID()) );
|
||||
CHECK (!(rC == p2.getID()) );
|
||||
|
||||
|
||||
|
||||
|
||||
rM.close();
|
||||
CHECK (!rM);
|
||||
CHECK (!(rM == rC) && !(rC == rM));
|
||||
CHECK ( (rM != rC) && (rC != rM));
|
||||
|
||||
|
||||
CHECK (!(rM == pRef1) && !(pRef1 == rM));
|
||||
CHECK ( (rM != pRef1) && (pRef1 != rM));
|
||||
CHECK ( (rM != pRef2) && (pRef2 != rM));
|
||||
CHECK (!(rM == pRef2) && !(pRef2 == rM));
|
||||
|
||||
|
||||
CHECK (!(rM == p1.getID()) );
|
||||
CHECK ( (rM != p1.getID()) );
|
||||
CHECK ( (rM != p2.getID()) );
|
||||
CHECK (!(rM == p2.getID()) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
checkLifecycle (PMObj const& p1, PMObj const& p2)
|
||||
{
|
||||
CHECK (checkUseCount(p1, 0));
|
||||
CHECK (checkUseCount(p2, 0));
|
||||
|
||||
|
||||
MORef<Clip> rMO;
|
||||
CHECK (!rMO);
|
||||
CHECK (0 == rMO.use_count());
|
||||
|
||||
|
||||
rMO.activate(p1);
|
||||
CHECK (rMO);
|
||||
CHECK (rMO->getMedia()->getFilename() == "test-1");
|
||||
CHECK (checkUseCount(rMO, 1));
|
||||
CHECK (checkUseCount(p1, 1)); // sharing ownership
|
||||
CHECK (checkUseCount(p2, 0));
|
||||
|
||||
|
||||
rMO.activate(p2);
|
||||
CHECK (rMO);
|
||||
CHECK (rMO->getMedia()->getFilename() == "test-2");
|
||||
CHECK (checkUseCount(rMO, 1));
|
||||
CHECK (checkUseCount(p1, 0)); // detached, use count dropped to previous value
|
||||
CHECK (checkUseCount(p2, 1)); // sharing ownership
|
||||
|
||||
|
||||
rMO.activate(p2);
|
||||
CHECK (checkUseCount(rMO, 1)); // no change
|
||||
|
||||
|
||||
rMO.close();
|
||||
CHECK (!rMO);
|
||||
CHECK (checkUseCount(p1, 0));
|
||||
CHECK (checkUseCount(p2, 0));
|
||||
|
||||
|
||||
VERIFY_ERROR (BOTTOM_MOBJECTREF, rMO.getPlacement() );
|
||||
VERIFY_ERROR (BOTTOM_MOBJECTREF, rMO->getMedia() );
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
checkTypeHandling (LumieraUid luid)
|
||||
{
|
||||
MObjectRef rMObj;
|
||||
MORef<Clip> rClip;
|
||||
MORef<TestSubMO1> rSub1;
|
||||
|
||||
|
||||
CHECK ( ! rMObj.use_count());
|
||||
CHECK ( ! rClip.use_count());
|
||||
CHECK ( ! rSub1.use_count());
|
||||
|
||||
|
||||
rMObj.activate(luid);
|
||||
CHECK (checkUseCount(rMObj, 1));
|
||||
CHECK ( ! rClip.use_count());
|
||||
CHECK ( ! rSub1.use_count());
|
||||
|
||||
|
||||
rClip.activate(rMObj); // attach on existing MObjectRef
|
||||
CHECK (checkUseCount(rMObj, 2));
|
||||
CHECK (checkUseCount(rClip, 2));
|
||||
CHECK ( ! rSub1.use_count());
|
||||
|
||||
|
||||
// impossible, because Clip isn't a subclass of TestSubMO1:
|
||||
VERIFY_ERROR (INVALID_PLACEMENTREF, rSub1.activate(luid) );
|
||||
VERIFY_ERROR (INVALID_PLACEMENTREF, rSub1 = rMObj );
|
||||
|
||||
|
||||
CHECK (rMObj->isValid());
|
||||
CHECK (rClip->isValid());
|
||||
CHECK (rMObj.getPlacement().getID() == rClip.getPlacement().getID());
|
||||
|
||||
|
||||
// doesn't compile, because the function isn't on MObject API:
|
||||
// rMObj->getMedia();
|
||||
|
||||
|
||||
rClip.close();
|
||||
CHECK (checkUseCount(rMObj, 1));
|
||||
CHECK ( ! rClip.use_count());
|
||||
|
||||
|
||||
// can assign, because the actual type is checked:
|
||||
rClip = rMObj;
|
||||
CHECK (checkUseCount(rMObj, 2));
|
||||
CHECK (checkUseCount(rClip, 2));
|
||||
|
||||
|
||||
cout << string(rClip) << endl; //////////TICKET #527
|
||||
cout << string(rClip->getMedia()->ident) << endl; //////////TICKET #520
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (MObjectRef_test, "unit session");
|
||||
|
||||
|
||||
|
||||
|
||||
}} // namespace mobject::test
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ namespace test {
|
|||
{
|
||||
PPipe srcP = Pipe::lookup (sourcePipeID);
|
||||
format queryPattern ("id(master_%1%), stream(%1%), ord(%2%)");
|
||||
return Query<Pipe> (queryPattern % srcP->getStreamID() % seqNr);
|
||||
return Query<Pipe> (str(queryPattern % srcP->getStreamID().getSym() % seqNr));
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -44,10 +44,10 @@ using std::endl;
|
|||
namespace mobject {
|
||||
namespace session {
|
||||
namespace test {
|
||||
|
||||
|
||||
using namespace mobject::test;
|
||||
typedef TestPlacement<TestSubMO21> PSub;
|
||||
|
||||
|
||||
typedef PlacementMO::ID P_ID;
|
||||
|
||||
|
||||
|
|
@ -65,68 +65,68 @@ namespace test {
|
|||
*/
|
||||
class PlacementRef_test : public Test
|
||||
{
|
||||
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
PSub testPlacement1(*new TestSubMO21);
|
||||
PSub testPlacement2(*new TestSubMO21);
|
||||
testPlacement2.chain(Time(2)); // define start time of Placement-2 to be at t=2
|
||||
|
||||
|
||||
// Prepare an (test)Index backing the PlacementRefs
|
||||
PPIdx index = SessionServiceMockIndex::install();
|
||||
PMO& root = index->getRoot();
|
||||
|
||||
|
||||
P_ID id1 = index->insert (testPlacement1, root);
|
||||
P_ID tmpID = index->insert (testPlacement2, root);
|
||||
CHECK (2 == index->size());
|
||||
|
||||
|
||||
// References to the "live" placements within our test index
|
||||
PMO& p1 = index->find(id1);
|
||||
PMO& p2 = index->find(tmpID);
|
||||
|
||||
|
||||
PlacementMO::Id<TestSubMO21> id2 = p2.recastID<TestSubMO21>();
|
||||
CHECK (id2);
|
||||
CHECK (id2 != p1.getID());
|
||||
|
||||
|
||||
// create placement refs
|
||||
PlacementRef<TestSubMO21> ref1 (p1);
|
||||
PlacementRef<TestSubMO21> ref2 (id2);
|
||||
|
||||
|
||||
PlacementRef<MObject> refX (ref2);
|
||||
|
||||
|
||||
CHECK (ref1);
|
||||
CHECK (ref2);
|
||||
CHECK (refX);
|
||||
CHECK (ref1 != ref2);
|
||||
CHECK (ref2 == refX);
|
||||
|
||||
|
||||
// indeed a "reference": resolves to the same memory location
|
||||
CHECK (isSameObject (p1, *ref1));
|
||||
CHECK (isSameObject (p2, *ref2));
|
||||
CHECK (isSameObject (p2, *refX));
|
||||
|
||||
|
||||
cout << string(*ref1) << endl;
|
||||
cout << string(*ref2) << endl;
|
||||
cout << string(*refX) << endl;
|
||||
|
||||
|
||||
// PlacementRef mimics placement behaviour
|
||||
ref1->specialAPI();
|
||||
CHECK (2 == ref1.use_count());
|
||||
CHECK (2 == ref2.use_count());
|
||||
ExplicitPlacement exPla = refX.resolve();
|
||||
CHECK (exPla.time == Time(2)); // indeed get back the time we set on p2 above
|
||||
CHECK (3 == ref2.use_count()); // exPla shares ownership with p2
|
||||
|
||||
CHECK (index->contains(ref1)); // ref can stand-in for a placement-ID
|
||||
CHECK (sizeof(id2) == sizeof(ref2)); // (and is actually implemented based on an ID)
|
||||
|
||||
CHECK (exPla.time == Time(2)); // indeed get back the time we set on p2 above
|
||||
CHECK (3 == ref2.use_count()); // exPla shares ownership with p2
|
||||
|
||||
CHECK (index->contains(ref1)); // ref can stand-in for a placement-ID
|
||||
CHECK (sizeof(id2) == sizeof(ref2)); // (and is actually implemented based on an ID)
|
||||
|
||||
// assignment on placement refs
|
||||
refX = ref1;
|
||||
CHECK (ref1 != ref2);
|
||||
CHECK (ref1 == refX);
|
||||
CHECK (ref2 != refX);
|
||||
|
||||
|
||||
// re-assignment with a new placement
|
||||
refX = p2;
|
||||
CHECK (refX == ref2);
|
||||
|
|
@ -135,7 +135,7 @@ namespace test {
|
|||
CHECK (refX == ref1);
|
||||
CHECK (refX != ref2);
|
||||
CHECK (isSameObject (*refX, p1));
|
||||
|
||||
|
||||
LumieraUid luid2 (p2.getID().get());
|
||||
refX = luid2; // assignment works even based on a plain LUID
|
||||
ref2 = ref1;
|
||||
|
|
@ -151,40 +151,40 @@ namespace test {
|
|||
CHECK (ref1 != ref2);
|
||||
CHECK (ref1 == refX);
|
||||
CHECK (ref2 != refX);
|
||||
|
||||
|
||||
// resolution is indeed "live", we see changes to the referred placement
|
||||
CHECK (refX.resolve().time == Time::MIN);
|
||||
p1.chain = p2.chain; // do a change on the placement within index....
|
||||
CHECK (refX.resolve().time == Time(2)); // now we get the time tie we originally set on p2
|
||||
|
||||
CHECK (p1.getID() != p2.getID()); // but the instance identities are still unaltered
|
||||
CHECK (refX.resolve().time == Time(2)); // now we get the time tie we originally set on p2
|
||||
|
||||
CHECK (p1.getID() != p2.getID()); // but the instance identities are still unaltered
|
||||
CHECK (2 == ref1.use_count());
|
||||
CHECK (3 == ref2.use_count()); // one more because of shared ownership with exPla
|
||||
|
||||
|
||||
CHECK (3 == ref2.use_count()); // one more because of shared ownership with exPla
|
||||
|
||||
|
||||
// actively removing p2 invalidates the other refs to
|
||||
index->remove (ref1);
|
||||
CHECK (!ref1); // checks invalidity without throwing
|
||||
CHECK (!ref1); // checks invalidity without throwing
|
||||
CHECK (!refX);
|
||||
VERIFY_ERROR(NOT_IN_SESSION, *ref1 );
|
||||
|
||||
|
||||
// deliberately create an invalid PlacementRef
|
||||
PlacementRef<TestSubMO21> bottom;
|
||||
CHECK (!bottom);
|
||||
VERIFY_ERROR(BOTTOM_PLACEMENTREF, *bottom );
|
||||
VERIFY_ERROR(BOTTOM_PLACEMENTREF, bottom->specialAPI() );
|
||||
VERIFY_ERROR(BOTTOM_PLACEMENTREF, bottom.resolve() );
|
||||
|
||||
|
||||
//consistency check; then reset PlacementRef index to default
|
||||
CHECK (1 == index->size());
|
||||
CHECK (index->isValid());
|
||||
index.reset();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (PlacementRef_test, "unit session");
|
||||
|
||||
|
||||
|
||||
|
||||
}}} // namespace mobject::session::test
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@
|
|||
#include "common/configrules.hpp"
|
||||
#include "proc/assetmanager.hpp"
|
||||
#include "proc/mobject/session.hpp"
|
||||
#include "lib/streamtype.hpp"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
|
|
@ -49,9 +50,10 @@ namespace asset {
|
|||
|
||||
using lumiera::ConfigRules;
|
||||
using lumiera::query::QueryHandler;
|
||||
|
||||
|
||||
|
||||
using lumiera::StreamType;
|
||||
|
||||
|
||||
|
||||
/** shortcut: query for given Pipe-ID */
|
||||
bool
|
||||
find (const string& pID)
|
||||
|
|
@ -94,29 +96,30 @@ namespace asset {
|
|||
define_and_search ()
|
||||
{
|
||||
string sID = newID ("stream");
|
||||
|
||||
// create Pipes explicitly
|
||||
StreamType::ID stID (sID);
|
||||
|
||||
// create Pipes explicitly
|
||||
// (without utilising default queries)
|
||||
PPipe pipe1 = Struct::retrieve.newPipe (newID("pipe"), newID("stream"));
|
||||
PPipe pipe2 = Struct::retrieve.newPipe (newID("pipe"), sID );
|
||||
|
||||
|
||||
CHECK (pipe1 != pipe2);
|
||||
CHECK (sID == pipe2->getStreamID());
|
||||
|
||||
CHECK (stID == pipe2->getStreamID());
|
||||
|
||||
CHECK (!find (pipe1->getPipeID()), "accidental clash of random test-IDs");
|
||||
CHECK (!find (pipe2->getPipeID()), "accidental clash of random test-IDs");
|
||||
|
||||
|
||||
// now declare that these objects should be considered "default"
|
||||
lumiera::query::setFakeBypass(""); /////////////////////////////////////////////////TODO mock resolution
|
||||
CHECK (Session::current->defaults.define (pipe1, Query<Pipe> (""))); // unrestricted default
|
||||
lumiera::query::setFakeBypass(""); /////////////////////////////////////////////////TODO mock resolution
|
||||
CHECK (Session::current->defaults.define (pipe1, Query<Pipe> (""))); // unrestricted default
|
||||
|
||||
lumiera::query::setFakeBypass("stream("+sID+")"); ///////////////////////////////////TODO mock resolution
|
||||
lumiera::query::setFakeBypass("stream("+sID+")"); ///////////////////////////////////TODO mock resolution
|
||||
CHECK (Session::current->defaults.define (pipe2, Query<Pipe> ("stream("+sID+")")));
|
||||
|
||||
|
||||
CHECK ( find (pipe1->getPipeID()), "failure declaring object as default");
|
||||
CHECK ( find (pipe2->getPipeID()), "failure declaring object as default");
|
||||
|
||||
CHECK (sID != pipe1->getStreamID(), "accidental clash");
|
||||
|
||||
CHECK (stID != pipe1->getStreamID(), "accidental clash");
|
||||
CHECK (!Session::current->defaults.define (pipe1, Query<Pipe> ("stream("+sID+")")));
|
||||
// can't be registered with this query, due to failure caused by wrong stream-ID
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@
|
|||
#include "proc/asset/pipe.hpp"
|
||||
#include "proc/assetmanager.hpp"
|
||||
#include "proc/mobject/session.hpp"
|
||||
#include "lib/streamtype.hpp"
|
||||
|
||||
#include <boost/format.hpp>
|
||||
|
||||
|
|
@ -49,8 +50,9 @@ namespace test {
|
|||
using mobject::Session;
|
||||
using lumiera::Query;
|
||||
using lumiera::query::normaliseID;
|
||||
|
||||
|
||||
using lumiera::StreamType;
|
||||
|
||||
|
||||
/** shortcut: run just a query
|
||||
* without creating new instances
|
||||
*/
|
||||
|
|
@ -117,7 +119,7 @@ namespace test {
|
|||
retrieveConstrainedDefault (string pID, string sID)
|
||||
{
|
||||
PPipe pipe1 = Pipe::query (""); // "the default pipe"
|
||||
CHECK (sID != pipe1->getStreamID(),
|
||||
CHECK ( pipe1->getStreamID() != StreamType::ID(sID),
|
||||
"stream-ID \"%s\" not suitable for test, because "
|
||||
"the default-pipe \"%s\" happens to have the same "
|
||||
"stream-ID. We need it to be different",
|
||||
|
|
@ -126,7 +128,7 @@ namespace test {
|
|||
|
||||
string query_for_sID ("stream("+sID+")");
|
||||
PPipe pipe2 = Pipe::query (query_for_sID);
|
||||
CHECK (sID == pipe2->getStreamID());
|
||||
CHECK (pipe2->getStreamID() == StreamType::ID(sID));
|
||||
CHECK (pipe2 != pipe1);
|
||||
CHECK (pipe2 == Pipe::query (query_for_sID)); // reproducible
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,12 +45,12 @@ using std::endl;
|
|||
namespace mobject {
|
||||
namespace session {
|
||||
namespace test {
|
||||
|
||||
|
||||
using session::test::TestClip;
|
||||
|
||||
|
||||
typedef PlacementIndex& Idx;
|
||||
|
||||
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* @test basic behaviour of the index mechanism used to keep track
|
||||
* of individual Placements as added to the current Session.
|
||||
|
|
@ -61,56 +61,56 @@ namespace test {
|
|||
*/
|
||||
class PlacementIndex_test : public Test
|
||||
{
|
||||
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
PlacementIndex index (make_dummyRoot());
|
||||
CHECK (index.isValid());
|
||||
|
||||
|
||||
checkSimpleInsertRemove (index);
|
||||
has_size (0, index);
|
||||
|
||||
|
||||
PMO::ID elmID = checkSimpleAccess (index);
|
||||
CHECK (index.isValid());
|
||||
has_size (2, index);
|
||||
|
||||
|
||||
checkTypedAccess (index, elmID);
|
||||
has_size (3, index);
|
||||
|
||||
|
||||
checkScopeHandling (index);
|
||||
has_size (9, index);
|
||||
|
||||
|
||||
checkContentsEnumeration (index);
|
||||
|
||||
|
||||
has_size (9, index);
|
||||
CHECK (index.isValid());
|
||||
|
||||
|
||||
index.clear();
|
||||
has_size (0, index);
|
||||
CHECK (index.isValid());
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
has_size(uint siz, Idx index)
|
||||
{
|
||||
CHECK (siz == index.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
checkSimpleInsertRemove (Idx index)
|
||||
{
|
||||
PMO clip = TestClip::create();
|
||||
PMO& root = index.getRoot();
|
||||
|
||||
|
||||
CHECK (0 == index.size());
|
||||
|
||||
|
||||
PMO::ID elmID = index.insert (clip, root);
|
||||
CHECK (1 == index.size());
|
||||
CHECK ( index.contains (elmID));
|
||||
CHECK (!index.contains (clip)); // index stores copies
|
||||
|
||||
CHECK (!index.contains (clip)); // index stores copies
|
||||
|
||||
index.remove(clip); // has no effect
|
||||
CHECK (1 == index.size());
|
||||
index.remove(elmID);
|
||||
|
|
@ -118,67 +118,67 @@ namespace test {
|
|||
CHECK (!index.contains (elmID));
|
||||
CHECK ( index.contains (root));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
PMO::ID
|
||||
checkSimpleAccess (Idx index)
|
||||
{
|
||||
PMO testObj = TestClip::create();
|
||||
PMO& root = index.getRoot();
|
||||
PMO::ID elmID = index.insert (testObj, root);
|
||||
|
||||
|
||||
PMO& elm = index.find(elmID);
|
||||
CHECK (elmID == elm.getID());
|
||||
CHECK (!isSameObject (elm,testObj)); // note: placements are registered as copy
|
||||
CHECK (isSameDef(elm,testObj)); // they are semantically equivalent ////////TICKET #511
|
||||
CHECK (elmID != testObj.getID()); // but have a distinct identity
|
||||
|
||||
CHECK (!isSameObject (elm,testObj)); // note: placements are registered as copy
|
||||
CHECK (isSameDef(elm,testObj)); // they are semantically equivalent ////////TICKET #511
|
||||
CHECK (elmID != testObj.getID()); // but have a distinct identity
|
||||
|
||||
PMO::ID elmID2 = index.insert(testObj, root);
|
||||
CHECK (elmID2 != elmID); // ...and each insert creates a new instance
|
||||
CHECK (elmID2 != elmID); // ...and each insert creates a new instance
|
||||
CHECK (testObj != index.find (elmID));
|
||||
CHECK (testObj != index.find (elmID2));
|
||||
CHECK (isSameDef(testObj, index.find(elmID)));
|
||||
CHECK (isSameDef(testObj, index.find(elmID2)));
|
||||
CHECK (!isSameObject (testObj, index.find(elmID2)));
|
||||
CHECK (!isSameObject (elm, index.find(elmID2)));
|
||||
|
||||
|
||||
// can repeatedly retrieve a reference to the same object
|
||||
CHECK ( isSameObject (elm, index.find(elmID )));
|
||||
CHECK ( isSameObject (elm, index.find(elmID )));
|
||||
|
||||
|
||||
// can also re-access objects by previous ref
|
||||
CHECK ( isSameObject (elm, index.find(elm)));
|
||||
return elmID;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
checkTypedAccess (Idx index, PMO::ID elmID)
|
||||
{
|
||||
PMO& elm = index.find(elmID);
|
||||
CHECK (elmID == elm.getID());
|
||||
|
||||
|
||||
typedef Placement<Clip> PClip;
|
||||
PClip anotherTestClip = TestClip::create();
|
||||
|
||||
|
||||
typedef PlacementMO::Id<Clip> IDClip;
|
||||
IDClip clipID = index.insert(anotherTestClip, elmID);
|
||||
// retaining the more specific type info
|
||||
|
||||
|
||||
// access as MObject...
|
||||
PMO::ID mID = clipID;
|
||||
PMO& asMO = index.find(mID);
|
||||
|
||||
|
||||
// access as Clip
|
||||
PClip& asClip = index.find(clipID);
|
||||
CHECK (LENGTH_TestClip == asClip->getMedia()->getLength()); // using the Clip API
|
||||
|
||||
|
||||
CHECK ( isSameObject(asMO,asClip));
|
||||
CHECK (!isSameObject(asClip, anotherTestClip)); // always inserting a copy into the PlacementIndex
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
checkInvalidRef (Idx index)
|
||||
{
|
||||
|
|
@ -186,26 +186,26 @@ namespace test {
|
|||
PlacementMO::ID invalidID (invalid);
|
||||
CHECK (!bool(invalidID));
|
||||
CHECK (!bool(invalid));
|
||||
|
||||
|
||||
VERIFY_ERROR(BOTTOM_PLACEMENTREF, index.find(invalid) );
|
||||
VERIFY_ERROR(BOTTOM_PLACEMENTREF, index.find(invalidID) );
|
||||
VERIFY_ERROR(BOTTOM_PLACEMENTREF, index.getScope(invalidID) );
|
||||
|
||||
|
||||
CHECK (!index.contains(invalidID));
|
||||
|
||||
|
||||
PMO testObj = TestClip::create();
|
||||
VERIFY_ERROR(INVALID_SCOPE, index.insert(testObj, invalidID) );
|
||||
|
||||
|
||||
CHECK (false == index.remove(invalidID));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
checkScopeHandling (Idx index)
|
||||
{
|
||||
PMO testObj = TestClip::create();
|
||||
PMO& root = index.getRoot();
|
||||
|
||||
|
||||
typedef PMO::ID ID;
|
||||
ID e1 = index.insert (testObj, root);
|
||||
ID e11 = index.insert (testObj, e1);
|
||||
|
|
@ -215,7 +215,7 @@ namespace test {
|
|||
ID e132 = index.insert (testObj, e13);
|
||||
ID e133 = index.insert (testObj, e13);
|
||||
ID e1331 = index.insert (testObj, e133);
|
||||
|
||||
|
||||
CHECK (index.isValid());
|
||||
CHECK (root == index.getScope(e1));
|
||||
CHECK (e1 == index.getScope(e11).getID());
|
||||
|
|
@ -227,22 +227,22 @@ namespace test {
|
|||
CHECK (e133 == index.getScope(e1331).getID());
|
||||
CHECK (e1 != e13);
|
||||
CHECK (e13 != e133);
|
||||
|
||||
|
||||
CHECK (index.getScope(e11) == index.getScope(index.find(e11)));
|
||||
CHECK (index.getScope(e131) == index.getScope(index.find(e131)));
|
||||
|
||||
|
||||
VERIFY_ERROR(NONEMPTY_SCOPE, index.remove(e13) ); // can't remove a scope-constituting element
|
||||
VERIFY_ERROR(NONEMPTY_SCOPE, index.remove(e133) );
|
||||
|
||||
|
||||
CHECK (index.contains(e1331));
|
||||
CHECK (index.remove(e1331));
|
||||
CHECK (!index.contains(e1331));
|
||||
CHECK (!index.remove(e1331));
|
||||
|
||||
CHECK (index.remove(e133)); // but can remove an scope, after emptying it
|
||||
|
||||
CHECK (index.remove(e133)); // but can remove an scope, after emptying it
|
||||
CHECK (!index.contains(e133));
|
||||
CHECK (index.isValid());
|
||||
|
||||
|
||||
// build a complete new subtree
|
||||
uint siz = index.size();
|
||||
ID e1321 = index.insert (testObj, e132);
|
||||
|
|
@ -258,7 +258,7 @@ namespace test {
|
|||
ID e132142 = index.insert (testObj, e13214);
|
||||
ID e132143 = index.insert (testObj, e13214);
|
||||
ID e132144 = index.insert (testObj, e13214);
|
||||
|
||||
|
||||
// ...and kill it recursively in one sway
|
||||
index.clear (e1321);
|
||||
CHECK (!index.contains (e1321));
|
||||
|
|
@ -269,11 +269,11 @@ namespace test {
|
|||
CHECK (siz == index.size());
|
||||
CHECK (index.isValid());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
typedef PlacementIndex::iterator Iter;
|
||||
|
||||
|
||||
/** @test drill down into the tree-like structure
|
||||
* and enumerate the contents of each element, if any
|
||||
*/
|
||||
|
|
@ -281,14 +281,14 @@ namespace test {
|
|||
checkContentsEnumeration (Idx index)
|
||||
{
|
||||
PMO& root = index.getRoot();
|
||||
|
||||
|
||||
Iter rootContents = index.getReferrers (root.getID());
|
||||
CHECK (rootContents);
|
||||
|
||||
|
||||
discover (index, rootContents, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
discover (Idx index, Iter iter, uint level)
|
||||
{
|
||||
|
|
@ -296,30 +296,30 @@ namespace test {
|
|||
for ( ; iter; ++iter )
|
||||
{
|
||||
cout << indent(level) << "::" << string(*iter) << endl;
|
||||
|
||||
|
||||
++count;
|
||||
Iter scopeContents = index.getReferrers (iter->getID());
|
||||
if (scopeContents)
|
||||
discover (index, scopeContents, level+1);
|
||||
}
|
||||
|
||||
|
||||
static format summary ("...%i elements at Level %i");
|
||||
cout << indent(level) << summary % count % level << endl;
|
||||
|
||||
|
||||
CHECK (!iter);
|
||||
CHECK (0 < count);
|
||||
}
|
||||
|
||||
|
||||
static string
|
||||
indent (uint level)
|
||||
{
|
||||
return string (level, ' ');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (PlacementIndex_test, "unit session");
|
||||
|
||||
|
||||
|
||||
|
||||
}}} // namespace mobject::session::test
|
||||
|
|
|
|||
|
|
@ -134,7 +134,7 @@ namespace test {
|
|||
{
|
||||
QueryFocus original; // automatically attaches to current stack top
|
||||
uint num_refs = refs (original);
|
||||
CHECK (num_refs > 1); // because the run() function also holds a ref
|
||||
CHECK (num_refs > 1); // because the run() function also holds a ref
|
||||
|
||||
QueryFocus subF = QueryFocus::push();
|
||||
cout << string(subF) << endl;
|
||||
|
|
@ -161,7 +161,7 @@ namespace test {
|
|||
subF2.pop(); // releasing this focus and re-attaching to what's on stack top
|
||||
cout << string(subF2) << "<<<--after pop()" << endl;
|
||||
CHECK (subF2 == subF);
|
||||
CHECK (2 == refs(subF2)); // both are now attached to the same path
|
||||
CHECK (2 == refs(subF2)); // both are now attached to the same path
|
||||
CHECK (2 == refs(subF));
|
||||
}
|
||||
// subF2 went out of scope, but no auto-pop happens (because subF is still there)
|
||||
|
|
|
|||
|
|
@ -84,7 +84,7 @@ test_lib_SOURCES = \
|
|||
$(testlib_srcdir)/sanitised-identifier-test.cpp \
|
||||
$(testlib_srcdir)/scoped-holder-test.cpp \
|
||||
$(testlib_srcdir)/scoped-ptrvect-test.cpp \
|
||||
$(testlib_srcdir)/scopedholdertransfertest.cpp \
|
||||
$(testlib_srcdir)/scoped-holder-transfer-test.cpp \
|
||||
$(testlib_srcdir)/singleton-subclass-test.cpp \
|
||||
$(testlib_srcdir)/singleton-test.cpp \
|
||||
$(testlib_srcdir)/singletontestmocktest.cpp \
|
||||
|
|
@ -106,7 +106,7 @@ test_lib_SOURCES = \
|
|||
$(testlib_srcdir)/typed-allocation-manager-test.cpp \
|
||||
$(testlib_srcdir)/typed-counter-test.cpp \
|
||||
$(testlib_srcdir)/util-foreach-test.cpp \
|
||||
$(testlib_srcdir)/vectortransfertest.cpp \
|
||||
$(testlib_srcdir)/vector-transfer-test.cpp \
|
||||
$(testlib_srcdir)/visitingtoolconcept.cpp \
|
||||
$(testlib_srcdir)/visitingtoolextendedtest.cpp \
|
||||
$(testlib_srcdir)/visitingtooltest.cpp
|
||||
|
|
|
|||
|
|
@ -33,37 +33,37 @@
|
|||
|
||||
namespace lib {
|
||||
namespace test{
|
||||
|
||||
|
||||
using lumiera::P;
|
||||
using std::string;
|
||||
using std::tr1::shared_ptr;
|
||||
using std::tr1::weak_ptr;
|
||||
|
||||
|
||||
using lumiera::error::LUMIERA_ERROR_ASSERTION;
|
||||
|
||||
|
||||
|
||||
|
||||
struct X
|
||||
: boost::totally_ordered<X>
|
||||
{
|
||||
long x_;
|
||||
|
||||
|
||||
X(long x=0) : x_(x) {}
|
||||
operator long () { return x_; }
|
||||
|
||||
|
||||
bool operator< (const X& ox) const { return x_ < ox.x_; }
|
||||
bool operator== (const X& ox) const { return x_ == ox.x_; }
|
||||
|
||||
|
||||
virtual ~X() {} // using RTTI
|
||||
};
|
||||
|
||||
|
||||
struct XX : public X
|
||||
{
|
||||
long xx_;
|
||||
|
||||
|
||||
XX(long x=0) : X(x), xx_(x+1) {}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/****************************************************************
|
||||
* @test assure correct behaviour of lumiera's custom shared-ptr,
|
||||
* including ADL of operators, shared ownership, typing
|
||||
|
|
@ -80,8 +80,8 @@ namespace test{
|
|||
check_type_relations ();
|
||||
check_ordering ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test smart-ptr basic behaviour */
|
||||
void
|
||||
check_refcounting ()
|
||||
|
|
@ -90,84 +90,84 @@ namespace test{
|
|||
CHECK (p1);
|
||||
CHECK (1 == p1.use_count());
|
||||
CHECK (7 == p1->x_);
|
||||
|
||||
|
||||
{
|
||||
P<X> p2 (new X(9));
|
||||
CHECK (1 == p2.use_count());
|
||||
|
||||
|
||||
p2.swap (p1);
|
||||
CHECK (1 == p1.use_count());
|
||||
CHECK (1 == p2.use_count());
|
||||
|
||||
|
||||
p2 = p1;
|
||||
CHECK (2 == p1.use_count());
|
||||
CHECK (2 == p2.use_count());
|
||||
}
|
||||
|
||||
|
||||
CHECK (1 == p1.use_count());
|
||||
CHECK (9 == p1->x_);
|
||||
|
||||
|
||||
p1.reset();
|
||||
CHECK (0 == p1.use_count());
|
||||
CHECK (!p1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test cooperation with other shared-ptr types */
|
||||
void
|
||||
check_shared_ownership ()
|
||||
{
|
||||
std::auto_ptr<X> au (new X(22));
|
||||
CHECK (au.get());
|
||||
|
||||
|
||||
P<X> pX (au);
|
||||
CHECK (!au.get());
|
||||
CHECK (pX);
|
||||
CHECK (1 == pX.use_count());
|
||||
CHECK (22 == pX->x_);
|
||||
|
||||
|
||||
weak_ptr<X> wX (pX);
|
||||
CHECK (wX.lock());
|
||||
CHECK (1 == pX.use_count());
|
||||
|
||||
|
||||
shared_ptr<X> sp1 (wX);
|
||||
shared_ptr<X> sp2 (pX);
|
||||
shared_ptr<X> sp3; sp3 = pX;
|
||||
|
||||
|
||||
CHECK (22 == sp3->x_);
|
||||
CHECK (4 == pX.use_count());
|
||||
CHECK (*pX == *sp1);
|
||||
CHECK (*sp1 == *sp2);
|
||||
CHECK (*sp2 == *sp3);
|
||||
|
||||
|
||||
P<X> pX2;
|
||||
pX2.swap(pX);
|
||||
CHECK (!pX);
|
||||
CHECK (0 == pX.use_count());
|
||||
CHECK (4 == pX2.use_count());
|
||||
|
||||
|
||||
P<X, P<X> > pXX (pX2); // a different type, but compatible pointers
|
||||
pX2 = pX;
|
||||
CHECK (!pX2);
|
||||
CHECK (0 == pX2.use_count());
|
||||
CHECK (4 == pXX.use_count());
|
||||
|
||||
|
||||
sp3 = sp2 = sp1 = pX;
|
||||
CHECK (22 == pXX->x_);
|
||||
CHECK (1 == pXX.use_count());
|
||||
CHECK (!sp1);
|
||||
CHECK (!sp2);
|
||||
CHECK (!sp3);
|
||||
|
||||
|
||||
CHECK (22 == wX.lock()->x_);
|
||||
CHECK (1 == pXX.use_count());
|
||||
|
||||
|
||||
pXX.reset();
|
||||
CHECK (!pXX);
|
||||
CHECK (!wX.lock());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test building type relationships on smart-ptrs */
|
||||
void
|
||||
check_type_relations ()
|
||||
|
|
@ -179,34 +179,34 @@ namespace test{
|
|||
P<XX,shared_ptr<long> > pLo;// Base: shared_ptr<long> (rather nonsense, but well...)
|
||||
P<X,string> pLoL; // Base: std::string
|
||||
P<string> pLoLoL; // Base: shared_ptr<string>
|
||||
|
||||
|
||||
CHECK (INSTANCEOF (shared_ptr<X>, &pX));
|
||||
|
||||
|
||||
CHECK ( INSTANCEOF (shared_ptr<XX>, &pX1));
|
||||
// CHECK (!INSTANCEOF (shared_ptr<X>, &pX1)); // doesn't compile (no RTTI) -- that's correct
|
||||
// CHECK (!INSTANCEOF (P<X>, &pX1)); // similar, type mismatch detected by compiler
|
||||
|
||||
// CHECK (!INSTANCEOF (shared_ptr<X>, &pX1)); // doesn't compile (no RTTI) -- that's correct
|
||||
// CHECK (!INSTANCEOF (P<X>, &pX1)); // similar, type mismatch detected by compiler
|
||||
|
||||
CHECK ( INSTANCEOF (shared_ptr<X>, &pX2));
|
||||
// CHECK (!INSTANCEOF (shared_ptr<XX>, &pX2));
|
||||
CHECK ( INSTANCEOF (P<X>, &pX2));
|
||||
|
||||
|
||||
CHECK ( INSTANCEOF (shared_ptr<X>, &pX3));
|
||||
// CHECK (!INSTANCEOF (shared_ptr<XX>, &pX3));
|
||||
// CHECK (!INSTANCEOF (P<X>, &pX3));
|
||||
|
||||
|
||||
CHECK ( INSTANCEOF (shared_ptr<long>, &pLo));
|
||||
// CHECK (!INSTANCEOF (shared_ptr<X>, &pLo));
|
||||
// CHECK (!INSTANCEOF (P<X>, &pLo));
|
||||
|
||||
|
||||
// CHECK (!INSTANCEOF (shared_ptr<long>, &pLoL));
|
||||
// CHECK (!INSTANCEOF (shared_ptr<X>, &pLoL));
|
||||
// CHECK (!INSTANCEOF (P<X>, &pLoL));
|
||||
CHECK ( INSTANCEOF (string, &pLoL));
|
||||
|
||||
|
||||
CHECK ( INSTANCEOF (shared_ptr<string>, &pLoLoL));
|
||||
// CHECK (!INSTANCEOF (string, &pLoLoL));
|
||||
// CHECK (!INSTANCEOF (shared_ptr<X>, &pLoLoL));
|
||||
|
||||
|
||||
pX = pX1; // OK: pointee subtype...
|
||||
pX = pX2; // invokes shared_ptr<X>::operator= (shared_ptr<X> const&)
|
||||
pX = pX3;
|
||||
|
|
@ -215,99 +215,99 @@ namespace test{
|
|||
// pX = pLoLoL; // same...
|
||||
// you won't be able to do much with the "LoLo"-Types,
|
||||
// as their types and pointee types's relations don't match
|
||||
|
||||
|
||||
pX.reset (new XX(5));
|
||||
CHECK (5 == *pX); // implicit conversion from X to long
|
||||
|
||||
CHECK (5 == *pX); // implicit conversion from X to long
|
||||
|
||||
pX2 = pX; // works, because both are implemented in terms of shared_ptr<X>
|
||||
CHECK (5 == pX2->x_);
|
||||
CHECK (6 == pX2->xx_); // using the XX interface (performing dynamic downcast)
|
||||
|
||||
CHECK (6 == pX2->xx_); // using the XX interface (performing dynamic downcast)
|
||||
|
||||
pX3.reset (new X(7)); // again works because implemented in terms of shared_ptr<X>
|
||||
pX2 = pX3; // same
|
||||
CHECK (pX2); // both contain indeed a valid pointer....
|
||||
CHECK (pX2); // both contain indeed a valid pointer....
|
||||
CHECK (pX3);
|
||||
CHECK (! pX2.get()); // but dynamic cast to XX at access fails
|
||||
CHECK (! pX2.get()); // but dynamic cast to XX at access fails
|
||||
CHECK (! pX3.get());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test equality and ordering operators forwarded to pointee */
|
||||
void
|
||||
check_ordering ()
|
||||
{
|
||||
typedef P<X> PX;
|
||||
typedef P<XX,PX> PXX;
|
||||
|
||||
|
||||
PX pX1 (new X(3));
|
||||
PX pX2 (new XX(5));
|
||||
PX pX3, pX4, pX5, pX6;
|
||||
PXX pXX (new XX(7));
|
||||
|
||||
|
||||
pX3 = pXX;
|
||||
pX4.reset(new X(*pXX));
|
||||
|
||||
|
||||
CHECK ( (pX1 == pX1)); // reflexivity
|
||||
CHECK (!(pX1 != pX1));
|
||||
CHECK (!(pX1 < pX1));
|
||||
CHECK (!(pX1 > pX1));
|
||||
CHECK ( (pX1 <= pX1));
|
||||
CHECK ( (pX1 >= pX1));
|
||||
|
||||
|
||||
CHECK (!(pX1 == pX2)); // compare to same ptr type with larger pointee of subtype
|
||||
CHECK ( (pX1 != pX2));
|
||||
CHECK ( (pX1 < pX2));
|
||||
CHECK (!(pX1 > pX2));
|
||||
CHECK ( (pX1 <= pX2));
|
||||
CHECK (!(pX1 >= pX2));
|
||||
|
||||
|
||||
CHECK (!(pX2 == pXX)); // compare to ptr subtype with larger pointee of same subtype
|
||||
CHECK ( (pX2 != pXX));
|
||||
CHECK ( (pX2 < pXX));
|
||||
CHECK (!(pX2 > pXX));
|
||||
CHECK ( (pX2 <= pXX));
|
||||
CHECK (!(pX2 >= pXX));
|
||||
|
||||
|
||||
CHECK (!(pX1 == pXX)); // transitively compare to ptr subtype with larger pointee of subtype
|
||||
CHECK ( (pX1 != pXX));
|
||||
CHECK ( (pX1 < pXX));
|
||||
CHECK (!(pX1 > pXX));
|
||||
CHECK ( (pX1 <= pXX));
|
||||
CHECK (!(pX1 >= pXX));
|
||||
|
||||
|
||||
CHECK ( (pX3 == pXX)); // compare ptr to subtype ptr both referring to same pointee
|
||||
CHECK (!(pX3 != pXX));
|
||||
CHECK (!(pX3 < pXX));
|
||||
CHECK (!(pX3 > pXX));
|
||||
CHECK ( (pX3 <= pXX));
|
||||
CHECK ( (pX3 >= pXX));
|
||||
|
||||
|
||||
CHECK ( (pX4 == pXX)); // compare ptr to subtype ptr both referring to different but equal pointees
|
||||
CHECK (!(pX4 != pXX));
|
||||
CHECK (!(pX4 < pXX));
|
||||
CHECK (!(pX4 > pXX));
|
||||
CHECK ( (pX4 <= pXX));
|
||||
CHECK ( (pX4 >= pXX));
|
||||
|
||||
|
||||
CHECK (!(pXX == pX5)); // compare subtype ptr to empty ptr: "unequal but not orderable"
|
||||
CHECK ( (pXX != pX5));
|
||||
|
||||
|
||||
CHECK ( (pX5 == pX6)); // compare two empty ptrs: "equal, equivalent but not orderable"
|
||||
CHECK (!(pX5 != pX6));
|
||||
|
||||
|
||||
// order relations on NIL pointers disallowed
|
||||
|
||||
|
||||
#if false ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT
|
||||
VERIFY_ERROR (ASSERTION, pXX < pX5 );
|
||||
VERIFY_ERROR (ASSERTION, pXX > pX5 );
|
||||
VERIFY_ERROR (ASSERTION, pXX <= pX5 );
|
||||
VERIFY_ERROR (ASSERTION, pXX >= pX5 );
|
||||
|
||||
|
||||
VERIFY_ERROR (ASSERTION, pX5 < pXX );
|
||||
VERIFY_ERROR (ASSERTION, pX5 > pXX );
|
||||
VERIFY_ERROR (ASSERTION, pX5 <= pXX );
|
||||
VERIFY_ERROR (ASSERTION, pX5 >= pXX );
|
||||
|
||||
|
||||
VERIFY_ERROR (ASSERTION, pX5 < pX6 );
|
||||
VERIFY_ERROR (ASSERTION, pX5 > pX6 );
|
||||
VERIFY_ERROR (ASSERTION, pX5 <= pX6 );
|
||||
|
|
@ -315,11 +315,11 @@ namespace test{
|
|||
#endif ///////////////////////////////////////////////////////////////////////////////////////////////TICKET #537 : restore throwing ASSERT
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (CustomSharedPtr_test, "unit common");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
|
|
|||
|
|
@ -39,12 +39,12 @@
|
|||
namespace lib {
|
||||
namespace wrapper {
|
||||
namespace test{
|
||||
|
||||
|
||||
using ::Test;
|
||||
using lib::test::randStr;
|
||||
using lib::test::showSizeof;
|
||||
using util::isSameObject;
|
||||
|
||||
|
||||
using std::tr1::placeholders::_1;
|
||||
using std::tr1::ref;
|
||||
using std::vector;
|
||||
|
|
@ -52,59 +52,57 @@ namespace test{
|
|||
using std::rand;
|
||||
using std::cout;
|
||||
using std::endl;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace { // Test helper: yet another ctor/dtor counting class
|
||||
|
||||
|
||||
long cntTracker = 0;
|
||||
|
||||
|
||||
struct Tracker
|
||||
{
|
||||
uint i_;
|
||||
|
||||
|
||||
Tracker() : i_(rand() % 500) { ++cntTracker; }
|
||||
Tracker(Tracker const& ot) : i_(ot.i_) { ++cntTracker; }
|
||||
~Tracker() { --cntTracker; }
|
||||
};
|
||||
|
||||
|
||||
bool operator== (Tracker const& t1, Tracker const& t2) { return t1.i_ == t2.i_; }
|
||||
bool operator!= (Tracker const& t1, Tracker const& t2) { return t1.i_ != t2.i_; }
|
||||
|
||||
|
||||
|
||||
|
||||
/// to be bound as test function....
|
||||
int&
|
||||
pickElement (vector<int>& vec, size_t idx)
|
||||
{
|
||||
return vec[idx];
|
||||
}
|
||||
|
||||
|
||||
function<int&(size_t)>
|
||||
pickElement_ofVector (vector<int>& vec)
|
||||
{
|
||||
return std::tr1::bind (pickElement, ref(vec), _1 );
|
||||
}
|
||||
|
||||
|
||||
} // (END) Test helpers
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* @test use the ItemWrapper to define inline-storage holding values,
|
||||
* pointers and references. Verify correct behaviour in each case,
|
||||
* including (self)assignment, empty check, invalid dereferentiation.
|
||||
*
|
||||
*
|
||||
* @see wrapper.hpp
|
||||
*/
|
||||
class ItemWrapper_test : public Test
|
||||
{
|
||||
|
||||
|
||||
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
|
|
@ -113,83 +111,83 @@ namespace test{
|
|||
string s1 (randStr(50));
|
||||
string s2 (randStr(50));
|
||||
const char* cp (s1.c_str());
|
||||
|
||||
|
||||
verifyWrapper<ulong> (l1, l2);
|
||||
verifyWrapper<ulong&> (l1, l2);
|
||||
verifyWrapper<ulong*> (&l1, &l2);
|
||||
verifyWrapper<ulong*> ((0), &l2);
|
||||
verifyWrapper<ulong*> (&l1, (0));
|
||||
verifyWrapper<ulong const&> (l1, l2);
|
||||
|
||||
|
||||
verifyWrapper<string> (s1, s2);
|
||||
verifyWrapper<string&> (s1, s2);
|
||||
verifyWrapper<string*> (&s1, &s2);
|
||||
|
||||
|
||||
verifyWrapper<const char*> (cp, "Lumiera");
|
||||
|
||||
|
||||
|
||||
|
||||
verifySaneInstanceHandling();
|
||||
verifyWrappedRef ();
|
||||
|
||||
|
||||
verifyFunctionResult ();
|
||||
verifyFunctionRefResult ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
template<typename X>
|
||||
void
|
||||
verifyWrapper (X val, X otherVal)
|
||||
{
|
||||
const ItemWrapper<X> wrap(val);
|
||||
CHECK (wrap);
|
||||
|
||||
|
||||
cout << "ItemWrapper: " << showSizeof(wrap) << endl;
|
||||
|
||||
|
||||
ItemWrapper<X> copy1 (wrap);
|
||||
ItemWrapper<X> copy2;
|
||||
ItemWrapper<X> empty;
|
||||
|
||||
|
||||
CHECK (copy1);
|
||||
CHECK (!copy2);
|
||||
CHECK (false == bool(empty));
|
||||
|
||||
|
||||
CHECK (wrap == copy1);
|
||||
CHECK (wrap != copy2);
|
||||
CHECK (wrap != empty);
|
||||
|
||||
|
||||
copy2 = copy1;
|
||||
CHECK (copy2);
|
||||
CHECK (wrap == copy2);
|
||||
CHECK (wrap != empty);
|
||||
|
||||
|
||||
copy2 = otherVal;
|
||||
CHECK (copy2);
|
||||
CHECK (wrap != copy2);
|
||||
CHECK (wrap != empty);
|
||||
|
||||
|
||||
CHECK (val == *wrap);
|
||||
CHECK (val == *copy1);
|
||||
CHECK (val != *copy2);
|
||||
VERIFY_ERROR (BOTTOM_VALUE, *empty );
|
||||
|
||||
|
||||
CHECK (otherVal == *copy2);
|
||||
copy1 = copy2;
|
||||
CHECK (otherVal == *copy1);
|
||||
CHECK (otherVal == *copy2);
|
||||
CHECK (wrap != copy1);
|
||||
CHECK (wrap != copy2);
|
||||
|
||||
|
||||
copy1 = empty; // assign empty to discard value
|
||||
copy1 = copy1; // self-assign empty value
|
||||
CHECK (!copy1);
|
||||
|
||||
|
||||
copy1 = copy2;
|
||||
CHECK (otherVal == *copy1);
|
||||
copy1 = copy1; // self-assign (will be suppressed)
|
||||
CHECK (otherVal == *copy1);
|
||||
copy1 = *copy1; // self-assign also detected in this case
|
||||
CHECK (otherVal == *copy2);
|
||||
|
||||
|
||||
CHECK (copy1);
|
||||
copy1.reset();
|
||||
CHECK (!copy1);
|
||||
|
|
@ -197,8 +195,8 @@ namespace test{
|
|||
CHECK (copy2 != copy1);
|
||||
VERIFY_ERROR (BOTTOM_VALUE, *copy1 );
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test verify that ctor and dtor calls are balanced,
|
||||
* even when assigning and self-assigning.
|
||||
*/
|
||||
|
|
@ -209,16 +207,16 @@ namespace test{
|
|||
{
|
||||
Tracker t1;
|
||||
Tracker t2;
|
||||
|
||||
|
||||
verifyWrapper<Tracker> (t1, t2);
|
||||
verifyWrapper<Tracker&> (t1, t2);
|
||||
verifyWrapper<Tracker*> (&t1, &t2);
|
||||
|
||||
|
||||
}
|
||||
CHECK (0 == cntTracker);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test verify especially that we can wrap and handle
|
||||
* a reference "value" in a pointer-like manner
|
||||
*/
|
||||
|
|
@ -228,23 +226,23 @@ namespace test{
|
|||
int x = 5;
|
||||
ItemWrapper<int&> refWrap;
|
||||
CHECK (!refWrap);
|
||||
|
||||
|
||||
refWrap = x;
|
||||
CHECK (refWrap);
|
||||
CHECK (5 == *refWrap);
|
||||
CHECK (x == *refWrap);
|
||||
|
||||
|
||||
*refWrap += 5;
|
||||
CHECK (x == 10);
|
||||
|
||||
|
||||
ItemWrapper<int*> ptrWrap (& *refWrap);
|
||||
CHECK ( isSameObject (**ptrWrap, x));
|
||||
CHECK (!isSameObject ( *ptrWrap, &x));
|
||||
**ptrWrap += 13;
|
||||
CHECK (x == 23);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test verify an extension built on top of the ItemWrapper:
|
||||
* a function which remembers the last result. As a simple test,
|
||||
* we bind the \c rand() standard lib function and remember the
|
||||
|
|
@ -254,17 +252,17 @@ namespace test{
|
|||
verifyFunctionResult()
|
||||
{
|
||||
FunctionResult<int(void)> randomVal (std::rand);
|
||||
|
||||
|
||||
// function was never invoked, thus the remembered result is NIL
|
||||
CHECK (!randomVal);
|
||||
VERIFY_ERROR (BOTTOM_VALUE, *randomVal );
|
||||
|
||||
|
||||
int v1 = randomVal();
|
||||
CHECK (v1 == *randomVal);
|
||||
CHECK (v1 == *randomVal);
|
||||
CHECK (v1 == *randomVal);
|
||||
CHECK (randomVal);
|
||||
|
||||
|
||||
int v2;
|
||||
do v2 = randomVal();
|
||||
while (v1 == v2);
|
||||
|
|
@ -272,8 +270,8 @@ namespace test{
|
|||
CHECK (v2 == *randomVal);
|
||||
CHECK (v1 != *randomVal);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test verify an extension built on top of the ItemWrapper:
|
||||
* a function which remembers the last result. Here we use
|
||||
* a test function, which picks a member of an vector and
|
||||
|
|
@ -288,27 +286,27 @@ namespace test{
|
|||
vector<int> testVec;
|
||||
for (uint i=0; i<10; ++i)
|
||||
testVec.push_back(i);
|
||||
|
||||
|
||||
FunctionResult<int&(size_t)> funRes (pickElement_ofVector(testVec));
|
||||
|
||||
|
||||
// function was never invoked, thus the remembered result is NIL
|
||||
CHECK (!funRes);
|
||||
VERIFY_ERROR (BOTTOM_VALUE, *funRes );
|
||||
|
||||
|
||||
int& r5 = funRes (5);
|
||||
CHECK (funRes); // indicates existence of cached result
|
||||
|
||||
CHECK (funRes); // indicates existence of cached result
|
||||
|
||||
CHECK (5 == r5);
|
||||
CHECK (isSameObject (r5, testVec[5]));
|
||||
|
||||
|
||||
int& r5x = *funRes;
|
||||
CHECK (isSameObject (r5, r5x));
|
||||
|
||||
|
||||
CHECK ( isSameObject (r5, *funRes));
|
||||
int& r7 = funRes (7);
|
||||
CHECK (!isSameObject (r5, *funRes));
|
||||
CHECK ( isSameObject (r7, *funRes));
|
||||
|
||||
|
||||
-- r5x;
|
||||
++ *funRes;
|
||||
CHECK (5-1 == testVec[5]);
|
||||
|
|
@ -316,9 +314,9 @@ namespace test{
|
|||
CHECK (7+1 == r7);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
LAUNCHER (ItemWrapper_test, "unit common");
|
||||
|
||||
|
||||
|
||||
|
||||
}}} // namespace lib::wrapper::test
|
||||
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
namespace lib {
|
||||
namespace test{
|
||||
|
||||
|
||||
using ::Test;
|
||||
using boost::lexical_cast;
|
||||
using util::for_each;
|
||||
|
|
@ -46,74 +46,74 @@ namespace test{
|
|||
using std::cout;
|
||||
using std::endl;
|
||||
using std::rand;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace { // Test data
|
||||
|
||||
|
||||
uint NUM_ELMS = 10;
|
||||
|
||||
|
||||
struct TestSource
|
||||
{
|
||||
vector<int> data_;
|
||||
|
||||
|
||||
TestSource(uint num)
|
||||
{
|
||||
while (num)
|
||||
data_.push_back(num--);
|
||||
}
|
||||
|
||||
|
||||
typedef vector<int>::iterator sourceIter;
|
||||
typedef RangeIter<sourceIter> iterator;
|
||||
|
||||
|
||||
iterator begin() { return iterator(data_.begin(),data_.end()); }
|
||||
iterator end() { return iterator(); }
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
} // (END) Test data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* @test build combined and filtering iterators with the help of lib::IterTool.
|
||||
* Check correct behaviour of the resulting iterators and
|
||||
* verify they fulfil the Lumiera Forward Iterator concept
|
||||
*
|
||||
*
|
||||
* @todo implement more iterator tools.... see Ticket #347
|
||||
*/
|
||||
class IterTools_test : public Test
|
||||
{
|
||||
|
||||
|
||||
typedef TestSource::iterator Iter;
|
||||
|
||||
|
||||
|
||||
|
||||
virtual void
|
||||
run (Arg arg)
|
||||
{
|
||||
if (0 < arg.size()) NUM_ELMS = lexical_cast<uint> (arg[0]);
|
||||
|
||||
|
||||
TestSource source(NUM_ELMS);
|
||||
|
||||
|
||||
pullOut (source.begin());
|
||||
verifyComparisons (source.begin());
|
||||
|
||||
|
||||
|
||||
|
||||
buildFilterIterator (source.begin());
|
||||
Iter ii (source.begin());
|
||||
++++++ii;
|
||||
buildFilterIterator (ii);
|
||||
verify_filterRepetitions();
|
||||
|
||||
|
||||
buildTransformingIterator (source.begin());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
template<class IT>
|
||||
void
|
||||
pullOut (IT const& ii)
|
||||
|
|
@ -122,34 +122,34 @@ namespace test{
|
|||
cout << "::" << *iter;
|
||||
cout << endl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static bool takeAll (int) { return true; }
|
||||
static bool takeOdd (int i) { return 0 != i % 2; }
|
||||
static bool takeEve (int i) { return 0 == i % 2; }
|
||||
|
||||
|
||||
void
|
||||
buildFilterIterator (Iter const& ii)
|
||||
{
|
||||
pullOut (filterIterator (ii, takeAll)); // note: using the convenient builder function
|
||||
pullOut (filterIterator (ii, takeEve));
|
||||
pullOut (filterIterator (ii, takeOdd));
|
||||
|
||||
|
||||
FilterIter<Iter> all (ii, takeAll);
|
||||
FilterIter<Iter> odd (ii, takeOdd);
|
||||
verifyComparisons (all);
|
||||
verifyComparisons (odd);
|
||||
|
||||
|
||||
while (++all && ++odd)
|
||||
CHECK (all != odd);
|
||||
|
||||
|
||||
while (++all) { }
|
||||
CHECK (isnil (odd));
|
||||
CHECK (all == odd);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test verify the helper to filter duplicate elements
|
||||
* emitted by an source iterator. This test creates
|
||||
* a sequence of numbers with random repetitions.
|
||||
|
|
@ -165,56 +165,56 @@ namespace test{
|
|||
while (--n);
|
||||
}
|
||||
CHECK (NUM_ELMS < numberz.size(), "no repetition in test data??");
|
||||
|
||||
|
||||
typedef vector<uint>::iterator SrcIter;
|
||||
typedef RangeIter<SrcIter> SeqIter;
|
||||
typedef FilterIter<SeqIter> FilteredSeq;
|
||||
|
||||
|
||||
SeqIter completeSequence (numberz.begin(), numberz.end());
|
||||
FilteredSeq filtered = filterRepetitions (completeSequence);
|
||||
|
||||
|
||||
uint num=0;
|
||||
for (; num<NUM_ELMS && !isnil(filtered);
|
||||
++num,
|
||||
++filtered
|
||||
)
|
||||
CHECK (num == *filtered);
|
||||
|
||||
|
||||
CHECK (num == NUM_ELMS && isnil(filtered));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static ulong addTwo (int i) { return i+2; }
|
||||
static int negate (int i) { return -i; }
|
||||
static int idFunc (int i) { return i; }
|
||||
|
||||
|
||||
void
|
||||
buildTransformingIterator (Iter const& ii)
|
||||
{
|
||||
pullOut (transformIterator(ii, idFunc));
|
||||
pullOut (transformIterator(ii, negate));
|
||||
pullOut (transformIterator(ii, addTwo)); // note: changing output type to unsigned
|
||||
|
||||
|
||||
TransformIter<Iter, int> idi (ii, idFunc);
|
||||
TransformIter<Iter, int> neg (ii, negate);
|
||||
verifyComparisons (idi);
|
||||
verifyComparisons (neg);
|
||||
|
||||
|
||||
CHECK (idi);
|
||||
CHECK (neg);
|
||||
for ( ;idi&&neg;
|
||||
++idi,++neg)
|
||||
CHECK (idi != neg);
|
||||
|
||||
|
||||
CHECK (!idi && !neg);
|
||||
CHECK (idi == neg);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** @test verify equality handling and NIL detection
|
||||
* for the given iterator/wrapper handed in */
|
||||
template<class IT>
|
||||
|
|
@ -227,36 +227,36 @@ namespace test{
|
|||
CHECK ( isnil (iN));
|
||||
CHECK (!isnil (i1));
|
||||
CHECK (!isnil (i2));
|
||||
|
||||
|
||||
CHECK (i1 == i2); CHECK (i2 == i1);
|
||||
CHECK (i1 != iN); CHECK (iN != i1);
|
||||
CHECK (i2 != iN); CHECK (iN != i2);
|
||||
|
||||
|
||||
++i1;
|
||||
CHECK (i1 != i2);
|
||||
CHECK (i1 != iN);
|
||||
|
||||
|
||||
++i2;
|
||||
CHECK (i1 == i2);
|
||||
CHECK (i1 != iN);
|
||||
CHECK (i2 != iN);
|
||||
|
||||
|
||||
while (++i1) { }
|
||||
CHECK (isnil(i1));
|
||||
CHECK (i1 != i2);
|
||||
CHECK (i1 == iN);
|
||||
|
||||
|
||||
while (++i2) { }
|
||||
CHECK (isnil(i2));
|
||||
CHECK (i2 == i1);
|
||||
CHECK (i2 == iN);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
LAUNCHER (IterTools_test, "unit common");
|
||||
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
||||
|
|
|
|||
|
|
@ -32,98 +32,98 @@
|
|||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace test {
|
||||
|
||||
|
||||
using ::test::Test;
|
||||
using func::applyFirst;
|
||||
using func::applyLast;
|
||||
using func::bindLast;
|
||||
using func::PApply;
|
||||
using func::BindToArgument;
|
||||
|
||||
|
||||
namespace { // test functions
|
||||
|
||||
Num<1> _1_;
|
||||
Num<2> _2_;
|
||||
Num<3> _3_;
|
||||
Num<4> _4_;
|
||||
Num<5> _5_;
|
||||
Num<6> _6_;
|
||||
Num<7> _7_;
|
||||
Num<8> _8_;
|
||||
Num<9> _9_;
|
||||
|
||||
/** "Function-1" will be used at the front side, accepting a tuple of values */
|
||||
template<uint i>
|
||||
Num<i>
|
||||
fun11 ( Num<i> val1
|
||||
)
|
||||
{
|
||||
return val1;
|
||||
}
|
||||
|
||||
template<uint i, uint ii>
|
||||
Num<i>
|
||||
fun12 ( Num<i> val1
|
||||
, Num<ii> val2
|
||||
)
|
||||
{
|
||||
val1.o_ += val2.o_;
|
||||
return val1;
|
||||
}
|
||||
|
||||
template<uint i, uint ii, uint iii>
|
||||
Num<i>
|
||||
fun13 ( Num<i> val1
|
||||
, Num<ii> val2
|
||||
, Num<iii> val3
|
||||
)
|
||||
{
|
||||
val1.o_ += val2.o_ + val3.o_;
|
||||
return val1;
|
||||
}
|
||||
|
||||
template<uint i, uint ii, uint iii, uint iv>
|
||||
Num<i>
|
||||
fun14 ( Num<i> val1
|
||||
, Num<ii> val2
|
||||
, Num<iii> val3
|
||||
, Num<iv> val4
|
||||
)
|
||||
{
|
||||
val1.o_ += val2.o_ + val3.o_ + val4.o_;
|
||||
return val1;
|
||||
}
|
||||
|
||||
template<uint i, uint ii, uint iii, uint iv, uint v>
|
||||
Num<i>
|
||||
fun15 ( Num<i> val1
|
||||
, Num<ii> val2
|
||||
, Num<iii> val3
|
||||
, Num<iv> val4
|
||||
, Num<v> val5
|
||||
)
|
||||
{
|
||||
val1.o_ += val2.o_ + val3.o_ + val4.o_ + val5.o_;
|
||||
return val1;
|
||||
}
|
||||
|
||||
|
||||
/** "Function-2" can be chained behind fun1 */
|
||||
template<class II>
|
||||
int
|
||||
fun2 (II val)
|
||||
{
|
||||
return val.o_;
|
||||
}
|
||||
|
||||
} // (End) test data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace { // test functions
|
||||
|
||||
Num<1> _1_;
|
||||
Num<2> _2_;
|
||||
Num<3> _3_;
|
||||
Num<4> _4_;
|
||||
Num<5> _5_;
|
||||
Num<6> _6_;
|
||||
Num<7> _7_;
|
||||
Num<8> _8_;
|
||||
Num<9> _9_;
|
||||
|
||||
/** "Function-1" will be used at the front side, accepting a tuple of values */
|
||||
template<uint i>
|
||||
Num<i>
|
||||
fun11 ( Num<i> val1
|
||||
)
|
||||
{
|
||||
return val1;
|
||||
}
|
||||
|
||||
template<uint i, uint ii>
|
||||
Num<i>
|
||||
fun12 ( Num<i> val1
|
||||
, Num<ii> val2
|
||||
)
|
||||
{
|
||||
val1.o_ += val2.o_;
|
||||
return val1;
|
||||
}
|
||||
|
||||
template<uint i, uint ii, uint iii>
|
||||
Num<i>
|
||||
fun13 ( Num<i> val1
|
||||
, Num<ii> val2
|
||||
, Num<iii> val3
|
||||
)
|
||||
{
|
||||
val1.o_ += val2.o_ + val3.o_;
|
||||
return val1;
|
||||
}
|
||||
|
||||
template<uint i, uint ii, uint iii, uint iv>
|
||||
Num<i>
|
||||
fun14 ( Num<i> val1
|
||||
, Num<ii> val2
|
||||
, Num<iii> val3
|
||||
, Num<iv> val4
|
||||
)
|
||||
{
|
||||
val1.o_ += val2.o_ + val3.o_ + val4.o_;
|
||||
return val1;
|
||||
}
|
||||
|
||||
template<uint i, uint ii, uint iii, uint iv, uint v>
|
||||
Num<i>
|
||||
fun15 ( Num<i> val1
|
||||
, Num<ii> val2
|
||||
, Num<iii> val3
|
||||
, Num<iv> val4
|
||||
, Num<v> val5
|
||||
)
|
||||
{
|
||||
val1.o_ += val2.o_ + val3.o_ + val4.o_ + val5.o_;
|
||||
return val1;
|
||||
}
|
||||
|
||||
|
||||
/** "Function-2" can be chained behind fun1 */
|
||||
template<class II>
|
||||
int
|
||||
fun2 (II val)
|
||||
{
|
||||
return val.o_;
|
||||
}
|
||||
|
||||
} // (End) test data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
* @test this test covers some extensions and variations on function closures:
|
||||
* - partial application of a function, returning a partial closure
|
||||
|
|
@ -140,8 +140,8 @@ namespace test {
|
|||
check_functionalComposition ();
|
||||
check_bindToArbitraryParameter ();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** verify the test input data
|
||||
* @see TypeListManipl_test#check_diagnostics()
|
||||
* for an explanation of the DISPLAY macro
|
||||
|
|
@ -151,59 +151,59 @@ namespace test {
|
|||
{
|
||||
CHECK (6 == (fun13<1,2,3> (_1_, _2_, _3_)).o_ );
|
||||
CHECK (6 == (fun13<1,1,1> (Num<1>(3), Num<1>(2), Num<1>(1))).o_ );
|
||||
|
||||
|
||||
CHECK ( 1 == fun2 (fun11<1> (_1_)) );
|
||||
CHECK ( 3 == fun2 (fun12<1,2> (_1_, _2_)) );
|
||||
CHECK ( 6 == fun2 (fun13<1,2,3> (_1_, _2_, _3_)) );
|
||||
CHECK (10 == fun2 (fun14<1,2,3,4> (_1_, _2_, _3_, _4_)) );
|
||||
CHECK (15 == fun2 (fun15<1,2,3,4,5> (_1_, _2_, _3_, _4_, _5_)) );
|
||||
|
||||
|
||||
CHECK ( 9 == fun2 (fun13<2,3,4> (_2_, _3_, _4_)) );
|
||||
CHECK (18 == fun2 (fun13<5,6,7> (_5_, _6_, _7_)) );
|
||||
CHECK (24 == fun2 (fun13<9,8,7> (_9_, _8_, _7_)) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
check_partialApplication ()
|
||||
{
|
||||
// Because the code of the partial function application is very technical,
|
||||
// the following might serve as explanation what actually happens....
|
||||
// (and actually it's a leftover from initial debugging)
|
||||
|
||||
|
||||
typedef Num<1> Sig123(Num<1>, Num<2>, Num<3>); // signature of the original function
|
||||
|
||||
|
||||
typedef Num<1> Sig23(Num<2>, Num<3>); // signature after having closed over the first argument
|
||||
typedef function<Sig23> F23; // and a tr1::function object to hold such a function
|
||||
|
||||
|
||||
Sig123& f =fun13<1,2,3>; // the actual input: a reference to the bare function
|
||||
|
||||
|
||||
|
||||
|
||||
// Version1: do a direct argument binding----------------- //
|
||||
|
||||
|
||||
typedef std::tr1::_Placeholder<1> PH1; // tr1::function argument placeholders
|
||||
typedef std::tr1::_Placeholder<2> PH2;
|
||||
|
||||
|
||||
PH1 ph1; // these empty structs are used to mark the arguments to be kept "open"
|
||||
PH2 ph2;
|
||||
Num<1> num18 (18); // ...and this value is for closing the first function argument
|
||||
|
||||
|
||||
F23 fun_23 = std::tr1::bind (f, num18 // do the actual binding (i.e. close the first argument with a constant value)
|
||||
, ph1
|
||||
, ph2
|
||||
);
|
||||
|
||||
|
||||
int res = 0;
|
||||
res = fun_23 (_2_,_3_).o_; // and invoke the resulting functor ("closure"), providing the remaining arguments
|
||||
CHECK (23 == res);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Version2: extract the binding arguments from a tuple--- //
|
||||
|
||||
|
||||
typedef Tuple<Types<Num<1>, PH1, PH2> > PartialArg; // Tuple type to hold the binding values. Note the placeholder types
|
||||
PartialArg arg(num18); // Value for partial application (the placeholders are default constructed)
|
||||
|
||||
|
||||
fun_23 = std::tr1::bind (f, tuple::element<0>(arg) // now extract the values to bind from this tuple
|
||||
, tuple::element<1>(arg)
|
||||
, tuple::element<2>(arg)
|
||||
|
|
@ -211,90 +211,90 @@ namespace test {
|
|||
res = 0;
|
||||
res = fun_23 (_2_,_3_).o_; // and invoke the resulting functor....
|
||||
CHECK (23 == res);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Version3: let the PApply-template do the work for us--- //
|
||||
|
||||
|
||||
typedef Types<Num<1> > ArgTypes; // now package just the argument(s) to be applied into a tuple
|
||||
Tuple<ArgTypes> args_to_bind (Num<1>(18));
|
||||
|
||||
|
||||
fun_23 = PApply<Sig123, ArgTypes>::bindFront (f , args_to_bind);
|
||||
// "bindFront" will close the parameters starting from left....
|
||||
res = 0;
|
||||
res = fun_23 (_2_,_3_).o_; // invoke the resulting functor...
|
||||
CHECK (23 == res);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// Version4: as you'd typically do it in real life-------- //
|
||||
|
||||
|
||||
fun_23 = func::applyFirst (f, Num<1>(18)); // use the convenience function API to close over a single value
|
||||
|
||||
|
||||
res = 0;
|
||||
res = fun_23 (_2_,_3_).o_; // invoke the resulting functor...
|
||||
CHECK (23 == res);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// what follows is the real unit test...
|
||||
function<Sig123> func123 (f); // alternatively do it with an tr1::function object
|
||||
fun_23 = func::applyFirst (func123, Num<1>(19));
|
||||
res = fun_23 (_2_,_3_).o_;
|
||||
CHECK (24 == res);
|
||||
|
||||
|
||||
typedef function<Num<1>(Num<1>, Num<2>)> F12;
|
||||
F12 fun_12 = func::applyLast(f, Num<3>(20)); // close the *last* argument of a function
|
||||
res = fun_12 (_1_,_2_).o_;
|
||||
CHECK (23 == res);
|
||||
|
||||
|
||||
fun_12 = func::applyLast(func123, Num<3>(21)); // alternatively use a function object
|
||||
res = fun_12 (_1_,_2_).o_;
|
||||
CHECK (24 == res);
|
||||
|
||||
|
||||
Sig123 *fP = &f; // a function pointer works too
|
||||
fun_12 = func::applyLast( fP, Num<3>(22));
|
||||
res = fun_12 (_1_,_2_).o_;
|
||||
CHECK (25 == res);
|
||||
// cover more cases....
|
||||
|
||||
CHECK (1 == (func::applyLast (fun11<1> , _1_) ( ) ).o_);
|
||||
CHECK (1+3 == (func::applyLast (fun12<1,3> , _3_) (_1_) ).o_);
|
||||
CHECK (1+3+5 == (func::applyLast (fun13<1,3,5> , _5_) (_1_,_3_) ).o_);
|
||||
CHECK (1+3+5+7 == (func::applyLast (fun14<1,3,5,7> , _7_) (_1_,_3_,_5_) ).o_);
|
||||
CHECK (1+3+5+7+9 == (func::applyLast (fun15<1,3,5,7,9>, _9_) (_1_,_3_,_5_,_7_)).o_);
|
||||
|
||||
CHECK (9+8+7+6+5 == (func::applyFirst(fun15<9,8,7,6,5>, _9_) (_8_,_7_,_6_,_5_)).o_);
|
||||
CHECK ( 8+7+6+5 == (func::applyFirst( fun14<8,7,6,5>, _8_) (_7_,_6_,_5_)).o_);
|
||||
CHECK ( 7+6+5 == (func::applyFirst( fun13<7,6,5>, _7_) (_6_,_5_)).o_);
|
||||
CHECK ( 6+5 == (func::applyFirst( fun12<6,5>, _6_) (_5_)).o_);
|
||||
CHECK ( 5 == (func::applyFirst( fun11<5>, _5_) ( )).o_);
|
||||
|
||||
|
||||
|
||||
|
||||
CHECK (1 == (func::applyLast (fun11<1> , _1_ ) ( ) ).o_);
|
||||
CHECK (1+3 == (func::applyLast (fun12<1,3> , _3_ ) (_1_) ).o_);
|
||||
CHECK (1+3+5 == (func::applyLast (fun13<1,3,5> , _5_ ) (_1_,_3_) ).o_);
|
||||
CHECK (1+3+5+7 == (func::applyLast (fun14<1,3,5,7> , _7_ ) (_1_,_3_,_5_) ).o_);
|
||||
CHECK (1+3+5+7+9 == (func::applyLast (fun15<1,3,5,7,9>, _9_ ) (_1_,_3_,_5_,_7_)).o_);
|
||||
|
||||
CHECK (9+8+7+6+5 == (func::applyFirst(fun15<9,8,7,6,5>, _9_ ) (_8_,_7_,_6_,_5_)).o_);
|
||||
CHECK ( 8+7+6+5 == (func::applyFirst( fun14<8,7,6,5>, _8_ ) (_7_,_6_,_5_)).o_);
|
||||
CHECK ( 7+6+5 == (func::applyFirst( fun13<7,6,5>, _7_ ) (_6_,_5_)).o_);
|
||||
CHECK ( 6+5 == (func::applyFirst( fun12<6,5>, _6_ ) (_5_)).o_);
|
||||
CHECK ( 5 == (func::applyFirst( fun11<5>, _5_ ) ( )).o_);
|
||||
|
||||
|
||||
|
||||
// Finally a more convoluted example
|
||||
// covering the general case of partial function closure:
|
||||
typedef Num<5> Sig54321(Num<5>, Num<4>, Num<3>, Num<2>, Num<1>); // Signature of the 5-argument function
|
||||
typedef Num<5> Sig54 (Num<5>, Num<4>); // ...closing the last 3 arguments should yield this 2-argument function
|
||||
typedef Types<Num<3>,Num<2>,Num<1> > Args2Close; // Tuple type to hold the 3 argument values used for the closure
|
||||
|
||||
|
||||
// Close the trailing 3 arguments of the 5-argument function...
|
||||
function<Sig54> fun_54 = PApply<Sig54321, Args2Close>::bindBack(fun15<5,4,3,2,1>,
|
||||
tuple::make(_3_,_2_,_1_)
|
||||
);
|
||||
|
||||
|
||||
// apply the remaining argument values
|
||||
Num<5> resN5 = fun_54 (_5_,_4_);
|
||||
CHECK (5+4+3+2+1 == resN5.o_);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
check_functionalComposition ()
|
||||
{
|
||||
|
|
@ -304,87 +304,87 @@ namespace test {
|
|||
typedef Num<1> Sig13(Num<1>,Num<2>,Num<3>);
|
||||
typedef Num<1> Sig14(Num<1>,Num<2>,Num<3>,Num<4>);
|
||||
typedef Num<1> Sig15(Num<1>,Num<2>,Num<3>,Num<4>,Num<5>);
|
||||
|
||||
|
||||
Sig2 & ff = fun2< Num<1> >;
|
||||
Sig11& f1 = fun11<1>;
|
||||
Sig12& f2 = fun12<1,2>;
|
||||
Sig13& f3 = fun13<1,2,3>;
|
||||
Sig14& f4 = fun14<1,2,3,4>;
|
||||
Sig15& f5 = fun15<1,2,3,4,5>;
|
||||
|
||||
|
||||
CHECK (1 == func::chained(f1, ff) (_1_) );
|
||||
CHECK (1+2 == func::chained(f2, ff) (_1_,_2_) );
|
||||
CHECK (1+2+3 == func::chained(f3, ff) (_1_,_2_,_3_) );
|
||||
CHECK (1+2+3+4 == func::chained(f4, ff) (_1_,_2_,_3_,_4_) );
|
||||
CHECK (1+2+3+4+5 == func::chained(f5, ff) (_1_,_2_,_3_,_4_,_5_) );
|
||||
|
||||
|
||||
|
||||
|
||||
function<Sig15> f5_fun = f5; // also works with function objects...
|
||||
function<Sig2> ff_fun = ff;
|
||||
CHECK (1+2+3+4+5 == func::chained(f5_fun, ff ) (_1_,_2_,_3_,_4_,_5_) );
|
||||
CHECK (1+2+3+4+5 == func::chained(f5, ff_fun) (_1_,_2_,_3_,_4_,_5_) );
|
||||
CHECK (1+2+3+4+5 == func::chained(f5_fun, ff_fun) (_1_,_2_,_3_,_4_,_5_) );
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
check_bindToArbitraryParameter ()
|
||||
{
|
||||
typedef Num<1> Sig15(Num<1>,Num<2>,Num<3>,Num<4>,Num<5>);
|
||||
|
||||
|
||||
typedef Num<1> SigR1( Num<2>,Num<3>,Num<4>,Num<5>);
|
||||
typedef Num<1> SigR2(Num<1>, Num<3>,Num<4>,Num<5>);
|
||||
typedef Num<1> SigR3(Num<1>,Num<2>, Num<4>,Num<5>);
|
||||
typedef Num<1> SigR4(Num<1>,Num<2>,Num<3>, Num<5>);
|
||||
typedef Num<1> SigR5(Num<1>,Num<2>,Num<3>,Num<4> );
|
||||
|
||||
|
||||
typedef Num<5> SigA5(Num<5>);
|
||||
|
||||
|
||||
Sig15& f = fun15<1,2,3,4,5>;
|
||||
SigA5& f5 = fun11<5>;
|
||||
Tuple<Types<char> > argT(55);
|
||||
|
||||
|
||||
function<SigR1> f_bound_1 = BindToArgument<Sig15,char,0>::reduced (f, argT);
|
||||
function<SigR2> f_bound_2 = BindToArgument<Sig15,char,1>::reduced (f, argT);
|
||||
function<SigR3> f_bound_3 = BindToArgument<Sig15,char,2>::reduced (f, argT);
|
||||
function<SigR4> f_bound_4 = BindToArgument<Sig15,char,3>::reduced (f, argT);
|
||||
function<SigR5> f_bound_5 = BindToArgument<Sig15,char,4>::reduced (f, argT);
|
||||
|
||||
|
||||
CHECK (55+2+3+4+5 == f_bound_1 ( _2_,_3_,_4_,_5_) );
|
||||
CHECK (1+55+3+4+5 == f_bound_2 (_1_, _3_,_4_,_5_) );
|
||||
CHECK (1+2+55+4+5 == f_bound_3 (_1_,_2_, _4_,_5_) );
|
||||
CHECK (1+2+3+55+5 == f_bound_4 (_1_,_2_,_3_, _5_) );
|
||||
CHECK (1+2+3+4+55 == f_bound_5 (_1_,_2_,_3_,_4_ ) );
|
||||
|
||||
|
||||
|
||||
|
||||
// degenerate case: specify wrong argument position (behind end of argument list)
|
||||
// causes the argument to be simply ignored and no binding to happen
|
||||
function<Sig15> f_bound_X = BindToArgument<Sig15,char,5>::reduced (f, argT);
|
||||
CHECK (1+2+3+4+5 == f_bound_X (_1_,_2_,_3_,_4_,_5_) );
|
||||
|
||||
|
||||
|
||||
|
||||
/* check the convenient function-style API */
|
||||
|
||||
|
||||
using std::tr1::bind;
|
||||
|
||||
|
||||
f_bound_5 = bindLast (f, bind(f5, Num<5>(99)));
|
||||
CHECK (1+2+3+4+99 == f_bound_5 (_1_,_2_,_3_,_4_ ) );
|
||||
|
||||
|
||||
f_bound_5 = bindLast (f, bind(&f5, Num<5>(99))); // can bind function pointer
|
||||
CHECK (1+2+3+4+99 == f_bound_5 (_1_,_2_,_3_,_4_ ) );
|
||||
|
||||
|
||||
function<Sig15> asFunctor(f);
|
||||
f_bound_5 = bindLast (asFunctor, bind(f5, Num<5>(88))); // use functor instead of direct ref
|
||||
CHECK (1+2+3+4+88 == f_bound_5 (_1_,_2_,_3_,_4_ ) );
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (FunctionComposition_test, "unit common");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}}} // namespace lumiera::typelist::test
|
||||
|
|
|
|||
|
|
@ -23,13 +23,13 @@
|
|||
|
||||
/** @file generator-test.cpp
|
||||
** \par what are we doing here??
|
||||
**
|
||||
**
|
||||
** the following test composes both an interface and the corresponding implementation
|
||||
** by instantiating "building block" templates over a collection of types. The resulting
|
||||
** class ends up inheriting a \e virtual function instantiated for each of the types
|
||||
** in the list. (remember: normally the number and signature of all virtual functions
|
||||
** need to be absolutely fixed in the class definition)
|
||||
**
|
||||
**
|
||||
** @see typelist-test.cpp
|
||||
** @see generator.hpp
|
||||
** @see lumiera::query::ConfigRules a real world usage example
|
||||
|
|
@ -50,99 +50,98 @@ using std::cout;
|
|||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace test {
|
||||
|
||||
/** template for generating lots of different test types */
|
||||
template<int I>
|
||||
struct Block
|
||||
|
||||
/** template for generating lots of different test types */
|
||||
template<int I>
|
||||
struct Block
|
||||
{
|
||||
static string name;
|
||||
string talk() { return "__"+name+"__"; }
|
||||
};
|
||||
|
||||
|
||||
boost::format fmt ("Block<%2i>");
|
||||
|
||||
template<int I>
|
||||
string Block<I>::name = str (fmt % I);
|
||||
|
||||
|
||||
|
||||
/** Use this building block for assembling an abstract interface */
|
||||
template<class X>
|
||||
class TakeIt
|
||||
{
|
||||
public:
|
||||
virtual void eat (X& x) = 0;
|
||||
virtual ~TakeIt() { }
|
||||
};
|
||||
|
||||
/** Use this building block for chaining corresponding implementation classes. */
|
||||
template<class X, class BASE>
|
||||
class DoIt
|
||||
: public BASE
|
||||
{
|
||||
protected:
|
||||
DoIt () { cout << "ctor DoIt<"<< X::name << " >\n";}
|
||||
virtual ~DoIt() { cout << "dtor DoIt<"<< X::name << " >\n";}
|
||||
public:
|
||||
void eat (X& x) { cout << "devouring" << x.talk() << "\n";}
|
||||
using BASE::eat; // prevent shadowing
|
||||
};
|
||||
|
||||
typedef Types< Block<1>
|
||||
, Block<2>
|
||||
, Block<3>
|
||||
, Block<5>
|
||||
, Block<8>
|
||||
, Block<13>
|
||||
>::List TheTypes;
|
||||
|
||||
typedef InstantiateForEach<TheTypes,TakeIt> TheInterface;
|
||||
|
||||
|
||||
struct BaseImpl : public TheInterface
|
||||
{
|
||||
void eat() { cout << "gulp!\n"; }
|
||||
};
|
||||
|
||||
typedef InstantiateChained<TheTypes,DoIt, BaseImpl> NumberBabbler;
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* @test check the helpers for dealing with lists-of-types.
|
||||
* Build an interface and an implementation class
|
||||
* by inheriting template instantiations
|
||||
* for a collection of classes</li>
|
||||
*/
|
||||
class TypeListGenerator_test : public Test
|
||||
{
|
||||
virtual void run(Arg)
|
||||
{
|
||||
static string name;
|
||||
string talk() { return "__"+name+"__"; }
|
||||
};
|
||||
|
||||
|
||||
boost::format fmt ("Block<%2i>");
|
||||
|
||||
template<int I>
|
||||
string Block<I>::name = str (fmt % I);
|
||||
|
||||
|
||||
|
||||
/** Use this building block for assembling an abstract interface */
|
||||
template<class X>
|
||||
class TakeIt
|
||||
{
|
||||
public:
|
||||
virtual void eat (X& x) = 0;
|
||||
virtual ~TakeIt() { }
|
||||
};
|
||||
|
||||
/** Use this building block for chaining corresponding implementation classes. */
|
||||
template<class X, class BASE>
|
||||
class DoIt
|
||||
: public BASE
|
||||
{
|
||||
protected:
|
||||
DoIt () { cout << "ctor DoIt<"<< X::name << " >\n";}
|
||||
virtual ~DoIt() { cout << "dtor DoIt<"<< X::name << " >\n";}
|
||||
public:
|
||||
void eat (X& x) { cout << "devouring" << x.talk() << "\n";}
|
||||
using BASE::eat; // prevent shadowing
|
||||
};
|
||||
|
||||
typedef Types< Block<1>
|
||||
, Block<2>
|
||||
, Block<3>
|
||||
, Block<5>
|
||||
, Block<8>
|
||||
, Block<13>
|
||||
>::List TheTypes;
|
||||
|
||||
typedef InstantiateForEach<TheTypes,TakeIt> TheInterface;
|
||||
|
||||
|
||||
struct BaseImpl : public TheInterface
|
||||
{
|
||||
void eat() { cout << "gulp!\n"; }
|
||||
};
|
||||
|
||||
typedef InstantiateChained<TheTypes,DoIt, BaseImpl> NumberBabbler;
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* @test check the helpers for dealing with lists-of-types.
|
||||
* <ul><li>build an interface and an implementation class
|
||||
* by inheriting template instantiations
|
||||
* for a collection of classes</li>
|
||||
* </ul>
|
||||
*/
|
||||
class TypeListGenerator_test : public Test
|
||||
{
|
||||
virtual void run(Arg)
|
||||
{
|
||||
NumberBabbler me_can_has_more_numberz;
|
||||
|
||||
CHECK (INSTANCEOF (TheInterface, &me_can_has_more_numberz));
|
||||
|
||||
TheTypes::Tail::Head b2; // Block<2>
|
||||
TheTypes::Tail::Tail::Tail::Head b5; // Block<5>
|
||||
TheTypes::Tail::Tail::Tail::Tail::Tail::Head b13; // Block<13>
|
||||
|
||||
me_can_has_more_numberz.eat (b2);
|
||||
me_can_has_more_numberz.eat (b5);
|
||||
|
||||
TakeIt<Block<13> >& subInterface = me_can_has_more_numberz;
|
||||
|
||||
subInterface.eat (b13);
|
||||
me_can_has_more_numberz.eat();
|
||||
|
||||
INFO (test, "SizeOf = %u", sizeof(me_can_has_more_numberz));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (TypeListGenerator_test, "unit common");
|
||||
|
||||
|
||||
|
||||
NumberBabbler me_can_has_more_numberz;
|
||||
|
||||
CHECK (INSTANCEOF (TheInterface, &me_can_has_more_numberz));
|
||||
|
||||
TheTypes::Tail::Head b2; // Block<2>
|
||||
TheTypes::Tail::Tail::Tail::Head b5; // Block<5>
|
||||
TheTypes::Tail::Tail::Tail::Tail::Tail::Head b13; // Block<13>
|
||||
|
||||
me_can_has_more_numberz.eat (b2);
|
||||
me_can_has_more_numberz.eat (b5);
|
||||
|
||||
TakeIt<Block<13> >& subInterface = me_can_has_more_numberz;
|
||||
|
||||
subInterface.eat (b13);
|
||||
me_can_has_more_numberz.eat();
|
||||
|
||||
INFO (test, "SizeOf = %u", sizeof(me_can_has_more_numberz));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (TypeListGenerator_test, "unit common");
|
||||
|
||||
|
||||
|
||||
}}} // namespace lumiera::typelist::test
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
/** @file type-tuple-test.cpp
|
||||
** Interplay of typelists, type tuples and simple record
|
||||
** data types build on top of them.
|
||||
**
|
||||
**
|
||||
** @see lumiera::typelist::Tuple
|
||||
** @see tuple.hpp
|
||||
** @see function-closure.hpp
|
||||
|
|
@ -48,28 +48,28 @@ using std::endl;
|
|||
namespace lumiera {
|
||||
namespace typelist{
|
||||
namespace test {
|
||||
|
||||
|
||||
|
||||
namespace { // test data
|
||||
|
||||
|
||||
typedef Types< Num<1>
|
||||
, Num<3>
|
||||
, Num<5>
|
||||
> Types1;
|
||||
typedef Types< Num<2>
|
||||
, Num<4>
|
||||
> Types2;
|
||||
typedef Types< Num<7> > Types3;
|
||||
|
||||
|
||||
|
||||
} // (End) test data
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
namespace { // test data
|
||||
|
||||
|
||||
typedef Types< Num<1>
|
||||
, Num<3>
|
||||
, Num<5>
|
||||
> Types1;
|
||||
typedef Types< Num<2>
|
||||
, Num<4>
|
||||
> Types2;
|
||||
typedef Types< Num<7> > Types3;
|
||||
|
||||
|
||||
|
||||
} // (End) test data
|
||||
|
||||
|
||||
|
||||
|
||||
/*************************************************************************
|
||||
* @test Cover various aspects of the type tuple.
|
||||
* Check the metaprogramming behaviour...
|
||||
|
|
@ -99,8 +99,8 @@ namespace test {
|
|||
check_tuple_copy();
|
||||
check_value_access();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/** verify the test input data
|
||||
* @see TypeListManipl_test#check_diagnostics()
|
||||
* for an explanation of the DISPLAY macro
|
||||
|
|
@ -111,156 +111,156 @@ namespace test {
|
|||
typedef Types1::List L1;
|
||||
typedef Types2::List L2;
|
||||
typedef Types3::List L3;
|
||||
|
||||
|
||||
DISPLAY (L1);
|
||||
DISPLAY (L2);
|
||||
DISPLAY (L3);
|
||||
|
||||
|
||||
typedef Tuple<Types1> Tup1;
|
||||
Tup1 tup1x (Num<1>(11));
|
||||
|
||||
|
||||
DISPLAY (Tup1); // prints the type
|
||||
DUMPVAL (Tup1()); // prints the contents
|
||||
DUMPVAL (tup1x);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
check_tuple_from_Typelist()
|
||||
{
|
||||
typedef Types1::List L1; // starting from an existing Typelist...
|
||||
|
||||
|
||||
typedef Tuple<L1> T_L1; // ListType based tuple type
|
||||
typedef Tuple<L1>::TupleType T1; // corresponding plain tuple type
|
||||
typedef Tuple<L1>::Type Type1; // extract the underlying type sequence
|
||||
|
||||
|
||||
DISPLAY (Type1);
|
||||
DISPLAY (T_L1);
|
||||
DISPLAY (T1);
|
||||
|
||||
|
||||
T_L1 tup1 (Num<1>(8)); // both flavours can be created at runtime
|
||||
T1 tup2 (Num<1>(9)); // (and we provide an explicit value for the 1st element)
|
||||
DUMPVAL (tup1);
|
||||
DUMPVAL (tup2);
|
||||
|
||||
|
||||
typedef Tuple<Node<int, L1> > Prepend;
|
||||
DISPLAY (Prepend); // another ListType based tuple created by prepending
|
||||
|
||||
|
||||
Prepend prepend (22, tup2); // but note: the ListType based tuple has an "(head,tail)" style ctor
|
||||
DUMPVAL (prepend); // ... and in construction, tup2 has been copied and coerced to ListType style
|
||||
|
||||
|
||||
typedef Tuple<Types<> > NulT; // plain-flat empty Tuple
|
||||
typedef Tuple<NullType> NulL; // list-style empty Tuple
|
||||
|
||||
|
||||
CHECK ( is_Tuple<T1>::value);
|
||||
CHECK ( is_TuplePlain<T1>::value);
|
||||
CHECK (! is_TupleListType<T1>::value);
|
||||
CHECK (! is_NullTuple<T1>::value);
|
||||
|
||||
|
||||
CHECK ( is_Tuple<T_L1>::value);
|
||||
CHECK (! is_TuplePlain<T_L1>::value);
|
||||
CHECK ( is_TupleListType<T_L1>::value);
|
||||
CHECK (! is_NullTuple<T_L1>::value);
|
||||
|
||||
|
||||
CHECK ( is_Tuple<NulT>::value);
|
||||
CHECK ( is_TuplePlain<NulT>::value);
|
||||
CHECK (! is_TupleListType<NulT>::value);
|
||||
CHECK ( is_NullTuple<NulT>::value);
|
||||
|
||||
|
||||
CHECK ( is_Tuple<NulL>::value);
|
||||
CHECK (! is_TuplePlain<NulL>::value);
|
||||
CHECK ( is_TupleListType<NulL>::value);
|
||||
CHECK ( is_NullTuple<NulL>::value);
|
||||
|
||||
|
||||
CHECK (! is_Tuple<Type1>::value);
|
||||
CHECK (! is_TuplePlain<Type1>::value);
|
||||
CHECK (!is_TupleListType<Type1>::value);
|
||||
CHECK (! is_NullTuple<Type1>::value);
|
||||
|
||||
|
||||
CHECK (! is_Tuple<Types1::List>::value);
|
||||
CHECK (! is_TuplePlain<Types1::List>::value);
|
||||
CHECK (!is_TupleListType<Types1::List>::value);
|
||||
CHECK (! is_NullTuple<Types1::List>::value);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
check_sub_tuple_types()
|
||||
{
|
||||
cout << "\t:\n\t: ---Sub-Tuple-Types----\n";
|
||||
|
||||
|
||||
typedef Append<Types2::List, Types1::List>::List L2;
|
||||
|
||||
|
||||
typedef Tuple<L2> T_L2; // list-style Tuple
|
||||
typedef Types<T_L2::HeadType> Head;
|
||||
typedef T_L2::TailType Tail;
|
||||
DISPLAY (T_L2);
|
||||
DISPLAY (Head);
|
||||
DISPLAY (Tail);
|
||||
|
||||
|
||||
typedef T_L2::TupleType T2; // plain-flat Tuple
|
||||
typedef Types<T2::HeadType> Head2;
|
||||
typedef T2::TailType Tail2;
|
||||
DISPLAY (T2);
|
||||
DISPLAY (Head2);
|
||||
DISPLAY (Tail2);
|
||||
|
||||
|
||||
typedef Tuple<Types<> > NulT; // plain-flat empty Tuple
|
||||
typedef Tuple<NullType> NulL; // list-style empty Tuple
|
||||
|
||||
|
||||
DISPLAY (T2::Type); // irrespective of the flavour,
|
||||
DISPLAY (T2::TailType); // a basic set of typedefs is
|
||||
DISPLAY (T2::TupleType); // always available
|
||||
DISPLAY (T2::ThisType);
|
||||
DISPLAY (T2::Tail);
|
||||
DISPLAY (T2::ArgList);
|
||||
|
||||
|
||||
DISPLAY (T_L2::Type); // the element types as type sequence
|
||||
DISPLAY (T_L2::TailType); // the element types of the "tail" tuple
|
||||
DISPLAY (T_L2::TupleType); // corresponding plain-flat tuple type
|
||||
DISPLAY (T_L2::ThisType); // "type_of(this)"
|
||||
DISPLAY (T_L2::Tail); // tail tuple
|
||||
DISPLAY (T_L2::ArgList); // typelist comprised of the element types
|
||||
|
||||
|
||||
DISPLAY (NulT::Type);
|
||||
DISPLAY (NulT::TailType);
|
||||
DISPLAY (NulT::TupleType);
|
||||
DISPLAY (NulT::ThisType);
|
||||
DISPLAY (NulT::Tail);
|
||||
DISPLAY (NulT::ArgList);
|
||||
|
||||
|
||||
DISPLAY (NulL::Type);
|
||||
DISPLAY (NulL::TailType);
|
||||
DISPLAY (NulL::TupleType);
|
||||
DISPLAY (NulL::ThisType);
|
||||
DISPLAY (NulL::Tail);
|
||||
DISPLAY (NulL::ArgList);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
check_shiftedTuple()
|
||||
{
|
||||
cout << "\t:\n\t: ---Shifted-Tuple---\n";
|
||||
|
||||
|
||||
typedef Append<Types2::List, Types3::List>::List L3;
|
||||
typedef Tuple<L3>::Type Ty3;
|
||||
typedef Tuple<Ty3> T3;
|
||||
|
||||
typedef Shifted<Ty3,0>::Type Ty_0; DISPLAY (Ty_0);
|
||||
typedef Shifted<Ty3,1>::Type Ty_1; DISPLAY (Ty_1);
|
||||
typedef Shifted<Ty3,2>::Type Ty_2; DISPLAY (Ty_2);
|
||||
typedef Shifted<Ty3,3>::Type Ty_3; DISPLAY (Ty_3);
|
||||
typedef Shifted<Ty3,4>::Type Ty_4; DISPLAY (Ty_4);
|
||||
|
||||
|
||||
typedef Shifted<Ty3,0>::Type Ty_0; DISPLAY (Ty_0);
|
||||
typedef Shifted<Ty3,1>::Type Ty_1; DISPLAY (Ty_1);
|
||||
typedef Shifted<Ty3,2>::Type Ty_2; DISPLAY (Ty_2);
|
||||
typedef Shifted<Ty3,3>::Type Ty_3; DISPLAY (Ty_3);
|
||||
typedef Shifted<Ty3,4>::Type Ty_4; DISPLAY (Ty_4);
|
||||
|
||||
typedef T3::ShiftedTuple<0>::Type T_0; DISPLAY (T_0);
|
||||
typedef T3::ShiftedTuple<1>::Type T_1; DISPLAY (T_1);
|
||||
typedef T3::ShiftedTuple<2>::Type T_2; DISPLAY (T_2);
|
||||
typedef T3::ShiftedTuple<3>::Type T_3; DISPLAY (T_3);
|
||||
typedef T3::ShiftedTuple<4>::Type T_4; DISPLAY (T_4);
|
||||
|
||||
|
||||
T3 tu3; DUMPVAL (tu3);
|
||||
T_0 tu3_0 = tu3.getShifted<0>(); DUMPVAL (tu3_0);
|
||||
T_1 tu3_1 = tu3.getShifted<1>(); DUMPVAL (tu3_1);
|
||||
|
|
@ -268,13 +268,13 @@ namespace test {
|
|||
T_3 tu3_3 = tu3.getShifted<3>(); DUMPVAL (tu3_3);
|
||||
T_4 tu3_4 = tu3.getShifted<4>(); DUMPVAL (tu3_4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
check_tuple_creation()
|
||||
{
|
||||
cout << "\t:\n\t: ---creating-Tuples---\n";
|
||||
|
||||
|
||||
Tuple<Types1> tup1 ;
|
||||
Tuple<Types1> tup11 (Num<1>(11) );
|
||||
Tuple<Types1> tup12 (Num<1>(), Num<3>(33) );
|
||||
|
|
@ -283,22 +283,22 @@ namespace test {
|
|||
DUMPVAL (tup11);
|
||||
DUMPVAL (tup12);
|
||||
DUMPVAL (tup13);
|
||||
|
||||
|
||||
typedef Tuple<Types<int,int,Num<11> > > Tup2;
|
||||
Tup2 tup2 = tuple::make(41,42, Num<11>(43)); // build tuple from given values
|
||||
DISPLAY (Tup2);
|
||||
DUMPVAL (tup2);
|
||||
|
||||
|
||||
typedef Tup2::Tail Tup22;
|
||||
Tup22 tup22 = tup2.getTail();
|
||||
DISPLAY (Tup22);
|
||||
DUMPVAL (tup22);
|
||||
|
||||
|
||||
typedef Tup2::Tail::Tail Tup222;
|
||||
Tup222 tup222 = tup22.getTail();
|
||||
DISPLAY (Tup222);
|
||||
DUMPVAL (tup222);
|
||||
|
||||
|
||||
typedef Tuple<Types<> > T0T;
|
||||
typedef Tuple<NullType> T0L;
|
||||
T0T nullT = tuple::makeNullTuple();
|
||||
|
|
@ -312,31 +312,31 @@ namespace test {
|
|||
DUMPVAL (nulTcpy);
|
||||
DUMPVAL (nulTref);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
check_build_from_subTuple()
|
||||
{
|
||||
cout << "\t:\n\t: ---build-from-sub-Tuples---\n";
|
||||
|
||||
|
||||
typedef Append<Types1::List, Types3::List>::List TL;
|
||||
typedef Tuple<TL>::Type TT;
|
||||
typedef Tuple<TL> T1357L;
|
||||
typedef Tuple<TT> T1357T;
|
||||
DISPLAY (T1357L);
|
||||
DISPLAY (T1357T);
|
||||
|
||||
|
||||
typedef Tuple<Types1::List> T135L;
|
||||
typedef Tuple<Types<Num<5>,Num<7> > > T57T;
|
||||
typedef Tuple<Types<Num<3>,Num<5> > > T35T;
|
||||
DISPLAY (T135L);
|
||||
DISPLAY (T57T);
|
||||
DISPLAY (T35T);
|
||||
|
||||
|
||||
T135L sub135;
|
||||
T57T sub57;
|
||||
T35T sub35 (Num<3>(8),Num<5>(8));
|
||||
|
||||
|
||||
DUMPVAL (sub135);
|
||||
T1357T b_135 = tuple::BuildTuple<T1357T,T135L>::create(sub135);
|
||||
DUMPVAL (b_135);
|
||||
|
|
@ -346,113 +346,113 @@ namespace test {
|
|||
DUMPVAL (b_135);
|
||||
b_135 = tuple::BuildTuple<TT,Types1::List>::create(sub135);
|
||||
DUMPVAL (b_135); // all variations of type specification lead to the same result
|
||||
|
||||
|
||||
DUMPVAL (sub57);
|
||||
T1357T b_57 = tuple::BuildTuple<T1357T,T57T,2>::create(sub57);
|
||||
DUMPVAL (b_57);
|
||||
|
||||
|
||||
DUMPVAL (sub35);
|
||||
T1357T b_35 = tuple::BuildTuple<T1357T,T35T,1>::create(sub35);
|
||||
DUMPVAL (b_35);
|
||||
|
||||
|
||||
b_35 = tuple::BuildTuple<T1357T,T35T,2>::create(sub35);
|
||||
DUMPVAL (b_35); // note: wrong start position, argument tuple ignored completely
|
||||
b_35 = tuple::BuildTuple<T1357T,T35T,4>::create(sub35);
|
||||
DUMPVAL (b_35);
|
||||
|
||||
|
||||
// use an argument tuple beyond the last argument of the target tuple...
|
||||
typedef Tuple<Types<Num<7>,Num<8> > > T78T;
|
||||
T78T sub78 (Num<7>(77),Num<8>(88));
|
||||
DUMPVAL (sub78);
|
||||
T1357T b_78 = tuple::BuildTuple<T1357T,T78T,3>::create(sub78);
|
||||
DUMPVAL (b_78); // note: superfluous arguments ignored
|
||||
|
||||
|
||||
typedef Tuple<Types<> > NulT;
|
||||
NulT nult;
|
||||
T1357T b_nul = tuple::BuildTuple<T1357T,NulT,1>::create(nult);
|
||||
DUMPVAL (b_nul);
|
||||
b_nul = tuple::BuildTuple<T1357T,NulT,4>::create(nult);
|
||||
DUMPVAL (b_nul);
|
||||
|
||||
|
||||
NulT b_nul2 = tuple::BuildTuple<NulT,T78T>::create(sub78);
|
||||
DUMPVAL (b_nul2)
|
||||
b_nul2 = tuple::BuildTuple<NulT,T78T,1>::create(sub78);
|
||||
DUMPVAL (b_nul2)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
check_tuple_copy()
|
||||
{
|
||||
cout << "\t:\n\t: ---copy-operations---\n";
|
||||
|
||||
|
||||
Tuple<Types1> tup1 (Num<1>(11), Num<3>(33), Num<5>() );
|
||||
|
||||
|
||||
Tuple<Types1> tup11 (tup1);
|
||||
tup11.getAt<2>().o_ = 44;
|
||||
DUMPVAL (tup1);
|
||||
DUMPVAL (tup11);
|
||||
|
||||
|
||||
tup1 = tup11;
|
||||
DUMPVAL (tup1);
|
||||
|
||||
|
||||
Tuple<Types1::List> tupL = tup11.getShifted<0>();
|
||||
Tuple<Types1> tup1L (tupL); // create plain tuple from list-style tuple
|
||||
DUMPVAL (tupL);
|
||||
DUMPVAL (tup1L);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
check_value_access()
|
||||
{
|
||||
cout << "\t:\n\t: ---value-access---\n";
|
||||
|
||||
|
||||
typedef Append<Types2::List, Types2::List>::List T2424;
|
||||
typedef Tuple<T2424> TupX;
|
||||
TupX tupX;
|
||||
DISPLAY (TupX);
|
||||
DUMPVAL (tupX);
|
||||
|
||||
|
||||
Tuple<Types2> tu2;
|
||||
DUMPVAL (tu2);
|
||||
tuple::element<1>(tu2).o_ = 5;
|
||||
tu2.getHead() = Num<2> (tu2.getAt<1>().o_);
|
||||
DUMPVAL (tu2);
|
||||
|
||||
|
||||
|
||||
|
||||
tupX.getShifted<2>() = tu2;
|
||||
DUMPVAL (tupX);
|
||||
|
||||
|
||||
typedef Shifted<TupX::TupleType,2>::TupleType T4;
|
||||
T4 t4 (tupX.getShifted<2>());
|
||||
DISPLAY (T4);
|
||||
DUMPVAL (t4);
|
||||
|
||||
|
||||
DISPLAY (TupX::Type)
|
||||
DISPLAY (TupX::TailType)
|
||||
DISPLAY (TupX::ThisType)
|
||||
DISPLAY (TupX::TupleType)
|
||||
|
||||
|
||||
typedef TupX::TupleType TupT;
|
||||
DISPLAY (TupT::Type)
|
||||
DISPLAY (TupT::TailType)
|
||||
DISPLAY (TupT::ThisType)
|
||||
DISPLAY (TupT::TupleType)
|
||||
|
||||
|
||||
TupT tupXcopy (tupX);
|
||||
DUMPVAL (tupXcopy);
|
||||
|
||||
|
||||
TupT& tupXcast (tupX.tupleCast()); // (down)cast list-style to plain tuple
|
||||
DUMPVAL (tupXcast);
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (TypeTuple_test, "unit common");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}}} // namespace lumiera::typelist::test
|
||||
|
|
|
|||
|
|
@ -23,7 +23,9 @@
|
|||
|
||||
|
||||
#include "lib/test/run.hpp"
|
||||
#include "lib/test/test-helper.hpp"
|
||||
#include "lib/util.hpp"
|
||||
#include "lib/error.hpp"
|
||||
|
||||
#include "lib/scoped-holder.hpp"
|
||||
#include "testdummy.hpp"
|
||||
|
|
@ -38,6 +40,7 @@ namespace test{
|
|||
|
||||
using ::Test;
|
||||
using util::isnil;
|
||||
using lumiera::error::LUMIERA_ERROR_LOGIC;
|
||||
|
||||
using std::map;
|
||||
using std::cout;
|
||||
|
|
@ -47,7 +50,7 @@ namespace test{
|
|||
|
||||
|
||||
/**********************************************************************************
|
||||
* @test ScopedHolder and ScopedPtrHolder are initially empty and copyable.
|
||||
* @test ScopedHolder and ScopedPtrHolder are initially empty and copyable.
|
||||
* After taking ownership, they prohibit copy operations, manage the
|
||||
* lifecycle of the contained object and provide smart-ptr like access.
|
||||
* A series of identical tests is conducted both with the ScopedPtrHolder
|
||||
|
|
@ -105,8 +108,8 @@ namespace test{
|
|||
|
||||
TRACE (test, "holder at %p", &holder);
|
||||
TRACE (test, "object at %p", holder.get() );
|
||||
TRACE (test, "size(object) = %u", sizeof(*holder));
|
||||
TRACE (test, "size(holder) = %u", sizeof(holder));
|
||||
TRACE (test, "size(object) = %lu", sizeof(*holder));
|
||||
TRACE (test, "size(holder) = %lu", sizeof(holder));
|
||||
}
|
||||
CHECK (0==checksum);
|
||||
}
|
||||
|
|
@ -132,7 +135,7 @@ namespace test{
|
|||
checksum -= val;
|
||||
CHECK (0==checksum);
|
||||
}
|
||||
CHECK (!holder); /* because the exception happens in ctor
|
||||
CHECK (!holder); /* because the exception happens in ctor
|
||||
object doesn't count as "created" */
|
||||
throw_in_ctor = false;
|
||||
}
|
||||
|
|
@ -157,60 +160,34 @@ namespace test{
|
|||
CHECK (holder);
|
||||
long currSum = checksum;
|
||||
void* adr = holder.get();
|
||||
try
|
||||
{
|
||||
holder2 = holder;
|
||||
NOTREACHED ();
|
||||
}
|
||||
catch (lumiera::error::Logic&)
|
||||
{
|
||||
CHECK (holder);
|
||||
CHECK (!holder2);
|
||||
CHECK (holder.get()==adr);
|
||||
CHECK (checksum==currSum);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
holder = holder2;
|
||||
NOTREACHED ();
|
||||
}
|
||||
catch (lumiera::error::Logic&)
|
||||
{
|
||||
CHECK (holder);
|
||||
CHECK (!holder2);
|
||||
CHECK (holder.get()==adr);
|
||||
CHECK (checksum==currSum);
|
||||
}
|
||||
VERIFY_ERROR(LOGIC, holder2 = holder );
|
||||
CHECK (holder);
|
||||
CHECK (!holder2);
|
||||
CHECK (holder.get()==adr);
|
||||
CHECK (checksum==currSum);
|
||||
|
||||
VERIFY_ERROR(LOGIC, holder = holder2 );
|
||||
CHECK (holder);
|
||||
CHECK (!holder2);
|
||||
CHECK (holder.get()==adr);
|
||||
CHECK (checksum==currSum);
|
||||
|
||||
create_contained_object (holder2);
|
||||
CHECK (holder2);
|
||||
CHECK (checksum != currSum);
|
||||
currSum = checksum;
|
||||
try
|
||||
{
|
||||
holder = holder2;
|
||||
NOTREACHED ();
|
||||
}
|
||||
catch (lumiera::error::Logic&)
|
||||
{
|
||||
CHECK (holder);
|
||||
CHECK (holder2);
|
||||
CHECK (holder.get()==adr);
|
||||
CHECK (checksum==currSum);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
HO holder3 (holder2);
|
||||
NOTREACHED ();
|
||||
}
|
||||
catch (lumiera::error::Logic&)
|
||||
{
|
||||
CHECK (holder);
|
||||
CHECK (holder2);
|
||||
CHECK (checksum==currSum);
|
||||
}
|
||||
VERIFY_ERROR(LOGIC, holder = holder2 );
|
||||
CHECK (holder);
|
||||
CHECK (holder2);
|
||||
CHECK (holder.get()==adr);
|
||||
CHECK (checksum==currSum);
|
||||
|
||||
VERIFY_ERROR(LOGIC, HO holder3 (holder2) );
|
||||
CHECK (holder);
|
||||
CHECK (holder2);
|
||||
CHECK (checksum==currSum);
|
||||
}
|
||||
CHECK (0==checksum);
|
||||
}
|
||||
|
|
@ -236,7 +213,7 @@ namespace test{
|
|||
CHECK (!contained);
|
||||
} // 100 holder objects created by sideeffect
|
||||
|
||||
CHECK (0==checksum); // ..... without creating any contained object!
|
||||
CHECK (0==checksum); // ..... without creating any contained object!
|
||||
CHECK (!isnil (maph));
|
||||
CHECK (100==maph.size());
|
||||
|
||||
|
|
@ -257,7 +234,7 @@ namespace test{
|
|||
CHECK (checksum == currSum - value55); // proves object#55's dtor has been invoked
|
||||
CHECK (maph.size() == 99);
|
||||
|
||||
maph[55]; // create new empty holder by sideeffect...
|
||||
maph[55]; // create new empty holder by sideeffect...
|
||||
CHECK (&maph[55]);
|
||||
CHECK (!maph[55]);
|
||||
CHECK (maph.size() == 100);
|
||||
|
|
@ -272,4 +249,3 @@ namespace test{
|
|||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@
|
|||
#include "lib/util.hpp"
|
||||
|
||||
#include "lib/scoped-holder.hpp"
|
||||
#include "lib/scopedholdertransfer.hpp"
|
||||
#include "lib/scoped-holder-transfer.hpp"
|
||||
#include "testdummy.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
|
@ -67,9 +67,9 @@ namespace lib {
|
|||
|
||||
if (throw_in_transfer)
|
||||
throw to.getVal();
|
||||
|
||||
to.setVal (from.getVal());
|
||||
from.setVal(0);
|
||||
|
||||
swap (from,to);
|
||||
from.setVal(0); // remove the old Dummy from accounting (checksum)
|
||||
}
|
||||
|
||||
};
|
||||
|
|
@ -41,9 +41,9 @@ using std::cout;
|
|||
|
||||
namespace lib {
|
||||
namespace test{
|
||||
|
||||
|
||||
using lumiera::error::LUMIERA_ERROR_ASSERTION;
|
||||
|
||||
|
||||
/**
|
||||
* Target object to be instantiated as Singleton
|
||||
* Allocates a variable amount of additional heap memory
|
||||
|
|
@ -54,34 +54,34 @@ namespace test{
|
|||
public:
|
||||
static int cnt;
|
||||
static void setCountParam (uint c) { Interface::cnt = c; }
|
||||
|
||||
|
||||
virtual string identify() { return "Interface"; }
|
||||
|
||||
|
||||
protected:
|
||||
Interface () : TestTargetObj(cnt) {}
|
||||
virtual ~Interface() {}
|
||||
|
||||
|
||||
friend class singleton::StaticCreate<Interface>;
|
||||
friend class singleton::HeapCreate<Interface>;
|
||||
};
|
||||
|
||||
|
||||
int Interface::cnt = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
class Impl : public Interface
|
||||
{
|
||||
public:
|
||||
virtual string identify() { return "Implementation"; }
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
// for checking the safety.....
|
||||
class Impl_XXX : public Impl { };
|
||||
class Unrelated { };
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* @test specialised variant of the Singleton Factory, for creating
|
||||
* subclasses (implementation classes) without coupling the
|
||||
|
|
@ -93,33 +93,34 @@ namespace test{
|
|||
*/
|
||||
class SingletonSubclass_test : public Test
|
||||
{
|
||||
|
||||
virtual void run(Arg arg)
|
||||
|
||||
virtual void
|
||||
run(Arg arg)
|
||||
{
|
||||
uint num= isnil(arg)? 1 : lexical_cast<uint>(arg[1]);
|
||||
|
||||
|
||||
cout << format("using the Singleton should create TargetObj(%d)...\n") % num;
|
||||
|
||||
|
||||
Interface::setCountParam(num);
|
||||
|
||||
|
||||
// marker to declare the concrete type to be created
|
||||
singleton::UseSubclass<Impl> typeinfo;
|
||||
|
||||
|
||||
// define an instance of the Singleton factory,
|
||||
// Specialised to create the concrete Type passed in
|
||||
SingletonSubclassFactory<Interface> instance (typeinfo);
|
||||
|
||||
|
||||
// Now use the Singleton factory...
|
||||
// Note: we get the Base type
|
||||
Interface& t1 = instance();
|
||||
Interface& t2 = instance();
|
||||
|
||||
|
||||
CHECK ( &t1 == &t2, "not a Singleton, got two different instances." );
|
||||
|
||||
|
||||
cout << "calling a non-static method on the Singleton-"
|
||||
<< t1.identify() << "\n"
|
||||
<< string (t1) << "\n";
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////TODO: find a way to configure NoBug to throw in case of assertion
|
||||
///////////////////////////////////////////////////////////////////////////////TODO: just for the proc tests. Also find a better way to configure
|
||||
///////////////////////////////////////////////////////////////////////////////TODO: the non-release check. Then re-enable these checks...
|
||||
|
|
@ -127,32 +128,33 @@ namespace test{
|
|||
// verify_error_detection ();
|
||||
//#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
void verify_error_detection ()
|
||||
|
||||
|
||||
|
||||
void
|
||||
verify_error_detection ()
|
||||
{
|
||||
|
||||
|
||||
singleton::UseSubclass<Impl_XXX> more_special_type;
|
||||
|
||||
|
||||
VERIFY_ERROR (ASSERTION, SingletonSubclassFactory<Interface> instance (more_special_type) );
|
||||
/* in debug mode, an attempt to re-configure an already
|
||||
* configured SingletonSubclassFactory with another type
|
||||
* should be detected and spotted by assertion failure */
|
||||
|
||||
|
||||
|
||||
|
||||
// Note: the following won't compile, because the "subclass" isn't a subclass...
|
||||
//
|
||||
// singleton::UseSubclass<Unrelated> yet_another_type;
|
||||
// SingletonSubclassFactory<Interface> instance (yet_another_type);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (SingletonSubclass_test, "unit common");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
|
|
|||
|
|
@ -40,23 +40,23 @@ using util::isnil;
|
|||
|
||||
namespace lib {
|
||||
namespace test{
|
||||
|
||||
|
||||
using std::string;
|
||||
using boost::hash;
|
||||
|
||||
|
||||
|
||||
|
||||
namespace { // test data
|
||||
Symbol KEY1 ("Key1");
|
||||
Symbol KEY2 ("Key2");
|
||||
Symbol KEY3 ("Key3");
|
||||
Symbol KEY4 ("Key4");
|
||||
Symbol KEY5 ("Key5");
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
typedef std::tr1::unordered_map< Symbol, string, hash<Symbol> > HTable;
|
||||
|
||||
|
||||
|
||||
|
||||
/*************************************************************
|
||||
* @test build a hashtable using Symbol objects as Keys.
|
||||
* Especially this verifies picking up a customised
|
||||
|
|
@ -65,20 +65,20 @@ namespace test{
|
|||
*/
|
||||
class SymbolHashtable_test : public Test
|
||||
{
|
||||
|
||||
void
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
checkHashFunction();
|
||||
|
||||
|
||||
HTable table;
|
||||
CHECK (isnil(table));
|
||||
|
||||
|
||||
table[KEY1] = string (KEY1);
|
||||
table[KEY2] = string (KEY2);
|
||||
table[KEY3] = string (KEY3);
|
||||
table[KEY4] = string (KEY4);
|
||||
|
||||
|
||||
CHECK (!isnil(table));
|
||||
CHECK (4 == table.size());
|
||||
CHECK (contains (table, KEY1));
|
||||
|
|
@ -86,80 +86,79 @@ namespace test{
|
|||
CHECK (contains (table, KEY3));
|
||||
CHECK (contains (table, KEY4));
|
||||
CHECK (!contains (table, KEY5));
|
||||
|
||||
|
||||
CHECK (string (KEY1) == table[KEY1]);
|
||||
CHECK (string (KEY2) == table[KEY2]);
|
||||
CHECK (string (KEY3) == table[KEY3]);
|
||||
CHECK (string (KEY4) == table[KEY4]);
|
||||
|
||||
|
||||
table[KEY3] += "...";
|
||||
CHECK (string(KEY3) != table[KEY3]);
|
||||
CHECK (string(KEY3)+"..." == table[KEY3]);
|
||||
|
||||
|
||||
CHECK (isnil (table[KEY5])); // adds a new empty value object as side effect
|
||||
CHECK (5 == table.size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
checkHashFunction()
|
||||
{
|
||||
string random = randStr(STRING_MAX_RELEVANT+1);
|
||||
|
||||
|
||||
string copy1(random);
|
||||
copy1[5] = '\0'; // truncate the c-String to 5 chars
|
||||
|
||||
|
||||
string copy2(random);
|
||||
copy2[rand() % STRING_MAX_RELEVANT] = '*'; // modify a random position
|
||||
|
||||
|
||||
string copy3(copy2);
|
||||
copy3[STRING_MAX_RELEVANT] = '*'; // modify behind observation limit
|
||||
|
||||
|
||||
Symbol l0;
|
||||
Literal l51 (copy1.c_str());
|
||||
Literal l52 (random.substr(0,5).c_str());
|
||||
|
||||
|
||||
Literal l_1 (random.c_str());
|
||||
Literal l_2 (copy2.c_str());
|
||||
Literal l_3 (copy3.c_str());
|
||||
|
||||
|
||||
CHECK (isnil (l0));
|
||||
CHECK (l0 != l51);
|
||||
CHECK (l51 == l52);
|
||||
|
||||
|
||||
CHECK (l51 != l_1);
|
||||
CHECK (l_1 != l_2);
|
||||
CHECK (l_2 == l_3); // difference not detected due to observation limit...
|
||||
CHECK (!std::strncmp (l_2, l_3, STRING_MAX_RELEVANT ));
|
||||
CHECK ( std::strncmp (l_2, l_3, STRING_MAX_RELEVANT+1));
|
||||
|
||||
|
||||
size_t h0 = hash_value (l0);
|
||||
size_t h51 = hash_value (l51);
|
||||
size_t h52 = hash_value (l52);
|
||||
size_t h_1 = hash_value (l_1);
|
||||
size_t h_2 = hash_value (l_2);
|
||||
size_t h_3 = hash_value (l_3);
|
||||
|
||||
|
||||
CHECK (h0 == 0);
|
||||
CHECK (h51 != 0);
|
||||
CHECK (h52 != 0);
|
||||
CHECK (h_1 != 0);
|
||||
CHECK (h_2 != 0);
|
||||
CHECK (h_3 != 0);
|
||||
|
||||
|
||||
CHECK (h51 == h52); // verify the hash function indeed stops at '\0'
|
||||
CHECK (h51 != h_1); // share a common prefix, but the hash differs
|
||||
CHECK (h_1 != h_2); // the single random modification is detected
|
||||
CHECK (h_2 == h_3); // because l_2 and l_3 differ behind the fixed observation limit
|
||||
|
||||
|
||||
CHECK (h_1 == hash_value (l_1)); //reproducible
|
||||
CHECK (h_2 == hash_value (l_2));
|
||||
CHECK (h_3 == hash_value (l_3));
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
LAUNCHER (SymbolHashtable_test, "function common");
|
||||
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
||||
|
|
|
|||
|
|
@ -45,13 +45,13 @@ namespace test{
|
|||
* @test properties of Symbol data type. Currently this is
|
||||
* just a thin wrapper for a const char *
|
||||
* @todo this test is very much WIP, as the implementation
|
||||
* of a real symbol type and symbol table remains
|
||||
* to be done. See Ticket #157
|
||||
* of a real symbol type and symbol table remains
|
||||
* to be done. ///////////////////////////Ticket #157
|
||||
*/
|
||||
class Symbol_test : public Test
|
||||
{
|
||||
|
||||
void
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
checkLiteral();
|
||||
|
|
@ -126,4 +126,3 @@ namespace test{
|
|||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ namespace test {
|
|||
}
|
||||
|
||||
ClassLock<Probe> get_class_lock;
|
||||
CHECK ( 1 == get_class_lock.use_count()); // embedded PerClassMonitor<Probe> got created exactly once
|
||||
CHECK ( 1 == get_class_lock.use_count()); // embedded PerClassMonitor<Probe> got created exactly once
|
||||
} // and stays alive until static dtors are called....
|
||||
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,29 +34,29 @@ using test::Test;
|
|||
|
||||
namespace lib {
|
||||
namespace test{
|
||||
|
||||
|
||||
namespace { // private test classes and data...
|
||||
|
||||
|
||||
const uint WAIT_mSec = 200; ///< milliseconds to wait before timeout
|
||||
|
||||
|
||||
} // (End) test classes and data....
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/********************************************************************************
|
||||
* @test timeout feature on condition wait as provided by pthread and accessible
|
||||
* via the object monitor based locking/waiting mechanism. Without creating
|
||||
* multiple threads, we engage into a blocking wait, which aborts due to
|
||||
* setting a timeout. (Note it is discouraged to use the timed wait feature;
|
||||
* when possible, you should prefer relying on the Lumiera scheduler)
|
||||
*
|
||||
*
|
||||
* @see SyncWaiting_test
|
||||
* @see sync::Timeout
|
||||
* @see sync.hpp
|
||||
|
|
@ -65,48 +65,48 @@ namespace test{
|
|||
: public Test,
|
||||
Sync<RecursiveLock_Waitable>
|
||||
{
|
||||
|
||||
|
||||
friend class Lock; // allows inheriting privately from Sync
|
||||
|
||||
|
||||
|
||||
|
||||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
checkTimeoutStruct();
|
||||
|
||||
|
||||
Lock block(this, &SyncTimedwait_test::neverHappens);
|
||||
|
||||
|
||||
cout << "back from LaLaLand, alive and thriving!\n";
|
||||
CHECK (block.isTimedWait());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool
|
||||
neverHappens() ///< the "condition test" used for waiting....
|
||||
{
|
||||
Lock currentLock(this); // get the Lock recursively
|
||||
if (!currentLock.isTimedWait()) // right from within the condition test:
|
||||
currentLock.setTimeout(WAIT_mSec); // switch waiting mode to timed wait and set timeout
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
void
|
||||
checkTimeoutStruct()
|
||||
{
|
||||
sync::Timeout tout;
|
||||
|
||||
|
||||
CHECK (!tout);
|
||||
CHECK (0 == tout.tv_sec);
|
||||
CHECK (0 == tout.tv_nsec);
|
||||
|
||||
|
||||
tout.setOffset (0);
|
||||
CHECK (!tout);
|
||||
CHECK (0 == tout.tv_sec);
|
||||
CHECK (0 == tout.tv_nsec);
|
||||
|
||||
|
||||
timespec ref;
|
||||
clock_gettime(CLOCK_REALTIME, &ref);
|
||||
tout.setOffset (1);
|
||||
|
|
@ -114,7 +114,7 @@ namespace test{
|
|||
CHECK (0 < tout.tv_sec);
|
||||
CHECK (ref.tv_sec <= tout.tv_sec);
|
||||
CHECK (ref.tv_nsec <= 1000000 + tout.tv_nsec || ref.tv_nsec > 1000000000-100000);
|
||||
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &ref);
|
||||
tout.setOffset (1000);
|
||||
CHECK (tout);
|
||||
|
|
@ -125,14 +125,14 @@ namespace test{
|
|||
<= tout.tv_nsec);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Register this test class... */
|
||||
LAUNCHER (SyncTimedwait_test, "unit common");
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}} // namespace lib::test
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace lib {
|
||||
|
|
@ -63,6 +64,12 @@ namespace test{
|
|||
val_ = newVal;
|
||||
}
|
||||
|
||||
friend void
|
||||
swap (Dummy& dum1, Dummy& dum2) ///< checksum neutral
|
||||
{
|
||||
std::swap(dum1.val_, dum2.val_);
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
init()
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@
|
|||
|
||||
#include "lib/test/run.hpp"
|
||||
|
||||
#include "lib/scopedholdertransfer.hpp"
|
||||
#include "lib/scoped-holder-transfer.hpp"
|
||||
#include "testdummy.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
format 58
|
||||
"Builder" // ProcessingLayer::MObject::Builder
|
||||
revision 20
|
||||
revision 21
|
||||
modified_by 5 "hiv"
|
||||
// class settings
|
||||
//class diagram settings
|
||||
|
|
@ -74,7 +74,7 @@ format 58
|
|||
iterative
|
||||
activityaction 128773 "define segment"
|
||||
opaque_action
|
||||
pin 128133 "inFixture" explicit_type ""
|
||||
pin 128133 "inContent" explicit_type ""
|
||||
unordered
|
||||
in
|
||||
end
|
||||
|
|
@ -107,11 +107,11 @@ format 58
|
|||
end
|
||||
|
||||
flow 130181 "<flow>"
|
||||
on pin_ref 128133 // inFixture
|
||||
on pin_ref 128133 // inContent
|
||||
end
|
||||
|
||||
flow 131717 "<flow>"
|
||||
on pin_ref 128133 // inFixture
|
||||
on pin_ref 128133 // inContent
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -168,6 +168,14 @@ format 58
|
|||
|
||||
activitynode 129157 activity_final ""
|
||||
end
|
||||
|
||||
activityobject 129157 "Timeline contents"
|
||||
explicit_type ""
|
||||
unordered
|
||||
flow 133125 "<flow>"
|
||||
on pin_ref 128133 // inContent
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
classdiagram 129285 "Builder Tool (Visitor)"
|
||||
|
|
|
|||
|
|
@ -2,76 +2,72 @@ format 58
|
|||
|
||||
activitycanvas 130437 activity_ref 128005 // building the Engine
|
||||
show_infonote default drawing_language default show_stereotype_properties default
|
||||
xyzwh 147 27 2000 581 532
|
||||
xyzwh 120 26 2000 468 525
|
||||
params
|
||||
parametercanvas 130565 parameter_ref 128645 // build Request
|
||||
xyzwh 541 12 2002 113 31
|
||||
xyzwh 401 11 2002 113 31
|
||||
end
|
||||
end
|
||||
end
|
||||
activityactioncanvas 130693 activityaction_ref 128645 // activity action configure Tools
|
||||
show_infonote default drawing_language default show_stereotype_properties default
|
||||
show_opaque_action_definition default
|
||||
xyzwh 529 71 2005 136 41
|
||||
xyzwh 389 63 2005 136 41
|
||||
end
|
||||
expansionregioncanvas 130821 expansionregion_ref 128133 // establish partitioning
|
||||
xyzwh 359 208 2005 205 96
|
||||
xyzwh 219 200 2005 205 96
|
||||
nodes
|
||||
expansionnodecanvas 131077 expansionnode_ref 128005 // segment Tool
|
||||
xyzwh 458 203 2007 33 11 label_xy 456 183
|
||||
xyzwh 318 195 2007 33 11 label_xy 316 175
|
||||
end
|
||||
expansionnodecanvas 132613 expansionnode_ref 128133 // segments
|
||||
xyzwh 460 298 2007 33 11 label_xy 459 312
|
||||
xyzwh 320 290 2007 33 11 label_xy 319 304
|
||||
end
|
||||
end
|
||||
end
|
||||
activityactioncanvas 130949 activityaction_ref 128773 // activity action define segment
|
||||
show_infonote default drawing_language default show_stereotype_properties default
|
||||
show_opaque_action_definition default
|
||||
xyzwh 409 236 2010 135 42
|
||||
xyzwh 269 228 2010 135 42
|
||||
pins
|
||||
pincanvas 131205 pin_ref 128133 // inFixture
|
||||
xyzwh 399 249 2012 11 11 label_xy 315 241
|
||||
pincanvas 131205 pin_ref 128133 // inContent
|
||||
xyzwh 259 241 2012 11 11 label_xy 170 250
|
||||
end
|
||||
end
|
||||
end
|
||||
activityobjectcanvas 131333 activityobject_ref 128005 // activity object Fixture
|
||||
show_infonote default drawing_language default show_stereotype_properties default
|
||||
xyzwh 177 239 2005 49 31
|
||||
end
|
||||
activitynodecanvas 133509 activitynode_ref 129029 // fork
|
||||
horizontal xyz 585 147 2005
|
||||
horizontal xyz 445 139 2005
|
||||
end
|
||||
expansionregioncanvas 133893 expansionregion_ref 128261 // build Processors
|
||||
xyzwh 359 349 2005 272 152
|
||||
xyzwh 219 341 2005 272 152
|
||||
nodes
|
||||
expansionnodecanvas 134021 expansionnode_ref 128261 // build Tool
|
||||
xyzwh 581 344 2007 33 11 label_xy 573 324
|
||||
xyzwh 441 336 2007 33 11 label_xy 433 316
|
||||
end
|
||||
expansionnodecanvas 134149 expansionnode_ref 128389 // segments
|
||||
xyzwh 460 344 2007 33 11 label_xy 460 359
|
||||
xyzwh 320 336 2007 33 11 label_xy 320 351
|
||||
end
|
||||
expansionnodecanvas 136581 expansionnode_ref 128517 // complete Render Engine
|
||||
xyzwh 460 495 2007 33 11 label_xy 496 500
|
||||
xyzwh 320 487 2007 33 11 label_xy 356 492
|
||||
end
|
||||
end
|
||||
end
|
||||
activityactioncanvas 134277 activityaction_ref 128901 // activity action create ProcNode
|
||||
show_infonote default drawing_language default show_stereotype_properties default
|
||||
show_opaque_action_definition default
|
||||
xyzwh 419 389 2010 114 42
|
||||
xyzwh 279 381 2010 114 42
|
||||
end
|
||||
activityactioncanvas 134405 activityaction_ref 129029 // activity action connect
|
||||
show_infonote default drawing_language default show_stereotype_properties default
|
||||
show_opaque_action_definition default
|
||||
xyzwh 420 442 2015 113 42
|
||||
xyzwh 280 434 2015 113 42
|
||||
end
|
||||
activitynodecanvas 134533 activitynode_ref 129157 // activity_final
|
||||
xyz 543 527 2005
|
||||
xyz 403 519 2005
|
||||
end
|
||||
simplerelationcanvas 131461 simplerelation_ref 128389
|
||||
from ref 131333 z 1999 to point 400 253
|
||||
line 131589 z 1999 to ref 130437
|
||||
activityobjectcanvas 137093 activityobject_ref 129157 // activity object Timeline contents
|
||||
show_infonote default drawing_language default show_stereotype_properties default
|
||||
xyzwh 147 157 2005 99 31
|
||||
end
|
||||
flowcanvas 132101 flow_ref 130309 // <flow>
|
||||
|
||||
|
|
@ -92,8 +88,8 @@ end
|
|||
flowcanvas 133765 flow_ref 130949 // <flow>
|
||||
geometry VHV
|
||||
|
||||
from ref 133509 z 2004 to point 595 180
|
||||
line 134789 z 2004 to point 472 180
|
||||
from ref 133509 z 2004 to point 455 172
|
||||
line 134789 z 2004 to point 332 172
|
||||
line 134917 z 2004 to ref 131077
|
||||
show_infonote default drawing_language default show_stereotype_properties default write_horizontally default
|
||||
end
|
||||
|
|
@ -105,7 +101,7 @@ end
|
|||
flowcanvas 135429 flow_ref 131205 // <flow>
|
||||
geometry HVr
|
||||
|
||||
from ref 134021 z 2006 to point 595 407
|
||||
from ref 134021 z 2006 to point 455 399
|
||||
line 135557 z 2006 to ref 134277
|
||||
show_infonote default drawing_language default show_stereotype_properties default write_horizontally default
|
||||
end
|
||||
|
|
@ -119,11 +115,6 @@ flowcanvas 136197 flow_ref 131461 // <flow>
|
|||
from ref 134277 z 2009 to ref 134405
|
||||
show_infonote default drawing_language default show_stereotype_properties default write_horizontally default
|
||||
end
|
||||
flowcanvas 136453 flow_ref 131717 // <flow>
|
||||
|
||||
from ref 131333 z 2004 to ref 131205
|
||||
show_infonote default drawing_language default show_stereotype_properties default write_horizontally default
|
||||
end
|
||||
flowcanvas 136709 flow_ref 131845 // <flow>
|
||||
|
||||
from ref 134405 z 2006 to ref 136581
|
||||
|
|
@ -131,9 +122,16 @@ flowcanvas 136709 flow_ref 131845 // <flow>
|
|||
end
|
||||
flowcanvas 136837 flow_ref 131973 // <flow>
|
||||
|
||||
from ref 136581 z 2004 to point 487 524
|
||||
from ref 136581 z 2004 to point 347 516
|
||||
line 136965 z 2004 to ref 134533
|
||||
show_infonote default drawing_language default show_stereotype_properties default write_horizontally default
|
||||
end
|
||||
preferred_whz 768 616 1
|
||||
flowcanvas 137221 flow_ref 133125 // <flow>
|
||||
geometry VH
|
||||
|
||||
from ref 137093 z 2004 to point 194 244
|
||||
line 137349 z 2004 to ref 131205
|
||||
show_infonote default drawing_language default show_stereotype_properties default write_horizontally default
|
||||
end
|
||||
preferred_whz 627 621 1
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,11 +1,13 @@
|
|||
window_sizes 1324 1020 270 1044 872 71
|
||||
window_sizes 1615 1020 270 1335 872 71
|
||||
diagrams
|
||||
classdiagram_ref 136453 // Session backbone
|
||||
631 352 100 4 0 0
|
||||
active objectdiagram_ref 138885 // ModelAssetRelations
|
||||
objectdiagram_ref 138885 // ModelAssetRelations
|
||||
730 488 100 4 0 0
|
||||
classdiagram_ref 128133 // Session structure
|
||||
835 697 100 4 0 0
|
||||
835 697 100 4 300 0
|
||||
active activitydiagram_ref 129413 // build flow
|
||||
627 621 100 4 0 0
|
||||
end
|
||||
show_stereotypes
|
||||
selected
|
||||
|
|
@ -31,7 +33,7 @@ open
|
|||
class_ref 152453 // PlacementRef
|
||||
classrelation_ref 178437 // <realization>
|
||||
class_ref 153733 // QueryFocusStack
|
||||
classview_ref 128261 // Builder Workings
|
||||
expansionregion_ref 128133 // establish partitioning
|
||||
usecaseview_ref 128261 // config examples
|
||||
classview_ref 128133 // Engine Workings
|
||||
class_ref 164485 // Request
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
format 58
|
||||
"lumiera"
|
||||
revision 64
|
||||
revision 65
|
||||
modified_by 5 "hiv"
|
||||
cpp_root_dir "../../src/"
|
||||
|
||||
|
|
|
|||
BIN
wiki/draw/Fixture1.png
Normal file
BIN
wiki/draw/Fixture1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 81 KiB |
BIN
wiki/draw/SegmentationSteps1.png
Normal file
BIN
wiki/draw/SegmentationSteps1.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 72 KiB |
|
|
@ -1077,6 +1077,26 @@ Please note the shortcomings and logical contradictions in the solution currentl
|
|||
* The current design rather places the implementation according to the roles of the involved entities, which causes some ping-pong on the implementation level. Especially the ScopeLocator singleton can be accessed multiple times. This is the usual clarity vs. performance tradeoff. Scope resolution is assumed rather to be //not performance critical.//
|
||||
</pre>
|
||||
</div>
|
||||
<div title="BuildFixture" modifier="Ichthyostega" modified="201011290504" created="201011282003" tags="Builder spec operational" changecount="32">
|
||||
<pre>//Building the fixture is actually at the core of the [[builder's operation|Builder]]//
|
||||
{{red{WIP as of 11/10}}} &rarr; see also the [[planning page|PlanningBuildFixture]]
|
||||
|
||||
;Resolving the DAG[>img[Steps towards creating a Segmentation|draw/SegmentationSteps1.png]]
|
||||
Because of the possibility of binding a Sequence multiple times, and maybe even nested as virtual clip, the [[high-level model|HighLevelModel]] actually constitutes a DAG, not a tree. This leds to quite some tricky problems, which we try to resolve by //rectifying the DAG into N virtual trees.// (&rarr; BindingScopeProblem)
|
||||
|
||||
Relying on this transformation, each Timeline spans a sub-tree virtually separated from all other timelines; the BuildProcess is driven by [[visiting|VisitorUse]] all the //tangible// objects within this subtree. In the example shown to the right, Sequence-β is both bound as VirtualClip into Sequence-α, as well as bound independently as top-level sequence into Timeline-2. Thus it will be visited twice, but the QueryFocus mechanism ensures that each visitation »sees« the proper context.
|
||||
|
||||
;Explicit Placements
|
||||
Each tangible object placement (relevant for rendering), which is encountered during that visitation, gets //resolved// into an [[explicit placement|ExplicitPlacement]]. If we see [[Placement]] as a positioning within a multi dimensional configuration space, then the resolution into an explicit placement is like the creation of an ''orthogonal base'': Within the explicit placement, each LocatingPin corresponds exactly to one degree of freedom and can be considered independently from all other locating pins. This resolution step removes any fancy dynamic behaviour and all scoping and indirect references. Indeed, an explicit placement is a mere //value object;// it isn't part of the session core (PlacementIndex), isn't typed and can't be referred indirectly.
|
||||
|
||||
;Segmentation of Time axis
|
||||
This simple and explicit positioning thus allows to arrange all objects as time intervals on a single axis. Any change and especially any overlap is likely to create a different wiring configuration. Thus, for each such configuration change, we fork off a new //segment// and //copy over// all partially touched placements. The resulting seamless sequence of non-overlapping time intervals provides the backbone of the datastructure called [[Fixture]].
|
||||
|
||||
;Building the Network
|
||||
From this backbone, the actual [[building mechanism|BuilderMechanics]] proceeds as a ongoing visitation and resolution, resulting in the gowth of a network of [[render nodes|ProcNode]] starting out from the source reading nodes and proceeding up through the local pipes, the transitions and the global pipes. When this build process is exhausted, besides the actual network, the result is a //residuum of nodes not connected any further.// Any of these [[exit nodes|ExitNode]] can be associated to a ~Pipe-ID in the high-level model. Within each segment, there should be one exit node per pipe-ID at max. These are the [[model ports|ModelPort]] resulting from the build process, keyed by their corresponding ~Pipe-ID.
|
||||
&rarr; see [[Structure of the Fixture|Fixture]]
|
||||
</pre>
|
||||
</div>
|
||||
<div title="BuildProcess" modifier="Ichthyostega" modified="200906071813" created="200706190658" tags="Builder operational img" changecount="30">
|
||||
<pre>All decisions on //how // the RenderProcess has to be carried out are concentrated in this rather complicated Builder Subsystem. The benefit of this approach is, besides decoupling of subsystems, to keep the actual performance-intensive video processing code as simple and transparent as possible. The price, in terms of increased complexity &mdash; to pay in the Builder &mdash; can be handled by making the Build Process generic to a large degree. Using a Design By Contract approach we can decompose the various decisions into small decision modules without having to trace the actual workings of the Build Process as a whole.
|
||||
|
||||
|
|
@ -1708,8 +1728,12 @@ To make the intended use of the classes more clear, consider the following two e
|
|||
<pre>a special ProcNode which is used to pull the finished output of one Render Pipeline (Tree or Graph). This term is already used in the Cinelerra2 codebase. I am unsure at the moment if it is a distinct subclass or rahter a specially configured ProcNode (a general design rule tells us to err in favour of the latter if in doubt).
|
||||
</pre>
|
||||
</div>
|
||||
<div title="ExplicitPlacement" modifier="MichaelPloujnikov" modified="200706271458" created="200706220304" tags="def" changecount="2">
|
||||
<pre>A special kind (subclass) of [[Placement]]. As such it is always linked to a //Subject//, i.e. a MObject. In addition to the properties of a (unspecific) Placement, the ExplicitPlacement specifies a absolute time and track position for locating the Subject
|
||||
<div title="ExplicitPlacement" modifier="Ichthyostega" modified="201012122052" created="200706220304" tags="def" changecount="6">
|
||||
<pre>A special kind (subclass) of [[Placement]]. As such it is always linked to a //Subject//, i.e. a MObject. But contrary to the (standard) placements, which may exhibit all kinds of fancy dynamic and scope dependent behaviour, within an explicit placement all properties are resolved and materialised. While the (standard) placement may contain an arbitrary list of LocatingPin objects, the resolution into an explicit placement performs a kind of »orthogonalisation«: each remaining LocatingPin defines exactly one degree of freedom independent of all others. Most notably, the explicit placement always specifies a absolute time and [[output designation|OutputDesignation]] for for locating the Subject. Explicit placements are ''immutable''.
|
||||
|
||||
!!Implementation considerations
|
||||
Explicit placements are just created and never mutated, but copying and storage might become a problem.
|
||||
It would thus be desirable to have a fixed-sized allocation, able to hold the placement body as well as the (fixed) locating pins inline.
|
||||
</pre>
|
||||
</div>
|
||||
<div title="Factories" modifier="Ichthyostega" modified="201003160211" created="200708100401" tags="impl discuss excludeMissing rewrite" changecount="24">
|
||||
|
|
@ -1766,19 +1790,34 @@ Some further details
|
|||
* a special case of this factory use is the [[Singleton]] factory, which is used a lot within the Proy-Layer code
|
||||
</pre>
|
||||
</div>
|
||||
<div title="Fixture" modifier="Ichthyostega" modified="201007160052" created="200706220324" tags="def" changecount="10">
|
||||
<pre>a specially configured sequence list
|
||||
<div title="Fixture" modifier="Ichthyostega" modified="201012092320" created="200706220324" tags="def spec Builder Model" changecount="44">
|
||||
<pre>a specially configured view -- joining together high-level and low-level model
|
||||
* all MObjects have their position, length and configuration set up ready for rendering.
|
||||
* any nested sequences (or other kinds of indirections) have been resolved.
|
||||
* every MObject is associated with an ExplicitPlacement, which declares a fixed position (Time, [[Pipe-ID|OutputDesignation]])
|
||||
* these ~ExplicitPlacements are contained in a ordered List, sometimes denoted as the //effective timeline.//
|
||||
* besides, there is a collection of all effective, possibly externally visible [[model ports|ModelPort]]
|
||||
* every MObject is attached by an ExplicitPlacement, which declares a fixed position (Time, [[Pipe|OutputDesignation]])
|
||||
* these ~ExplicitPlacements are contained immediately within the Fixture, ordered by time
|
||||
* besides, there is a collection of all effective, possibly externally visible [[model ports|ModelPortRegistry]]
|
||||
|
||||
As the builder and thus render engine //only consults the fixture,// while all editing operations finally propagate to the fixture as well, we get an isolation layer between the high level part of the Proc layer (editing, object manipulation) and the render engine. Creating the Fixture can be seen as a preprocessing step to simplify the build process. For this reason, the process of [[(re)building the fixture|PlanningBuildFixture]] has been designed together with the [[Builder]]
|
||||
As the builder and thus render engine //only consults the fixture,// while all editing operations finally propagate to the fixture as well, we get an isolation layer between the high level part of the Proc layer (editing, object manipulation) and the render engine. [[Creating the Fixture|BuildFixture]] is an important sideeffect of running the [[Builder]] when createing the [[render engine network|LowLevelModel]].
|
||||
|
||||
!{{red{WIP}}} Structure of the fixture
|
||||
The fixture is like a grid, where one dimension is given by the [[model ports|ModelPort]], and the other dimension extends in time. The time axis is grouped in segments of constant structure.
|
||||
A problem yet to be solved is how the fixture relates to the mulitude of top-level timelines, without generating a too fine grained segmentation.
|
||||
[<img[Structure of the Fixture|draw/Fixture1.png]]
|
||||
|
||||
The fixture is like a grid, where one dimension is given by the [[model ports|ModelPortRegistry]], and the other dimension extends in time. Within the time dimension there is a grouping into [[segments|Segmentation]] of constant structure.
|
||||
|
||||
;Model Ports
|
||||
:The model ports share a single uniform and global name space: actually they're keyed by ~Pipe-ID
|
||||
:Model ports are derived as a result of the build process, as the //residuum// of all nodes not connected any further
|
||||
:Each port belongs to a specific Timeline and is associated with the [[Segmentation]] of that timeline.
|
||||
|
||||
;Segmentation
|
||||
:The segmentation partitiones the time axis of a single timeline into segments of constant (wiring) configuration
|
||||
:Together, the segments form a seamless sequence of time intervals. They contain a copy of each (explicit) placement of a visible object touching that time interval. Besides that, segments are the top level grouping device of the render engine node graph; they are always built and discarded at once.
|
||||
:Segments may be //hot swapped// into an ongoing render.
|
||||
|
||||
;Exit Nodes
|
||||
:Each segment holds an ExitNode for each relevant ModelPort of the corresponding timeline.
|
||||
:Thus the exit nodes are keyed by ~Pipe-ID as well (and consequently have a distinct [[stream type|StreamType]]) -- each model port coresponds to {{{<number_of_segments>}}} separate exit nodes, but of course an exit node may be //mute.//
|
||||
</pre>
|
||||
</div>
|
||||
<div title="ForwardIterator" modifier="Ichthyostega" modified="200912190027" created="200910312114" tags="Concepts def spec" changecount="17">
|
||||
|
|
@ -2784,12 +2823,41 @@ These are used as token for dealing with other objects and have no identity of t
|
|||
|
||||
</pre>
|
||||
</div>
|
||||
<div title="ModelPort" modifier="Ichthyostega" created="201011100234" tags="def" changecount="1">
|
||||
<pre>Any point where output possibly might be produced. Model port entities are located within the [[Fixture]] &mdash; model port as a concept spans the high-level and low-level view. A model port can be associated both to a pipe in the HighLevelModel and denote a specific ExitNode in the render nodes network.
|
||||
<div title="ModelPort" modifier="Ichthyostega" modified="201012112233" created="201011100234" tags="def spec" changecount="8">
|
||||
<pre>Any point where output possibly might be produced. Model port entities are located within the [[Fixture]] &mdash; model port as a concept spans the high-level and low-level view. A model port can be associated both to a pipe in the HighLevelModel but at the same time denotes a set of corresponding [[exit nodes|ExitNode]] within the [[segments|Segmentation]] of the render nodes network.
|
||||
|
||||
A model port is rather derived than configured; it emerges when a pipe [[claims|WiringClaim]] an output desitnation and some other entity actually uses this designation as a target, either directly or indirecly. This match of provision and usage is detected during the build process and produces an entry in the fixture's model port table. These model ports in the fixture are keyed by ~Pipe-ID, thus each model port has an associated StreamType.
|
||||
A model port is rather derived than configured; it emerges when a pipe [[claims|WiringClaim]] an output destination and some other entity actually uses this designation as a target, either directly or indirectly. This match of provision and usage is detected during the build process and produces an entry in the fixture's model port table. These model ports in the fixture are keyed by ~Pipe-ID, thus each model port has an associated StreamType.
|
||||
|
||||
Model ports are the effective, resulting ouputs of each timeline; additional ports result from [[connecting a viewer|ViewerPlayConnection]]. Any render or display process happens at a model port.
|
||||
Model ports are the effective, resulting outputs of each timeline; additional ports result from [[connecting a viewer|ViewerPlayConnection]]. Any render or display process happens at a model port.
|
||||
|
||||
!formal specification
|
||||
Model port is a //conceptual entity,// denoting the possibility to pull generated data of a distinct (stream)type from a specific bus within the model -- any possible output produced or provided by Lumiera is bound to appear at a model port. The namespace of model ports is global, each being associated with a ~Pipe-ID.
|
||||
|
||||
Model ports are represented by small non-copyable descriptor objects with distinct identity, which are owned and managed by the [[Fixture]]. Clients are bound to resolve a model port on each usage, as configuration changes within the model might cause ports to appear and decease. To stress this usage pattern, actually {{{ModelPort}}} instances are small copyable value objects (smart handles), which can be used to access data within an opaque registry. Each model port belongs to a specific Timeline and is aware of this association, as is the timeline, allowing to get the collection of all ports of a given timeline. Besides, within the Fixture each model port refers to a specific [[segmentation of the time axis|Segmentation]] (relevant for this special timeline actually). Thus, with the help of this segmentation, a model port can yield an ExitNode to pull frames for a given time.
|
||||
|
||||
</pre>
|
||||
</div>
|
||||
<div title="ModelPortRegistry" modifier="Ichthyostega" modified="201012112230" created="201012030314" tags="Model impl" changecount="3">
|
||||
<pre>Model ports are conceptual entities, denoting the points where output might possibly be produced &rarr; see [[definition|ModelPort]].
|
||||
But there is an actual representation, a collection of small descriptor objects managed by the Fixture and organised within the model port table datastructure. Because model ports are discovered during the build process, we need the ability to (re)build this table dynamically, finally swapping in the modified configuration with a transactional switch. Only the builder is allowed to perform such mutations, while for client code model ports are immutable.
|
||||
|
||||
!supported operations
|
||||
* get the model port by ~Pipe-ID
|
||||
* a collection of model ports per timeline
|
||||
* sub-grouping by media kind, possibly even by StreamType
|
||||
* possibility to enumerate model ports in distinct //order,// defined within the timeline
|
||||
* with the additional possibility to filter by media kind or suitable stream type.
|
||||
* a way to express the fact of //not having a model port.//
|
||||
|
||||
!!!mutating and rebuilding
|
||||
Model ports are added once and never changed. The corresponding timeline and pipe is known at setup time, but the overall number of model ports is determined only as a result of completing the build process. At that point, the newly built configuration is swapped in transactionally to become the current configuration.
|
||||
|
||||
!Implementation considerations
|
||||
The transactional switch creates a clear partitioning in the lifespan of the model port table. //Before// that point, entries are just added, but not accessed in any way. //After// that point, no further mutation occurs, but lookup is frequent and happens in a variety of different configurations and transient orderings.
|
||||
|
||||
This observation leads to the idea of using //model port references// as frontend to provide all kinds of access, searching and reordering. These encapsulate the actual access by silently assuming reference to "the" global current model port configuration. This way the actual model port descriptors could be bulk allocated in a similar manner as the processing nodes and wiring descriptors. Access to stale model ports could be detected by the port references, allowing also for a {{{bool}}} checkable "has no port" information.
|
||||
|
||||
A model port registry, maintained by the builder, is responsible for storing the discovered model ports within a model port table, which is then swapped in after completing the build process. The {{{builder::ModelPortRegistry}}} acts as management interface, while client code accesses just the {{{ModelPort}}} frontend. A link to the actual registry instance is hooked into that frontend when bringing up the builder subsystem.
|
||||
</pre>
|
||||
</div>
|
||||
<div title="ModelRootMO" modifier="Ichthyostega" modified="200912110245" created="200912080307" tags="def" changecount="5">
|
||||
|
|
@ -4611,6 +4679,44 @@ We need to detect attaching and detaching of
|
|||
* root &harr; [[Track]]
|
||||
</pre>
|
||||
</div>
|
||||
<div title="Segmentation" modifier="Ichthyostega" modified="201012122202" created="201012121901" tags="def spec Builder" changecount="24">
|
||||
<pre>//Segmentation of timeline// denotes a data structure and a step in the BuildProcess.
|
||||
When [[building the fixture|BuildFixture]], ~MObjects -- as handled by their Placements -- are grouped below each timeline using them; Placements are then to be resolved into [[explicit Placements|ExplicitPlacement]], resulting in a single well defined time interval for each object. This allows to cut this effective timeline into slices of constant wiring structure, which are represented through the ''Segmentation Datastructure'', a time axis with segments holding object placements and [[exit nodes|ExitNode]]. &nbsp;&rarr; see [[structure of the Fixture|Fixture]]
|
||||
* for each Timeline we get a Segmentation
|
||||
** which in turn is a list of non-overlapping segments
|
||||
*** each holding
|
||||
**** an ExplicitPlacement for each covered object
|
||||
**** an ExitNode for each ModelPort of the corresponding timeline
|
||||
|
||||
!Storage considerations
|
||||
;(1) build process
|
||||
:&rarr; a tree walk yields the placements per timeline, which then get //resolved//
|
||||
:&rarr; after //sorting,// the segmentation can be established, thereby copying placements spanning multiple segments
|
||||
:&rarr; only //after running the complete build process for each segment,// the list of model ports and exit nodes can be established
|
||||
;(2) commit stage
|
||||
: -- after the build process(es) are completed, the new fixture gets ''committed'', thus becoming the officially valid state to be rendered. As render processes might be going on in parallel, some kind of locking or barrier is required. It seems advisable to make the change into a single atomic hot-swap. Meaning we'd get a single access point to be protected. But there is another twist: We need to find out which render processes to cancel an restart, to pick up the changes introduced by this build process, which might include adding and deleting of timelines as a whole, and any changes to the segmentation grid. Because of the highly dynamic nature of the placements, on the other hand it isn't viable to expect the high-level model to provide this information. Thus we need to find out about a ''change coverage'' at this point. We might expand on that idea to //prune any new segments which aren't changed.// This way, only a write barrier would be necessary on switching the actually changed segments, and any render processes touching these would be //tainted.// Old allocations could be released after all tainted processes are known to be terminated.
|
||||
;(3) rendering use
|
||||
:Each play/render process employs a ''frame dispatch step'' to get the right exit node for pulling a given frame. From there on, the process proceeds into the [[processing nodes|ProcNodes]], interleaved with backend/scheduler actions due to splitting into individually scheduled jobs. The storage of these processing nodes and accompanying wiring descriptors is hooked up behind the individual segments, by sharing a common {{{AllocationCluster}}}. Yet the calculation of individual frames also depends on ''parameters'' and especially ''automation'' connected with objects in the high-level model. It is likely that there might be some sharing, as the intention was to allow ''live changes'' to automated values. <br/>{{red{WIP 12/2010}}} details need to be worked out. &rarr; [[parameter wiring concept|Wiring]]
|
||||
!!!observations
|
||||
* Storage and initialisation for explicit placements is an issue. We should strive at making that inline as much as possible.
|
||||
* the overall segmentation emerges from a sorting of time points, which are start points of explicit placements
|
||||
* after the segmentation has been built, the usage pattern changes entirely into a lookup of segment by time
|
||||
* the individual segments act as umbrella for a lot of further objects hooked up behind.
|
||||
* we need the ability to exchange or swap-in whole segments
|
||||
* each segment controls an AllocationCluster
|
||||
* we need to track processes for tainting
|
||||
* access happens per ModelPort
|
||||
|
||||
!!!conclusions
|
||||
The Fixture is mostly comprised of the Segementation datastructure, but some other facilities are involved too
|
||||
# at top level, we need somehow to organise access per groups of model ports, actually grouped by timeline
|
||||
# during the build process, there is a collection of placements; this can be discarded afterwards
|
||||
# the backbone of the segmentation is closely linked to an ordering by time. Initially it should support sorting, access by time interval search later on.
|
||||
# discarding a segment (or failing to do so) has an high impact on the whole application. We should employ a reliable mechanism for that.
|
||||
# the frame dispatch and the tracking of processes can be combined; data duplication is a virtue when it comes to parallel processes
|
||||
# the process of comparing and tainting is broken out into a separate data structure to be used just once
|
||||
</pre>
|
||||
</div>
|
||||
<div title="Sequence" modifier="Ichthyostega" modified="201010180156" created="201001252327" tags="def" changecount="17">
|
||||
<pre>A sequence is a collection of media objects, arranged onto a track tree. Sequences are the building blocks within the session. To be visible and editable, a session needs to be bound into a top-level [[Timeline]]. Alternatively, it may be used as a VirtualClip nested within another sequence.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue