diff --git a/doc/devel/draw/Builder.Fixture-1.svg b/doc/devel/draw/Builder.Fixture-1.svg new file mode 100644 index 000000000..c7bb4e9d2 --- /dev/null +++ b/doc/devel/draw/Builder.Fixture-1.svg @@ -0,0 +1,4091 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + Structure of the Fixture + + + Ichthyostega + + + Lumiera: how the Fixture data structure is organised + 2010 + + + + + + + + + + + + + + + + List of Model Ports + + + + + exitnodes + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Segmentation-1 + Segmtn-2 + Eplicitplacem + diff --git a/doc/devel/draw/Builder.SegmentationSteps-1.svg b/doc/devel/draw/Builder.SegmentationSteps-1.svg new file mode 100644 index 000000000..9694920cf --- /dev/null +++ b/doc/devel/draw/Builder.SegmentationSteps-1.svg @@ -0,0 +1,3333 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + Steps towards building a Segmentation + + + Ichthyostega + + + explanation of Builder structures: How the Segmentation of the Lumiera low-level-model (render nodes graph) is derived from the high-level-model + 2010 + + + + + + + + + + + + + + + + + + Binding + + + + + + + + + + + Sequence-α + + + + + + Timeline-1 + + + Fixture + + + + + + + + + + + + + + + + + + global Pipes + + + + + + + + + + + + + x + + + + + + + + + + + + + + Clip-A + + + + + + + Meta-Clip + + + + + + + + + + Sequence-β + Segmentation + + + + + + + Clip-B + + + + + + + + Binding + + + Timeline-2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Clip-A + + + + + + + Clip-B + + + + + + + + + + + + Clip-B + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Binding + + + + x + + + + x + + + + x + + + + x + + explicit Placement + exit node + ModelPort-1 + + + + + + + + x + + + ModelPort-2 + + + + + + x + + + + + + diff --git a/doc/devel/uml/fig129413.png b/doc/devel/uml/fig129413.png index df8722ad2..581c0bf46 100644 Binary files a/doc/devel/uml/fig129413.png and b/doc/devel/uml/fig129413.png differ diff --git a/src/include/logging.h b/src/include/logging.h index d2420b0f8..d5123f48f 100644 --- a/src/include/logging.h +++ b/src/include/logging.h @@ -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); diff --git a/src/lib/allocationcluster.hpp b/src/lib/allocationcluster.hpp index 304405d58..1b51e9d5c 100644 --- a/src/lib/allocationcluster.hpp +++ b/src/lib/allocationcluster.hpp @@ -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" diff --git a/src/lib/query.hpp b/src/lib/query.hpp index 283292b24..2e3186cc6 100644 --- a/src/lib/query.hpp +++ b/src/lib/query.hpp @@ -28,7 +28,7 @@ #include #include -#include +#include /////////////////////////////////////////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 { diff --git a/src/lib/scopedholdertransfer.hpp b/src/lib/scoped-holder-transfer.hpp similarity index 97% rename from src/lib/scopedholdertransfer.hpp rename to src/lib/scoped-holder-transfer.hpp index 3d600e61a..e7e78c945 100644 --- a/src/lib/scopedholdertransfer.hpp +++ b/src/lib/scoped-holder-transfer.hpp @@ -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 @@ -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 diff --git a/src/lib/scoped-holder.hpp b/src/lib/scoped-holder.hpp index 4e2c82627..83191970f 100644 --- a/src/lib/scoped-holder.hpp +++ b/src/lib/scoped-holder.hpp @@ -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 */ diff --git a/src/lib/scoped-ptrvect.hpp b/src/lib/scoped-ptrvect.hpp index d21e2333a..fa7515c6b 100644 --- a/src/lib/scoped-ptrvect.hpp +++ b/src/lib/scoped-ptrvect.hpp @@ -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) { diff --git a/src/lib/streamtype.hpp b/src/lib/streamtype.hpp index 6dc5747fc..cf45ad59c 100644 --- a/src/lib/streamtype.hpp +++ b/src/lib/streamtype.hpp @@ -37,6 +37,7 @@ #include "lib/symbol.hpp" #include "lib/query.hpp" +#include "proc/asset/entry-id.hpp" #include @@ -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 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? diff --git a/src/proc/Makefile.am b/src/proc/Makefile.am index d2a185dbf..d8e58f786 100644 --- a/src/proc/Makefile.am +++ b/src/proc/Makefile.am @@ -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 \ diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index def4a02ee..ef56fc632 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -103,11 +103,13 @@ namespace asset { template 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 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 - inline const PcAsset - pAsset (shared_ptr const& subPtr) - { - return static_pointer_cast (subPtr); - } - - - /** type trait for detecting a shared-ptr-to-asset */ - template - struct is_pAsset : boost::false_type {}; - - template - struct is_pAsset > - : boost::is_base_of {}; - - - /** 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 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 + inline const PcAsset + pAsset (shared_ptr const& subPtr) + { + return static_pointer_cast (subPtr); + } + + + /** type trait for detecting a shared-ptr-to-asset */ + template + struct is_pAsset : boost::false_type {}; + + template + struct is_pAsset > + : boost::is_base_of {}; + + + /** marker constant denoting a NIL asset */ + template + ID ID::INVALID = ID(0); + + + /** convenient for debugging */ + inline string str (PcAsset const& a) + { + if (a) + return string (*a.get()); + else + return "Asset(NULL)"; + } + + + + } // namespace asset diff --git a/src/proc/asset/entry-id.hpp b/src/proc/asset/entry-id.hpp index 3f736892e..b16739a02 100644 --- a/src/proc/asset/entry-id.hpp +++ b/src/proc/asset/entry-id.hpp @@ -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(); } }; diff --git a/src/proc/asset/pipe.cpp b/src/proc/asset/pipe.cpp index 2188a8138..8e823313a 100644 --- a/src/proc/asset/pipe.cpp +++ b/src/proc/asset/pipe.cpp @@ -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 diff --git a/src/proc/asset/pipe.hpp b/src/proc/asset/pipe.hpp index 922dec444..aed616264 100644 --- a/src/proc/asset/pipe.hpp +++ b/src/proc/asset/pipe.hpp @@ -26,6 +26,7 @@ #include "proc/asset/struct.hpp" #include "proc/asset/procpatt.hpp" +#include "lib/streamtype.hpp" #include @@ -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 ctors... // - inline ID::ID(HashVal id) : ID (id) {}; - inline ID::ID(Pipe const& pipe) : ID (pipe.getID()) {}; + inline ID::ID(HashVal id) : ID (id) {}; + inline ID::ID(Pipe const& pipe) : ID (pipe.getID()) {}; + inline ID::ID(PPipe const& pipe) : ID (pipe->getID()) {}; + inline + ID::operator PPipe() const + { + return Pipe::lookup(*this); + } + + inline StreamType::ID + ID::streamType() const + { + return Pipe::lookup(*this)->getStreamID(); + } diff --git a/src/proc/asset/struct-scheme.hpp b/src/proc/asset/struct-scheme.hpp index c8e0d09a4..dd6f6f512 100644 --- a/src/proc/asset/struct-scheme.hpp +++ b/src/proc/asset/struct-scheme.hpp @@ -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 + { + static Symbol namePrefix() { return "type"; } + static Symbol catFolder() { return "stream-types";} + static Symbol idSymbol() { return "stype"; } + }; template<> struct StructTraits { static Symbol namePrefix() { return "patt"; } diff --git a/src/proc/asset/struct.cpp b/src/proc/asset/struct.cpp index 9145c2ad8..70f893149 100644 --- a/src/proc/asset/struct.cpp +++ b/src/proc/asset/struct.cpp @@ -148,7 +148,7 @@ namespace asset { normaliseID (pipeID); normaliseID (streamID); static format descriptor("pipe(%s), stream(%s)."); - Pipe* pP = impl_->fabricate (Query (descriptor % pipeID % streamID)); + Pipe* pP = impl_->fabricate (Query (str(descriptor % pipeID % streamID))); return AssetManager::instance().wrap (*pP); } diff --git a/src/proc/control/stypemanager.cpp b/src/proc/control/stypemanager.cpp index 10131f130..4ba2fda19 100644 --- a/src/proc/control/stypemanager.cpp +++ b/src/proc/control/stypemanager.cpp @@ -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) { diff --git a/src/proc/control/stypemanager.hpp b/src/proc/control/stypemanager.hpp index 70003eef4..cd6a311df 100644 --- a/src/proc/control/stypemanager.hpp +++ b/src/proc/control/stypemanager.hpp @@ -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) ; diff --git a/src/proc/control/styperegistry.hpp b/src/proc/control/styperegistry.hpp index 5979582d2..63c33e841 100644 --- a/src/proc/control/styperegistry.hpp +++ b/src/proc/control/styperegistry.hpp @@ -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 diff --git a/src/proc/engine/renderengine.cpp b/src/proc/engine/renderengine.cpp index 25eb6257d..73af98a72 100644 --- a/src/proc/engine/renderengine.cpp +++ b/src/proc/engine/renderengine.cpp @@ -24,10 +24,10 @@ #include "proc/engine/renderengine.hpp" namespace engine { - - + + /** */ - - - + + + } // namespace engine diff --git a/src/proc/engine/renderengine.hpp b/src/proc/engine/renderengine.hpp index 1c361c739..b64530ed4 100644 --- a/src/proc/engine/renderengine.hpp +++ b/src/proc/engine/renderengine.hpp @@ -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 renderSegments; - + }; } // namespace engine diff --git a/src/proc/engine/rendergraph.cpp b/src/proc/engine/rendergraph.cpp index c2ab6e332..0900dde06 100644 --- a/src/proc/engine/rendergraph.cpp +++ b/src/proc/engine/rendergraph.cpp @@ -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 diff --git a/src/proc/engine/rendergraph.hpp b/src/proc/engine/rendergraph.hpp index 6fdb28217..c994737f5 100644 --- a/src/proc/engine/rendergraph.hpp +++ b/src/proc/engine/rendergraph.hpp @@ -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 diff --git a/src/proc/mobject/builder/buildertool.hpp b/src/proc/mobject/builder/buildertool.hpp index 93086ac4c..2d919a70a 100644 --- a/src/proc/mobject/builder/buildertool.hpp +++ b/src/proc/mobject/builder/buildertool.hpp @@ -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 + : public lumiera::visitor::Tool { 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 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 diff --git a/src/proc/mobject/builder/common.hpp b/src/proc/mobject/builder/common.hpp index e0503499b..ed3554c4c 100644 --- a/src/proc/mobject/builder/common.hpp +++ b/src/proc/mobject/builder/common.hpp @@ -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: -*/ diff --git a/src/proc/mobject/builder/fixture-change-detector.hpp b/src/proc/mobject/builder/fixture-change-detector.hpp new file mode 100644 index 000000000..7d25225f3 --- /dev/null +++ b/src/proc/mobject/builder/fixture-change-detector.hpp @@ -0,0 +1,81 @@ +/* + FIXTURE-CHANGE-DETECTOR.hpp - isolating changed segments and tainted processes + + Copyright (C) Lumiera.org + 2010, Hermann Vosseler + + 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 + +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 PID; +// typedef ID StID; + + public: + + }; + + + +}} // namespace mobject::builder +#endif diff --git a/src/proc/mobject/builder/model-port-registry.cpp b/src/proc/mobject/builder/model-port-registry.cpp new file mode 100644 index 000000000..f674fd912 --- /dev/null +++ b/src/proc/mobject/builder/model-port-registry.cpp @@ -0,0 +1,302 @@ +/* + ModelPortRegistry - creating and organising and accessing model ports + + Copyright (C) Lumiera.org + 2010, Hermann Vosseler + + 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 LockRegistry; + + + /** storage for the link to the global + Registry instance currently in charge */ + lib::OptionalRef 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 transaction currently being built + * 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 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 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 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 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, ID 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 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 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 + 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 + 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 diff --git a/src/proc/mobject/builder/model-port-registry.hpp b/src/proc/mobject/builder/model-port-registry.hpp new file mode 100644 index 000000000..be69cac8b --- /dev/null +++ b/src/proc/mobject/builder/model-port-registry.hpp @@ -0,0 +1,181 @@ +/* + MODEL-PORT-REGISTRY.hpp - creating and organising and accessing model ports + + Copyright (C) Lumiera.org + 2010, Hermann Vosseler + + 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 transactional switch. + ** + ** 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 + +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 PID; + typedef ID 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 theGlobalRegistry; + + typedef std::map 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 diff --git a/src/proc/mobject/builder/segmentationtool.cpp b/src/proc/mobject/builder/segmentation-tool.cpp similarity index 50% rename from src/proc/mobject/builder/segmentationtool.cpp rename to src/proc/mobject/builder/segmentation-tool.cpp index d0a18595d..b87109d68 100644 --- a/src/proc/mobject/builder/segmentationtool.cpp +++ b/src/proc/mobject/builder/segmentation-tool.cpp @@ -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 diff --git a/src/proc/mobject/builder/segmentation-tool.hpp b/src/proc/mobject/builder/segmentation-tool.hpp new file mode 100644 index 000000000..a40f4c8f9 --- /dev/null +++ b/src/proc/mobject/builder/segmentation-tool.hpp @@ -0,0 +1,78 @@ +/* + SEGMENTATION-TOOL.hpp - Tool for creating a partitioning of the current timeline + + Copyright (C) Lumiera.org + 2008, Hermann Vosseler + + 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 +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 + { + + 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 diff --git a/src/proc/mobject/builder/segmentation.cpp b/src/proc/mobject/builder/segmentation.cpp new file mode 100644 index 000000000..7231dfd0a --- /dev/null +++ b/src/proc/mobject/builder/segmentation.cpp @@ -0,0 +1,85 @@ +/* + Segmentation - partitioning the effective timeline + + Copyright (C) Lumiera.org + 2010, Hermann Vosseler + + 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::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 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 diff --git a/src/proc/mobject/builder/segmentation.hpp b/src/proc/mobject/builder/segmentation.hpp new file mode 100644 index 000000000..c3c73249c --- /dev/null +++ b/src/proc/mobject/builder/segmentation.hpp @@ -0,0 +1,87 @@ +/* + SEGMENTATION.hpp - partitioning the effective timeline + + Copyright (C) Lumiera.org + 2010, Hermann Vosseler + + 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 + +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 PID; +// typedef ID StID; + + public: + + }; + + + + + /** + * TODO type comment + */ + class Segmentation + { + + public: + }; + + + +}} // namespace mobject::builder +#endif diff --git a/src/proc/mobject/builder/segmentationtool.hpp b/src/proc/mobject/builder/segmentationtool.hpp deleted file mode 100644 index 2b88f572a..000000000 --- a/src/proc/mobject/builder/segmentationtool.hpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - SEGMENTATIONTOOL.hpp - Tool for creating a partitioning of the current timeline - - Copyright (C) Lumiera.org - 2008, Hermann Vosseler - - 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 -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 - { - - 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 diff --git a/src/proc/mobject/builder/toolfactory.hpp b/src/proc/mobject/builder/toolfactory.hpp index b283bea60..e17687ad4 100644 --- a/src/proc/mobject/builder/toolfactory.hpp +++ b/src/proc/mobject/builder/toolfactory.hpp @@ -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" diff --git a/src/proc/mobject/builderfacade.cpp b/src/proc/mobject/builderfacade.cpp index 175aa2b24..cbf73bbbd 100644 --- a/src/proc/mobject/builderfacade.cpp +++ b/src/proc/mobject/builderfacade.cpp @@ -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 diff --git a/src/proc/mobject/builderfacade.hpp b/src/proc/mobject/builderfacade.hpp index 98197ec13..31ab936ab 100644 --- a/src/proc/mobject/builderfacade.hpp +++ b/src/proc/mobject/builderfacade.hpp @@ -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 diff --git a/src/proc/mobject/model-port.hpp b/src/proc/mobject/model-port.hpp new file mode 100644 index 000000000..7b033218b --- /dev/null +++ b/src/proc/mobject/model-port.hpp @@ -0,0 +1,152 @@ +/* + MODEL-PORT.hpp - point to pull output data from the model + + Copyright (C) Lumiera.org + 2010, Hermann Vosseler + + 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 transactional switch 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 + { + ID id_; + + public: + ModelPort() ///< \em unconnected model port + : id_(ID::INVALID) + { } + + ModelPort (ID refID); ///< @note conversion from pipe-ID + + // using default copy operations + + + static bool exists (ID); + + ID pipe() const; + ID 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 diff --git a/src/proc/mobject/session/sess-manager-impl.cpp b/src/proc/mobject/session/sess-manager-impl.cpp index 51696928f..c3294d891 100644 --- a/src/proc/mobject/session/sess-manager-impl.cpp +++ b/src/proc/mobject/session/sess-manager-impl.cpp @@ -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..."); } diff --git a/tests/44builder.tests b/tests/44builder.tests index 6424f453f..c5d20d870 100644 --- a/tests/44builder.tests +++ b/tests/44builder.tests @@ -15,7 +15,22 @@ PLANNED "BuildSegment_test" BuildSegment_test <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("stream("+sID+")"))); } diff --git a/tests/components/proc/asset/identityofassetstest.cpp b/tests/components/proc/asset/identityofassetstest.cpp index 95df1e15c..5ab11bad3 100644 --- a/tests/components/proc/asset/identityofassetstest.cpp +++ b/tests/components/proc/asset/identityofassetstest.cpp @@ -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 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 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 diff --git a/tests/components/proc/control/handling-pattern-basics-test.cpp b/tests/components/proc/control/handling-pattern-basics-test.cpp index b18fc28c3..cc58464ae 100644 --- a/tests/components/proc/control/handling-pattern-basics-test.cpp +++ b/tests/components/proc/control/handling-pattern-basics-test.cpp @@ -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 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 o_Fun (command1::operate); function c_Fun (command1::capture); function 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 ArgType; const int ARGU (1 + rand() % 1000); Tuple tuple(ARGU); TypedArguments > 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 diff --git a/tests/components/proc/control/memento-tie-test.cpp b/tests/components/proc/control/memento-tie-test.cpp index 5ba7a7cdf..e4cd61a3c 100644 --- a/tests/components/proc/control/memento-tie-test.cpp +++ b/tests/components/proc/control/memento-tie-test.cpp @@ -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) // 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 diff --git a/tests/components/proc/mobject/builder/fixture-change-detector-test.cpp b/tests/components/proc/mobject/builder/fixture-change-detector-test.cpp new file mode 100644 index 000000000..3d885f350 --- /dev/null +++ b/tests/components/proc/mobject/builder/fixture-change-detector-test.cpp @@ -0,0 +1,113 @@ +/* + FixtureChangeDetector(Test) - detecting segmentation differences + + Copyright (C) Lumiera.org + 2010, Hermann Vosseler + + 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 PID; + typedef asset::ID 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 ("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 diff --git a/tests/components/proc/mobject/builder/model-port-registry-test.cpp b/tests/components/proc/mobject/builder/model-port-registry-test.cpp new file mode 100644 index 000000000..c37407b4b --- /dev/null +++ b/tests/components/proc/mobject/builder/model-port-registry-test.cpp @@ -0,0 +1,275 @@ +/* + ModelPortRegistry(Test) - verify handling of model ports + + Copyright (C) Lumiera.org + 2010, Hermann Vosseler + + 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 PID; + typedef asset::ID 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 ("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 diff --git a/tests/components/proc/mobject/builder/segmentation-datastructure-test.cpp b/tests/components/proc/mobject/builder/segmentation-datastructure-test.cpp new file mode 100644 index 000000000..ac6c66d30 --- /dev/null +++ b/tests/components/proc/mobject/builder/segmentation-datastructure-test.cpp @@ -0,0 +1,113 @@ +/* + SegmentationDatastructure(Test) - verify basic properties of the Segmentation + + Copyright (C) Lumiera.org + 2010, Hermann Vosseler + + 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 PID; + typedef asset::ID 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 ("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 diff --git a/tests/components/proc/mobject/mobject-ref-test.cpp b/tests/components/proc/mobject/mobject-ref-test.cpp index 0cd49fc59..b01c7391c 100644 --- a/tests/components/proc/mobject/mobject-ref-test.cpp +++ b/tests/components/proc/mobject/mobject-ref-test.cpp @@ -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 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 PMObj; typedef Placement PClip; typedef TestPlacement 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 ref1 (id1); PlacementRef 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 void checkBuildMObjectRef (REF& refObj, void* placementAdr) { MORef 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()); CHECK ( rMO.isCompatible()); CHECK (!rMO.isCompatible()); Time start = rMO.getStartTime(); - + // re-link to the Placement (note we get the Clip API!) Placement & 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 pRef1 (p1); PlacementRef pRef2 (p2); - + MORef rM; MORef 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 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 rClip; MORef 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 diff --git a/tests/components/proc/mobject/output-mapping-test.cpp b/tests/components/proc/mobject/output-mapping-test.cpp index db6f36ee1..18dd9eb60 100644 --- a/tests/components/proc/mobject/output-mapping-test.cpp +++ b/tests/components/proc/mobject/output-mapping-test.cpp @@ -76,7 +76,7 @@ namespace test { { PPipe srcP = Pipe::lookup (sourcePipeID); format queryPattern ("id(master_%1%), stream(%1%), ord(%2%)"); - return Query (queryPattern % srcP->getStreamID() % seqNr); + return Query (str(queryPattern % srcP->getStreamID().getSym() % seqNr)); } }; diff --git a/tests/components/proc/mobject/placement-ref-test.cpp b/tests/components/proc/mobject/placement-ref-test.cpp index 50dcd2411..b8c873c21 100644 --- a/tests/components/proc/mobject/placement-ref-test.cpp +++ b/tests/components/proc/mobject/placement-ref-test.cpp @@ -44,10 +44,10 @@ using std::endl; namespace mobject { namespace session { namespace test { - + using namespace mobject::test; typedef TestPlacement 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 id2 = p2.recastID(); CHECK (id2); CHECK (id2 != p1.getID()); - + // create placement refs PlacementRef ref1 (p1); PlacementRef ref2 (id2); - + PlacementRef 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 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 diff --git a/tests/components/proc/mobject/session/defsmanagerimpltest.cpp b/tests/components/proc/mobject/session/defsmanagerimpltest.cpp index a520f3350..ba16d24d8 100644 --- a/tests/components/proc/mobject/session/defsmanagerimpltest.cpp +++ b/tests/components/proc/mobject/session/defsmanagerimpltest.cpp @@ -31,6 +31,7 @@ #include "common/configrules.hpp" #include "proc/assetmanager.hpp" #include "proc/mobject/session.hpp" +#include "lib/streamtype.hpp" #include @@ -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 (""))); // unrestricted default +lumiera::query::setFakeBypass(""); /////////////////////////////////////////////////TODO mock resolution + CHECK (Session::current->defaults.define (pipe1, Query (""))); // 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 ("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 ("stream("+sID+")"))); // can't be registered with this query, due to failure caused by wrong stream-ID } diff --git a/tests/components/proc/mobject/session/defsmanagertest.cpp b/tests/components/proc/mobject/session/defsmanagertest.cpp index 9372cec8d..8c75bcaf5 100644 --- a/tests/components/proc/mobject/session/defsmanagertest.cpp +++ b/tests/components/proc/mobject/session/defsmanagertest.cpp @@ -32,6 +32,7 @@ #include "proc/asset/pipe.hpp" #include "proc/assetmanager.hpp" #include "proc/mobject/session.hpp" +#include "lib/streamtype.hpp" #include @@ -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 } diff --git a/tests/components/proc/mobject/session/placement-index-test.cpp b/tests/components/proc/mobject/session/placement-index-test.cpp index 6873527a2..4ad4d88d5 100644 --- a/tests/components/proc/mobject/session/placement-index-test.cpp +++ b/tests/components/proc/mobject/session/placement-index-test.cpp @@ -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 PClip; PClip anotherTestClip = TestClip::create(); - + typedef PlacementMO::Id 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 diff --git a/tests/components/proc/mobject/session/query-focus-test.cpp b/tests/components/proc/mobject/session/query-focus-test.cpp index f66d89dd2..2ce9d92d2 100644 --- a/tests/components/proc/mobject/session/query-focus-test.cpp +++ b/tests/components/proc/mobject/session/query-focus-test.cpp @@ -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) diff --git a/tests/lib/Makefile.am b/tests/lib/Makefile.am index f8661006b..f6930f20b 100644 --- a/tests/lib/Makefile.am +++ b/tests/lib/Makefile.am @@ -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 diff --git a/tests/lib/custom-shared-ptr-test.cpp b/tests/lib/custom-shared-ptr-test.cpp index 646086be8..adb7c6f35 100644 --- a/tests/lib/custom-shared-ptr-test.cpp +++ b/tests/lib/custom-shared-ptr-test.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 { 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 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 au (new X(22)); CHECK (au.get()); - + P pX (au); CHECK (!au.get()); CHECK (pX); CHECK (1 == pX.use_count()); CHECK (22 == pX->x_); - + weak_ptr wX (pX); CHECK (wX.lock()); CHECK (1 == pX.use_count()); - + shared_ptr sp1 (wX); shared_ptr sp2 (pX); shared_ptr sp3; sp3 = pX; - + CHECK (22 == sp3->x_); CHECK (4 == pX.use_count()); CHECK (*pX == *sp1); CHECK (*sp1 == *sp2); CHECK (*sp2 == *sp3); - + P pX2; pX2.swap(pX); CHECK (!pX); CHECK (0 == pX.use_count()); CHECK (4 == pX2.use_count()); - + P > 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 > pLo;// Base: shared_ptr (rather nonsense, but well...) P pLoL; // Base: std::string P pLoLoL; // Base: shared_ptr - + CHECK (INSTANCEOF (shared_ptr, &pX)); - + CHECK ( INSTANCEOF (shared_ptr, &pX1)); -// CHECK (!INSTANCEOF (shared_ptr, &pX1)); // doesn't compile (no RTTI) -- that's correct -// CHECK (!INSTANCEOF (P, &pX1)); // similar, type mismatch detected by compiler - +// CHECK (!INSTANCEOF (shared_ptr, &pX1)); // doesn't compile (no RTTI) -- that's correct +// CHECK (!INSTANCEOF (P, &pX1)); // similar, type mismatch detected by compiler + CHECK ( INSTANCEOF (shared_ptr, &pX2)); // CHECK (!INSTANCEOF (shared_ptr, &pX2)); CHECK ( INSTANCEOF (P, &pX2)); - + CHECK ( INSTANCEOF (shared_ptr, &pX3)); // CHECK (!INSTANCEOF (shared_ptr, &pX3)); // CHECK (!INSTANCEOF (P, &pX3)); - + CHECK ( INSTANCEOF (shared_ptr, &pLo)); // CHECK (!INSTANCEOF (shared_ptr, &pLo)); // CHECK (!INSTANCEOF (P, &pLo)); - + // CHECK (!INSTANCEOF (shared_ptr, &pLoL)); // CHECK (!INSTANCEOF (shared_ptr, &pLoL)); // CHECK (!INSTANCEOF (P, &pLoL)); CHECK ( INSTANCEOF (string, &pLoL)); - + CHECK ( INSTANCEOF (shared_ptr, &pLoLoL)); // CHECK (!INSTANCEOF (string, &pLoLoL)); // CHECK (!INSTANCEOF (shared_ptr, &pLoLoL)); - + pX = pX1; // OK: pointee subtype... pX = pX2; // invokes shared_ptr::operator= (shared_ptr 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 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 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 PX; typedef P 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 diff --git a/tests/lib/item-wrapper-test.cpp b/tests/lib/item-wrapper-test.cpp index 746d910bc..0f8c108f7 100644 --- a/tests/lib/item-wrapper-test.cpp +++ b/tests/lib/item-wrapper-test.cpp @@ -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& vec, size_t idx) { return vec[idx]; } - + function pickElement_ofVector (vector& 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 (l1, l2); verifyWrapper (l1, l2); verifyWrapper (&l1, &l2); verifyWrapper ((0), &l2); verifyWrapper (&l1, (0)); verifyWrapper (l1, l2); - + verifyWrapper (s1, s2); verifyWrapper (s1, s2); verifyWrapper (&s1, &s2); - + verifyWrapper (cp, "Lumiera"); - - + + verifySaneInstanceHandling(); verifyWrappedRef (); - + verifyFunctionResult (); verifyFunctionRefResult (); } - - + + template void verifyWrapper (X val, X otherVal) { const ItemWrapper wrap(val); CHECK (wrap); - + cout << "ItemWrapper: " << showSizeof(wrap) << endl; - + ItemWrapper copy1 (wrap); ItemWrapper copy2; ItemWrapper 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 (t1, t2); verifyWrapper (t1, t2); verifyWrapper (&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 refWrap; CHECK (!refWrap); - + refWrap = x; CHECK (refWrap); CHECK (5 == *refWrap); CHECK (x == *refWrap); - + *refWrap += 5; CHECK (x == 10); - + ItemWrapper 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 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 testVec; for (uint i=0; i<10; ++i) testVec.push_back(i); - + FunctionResult 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 diff --git a/tests/lib/itertools-test.cpp b/tests/lib/itertools-test.cpp index 945a33de7..5ebc7cd77 100644 --- a/tests/lib/itertools-test.cpp +++ b/tests/lib/itertools-test.cpp @@ -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 data_; - + TestSource(uint num) { while (num) data_.push_back(num--); } - + typedef vector::iterator sourceIter; typedef RangeIter 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 (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 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 all (ii, takeAll); FilterIter 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::iterator SrcIter; typedef RangeIter SeqIter; typedef FilterIter FilteredSeq; - + SeqIter completeSequence (numberz.begin(), numberz.end()); FilteredSeq filtered = filterRepetitions (completeSequence); - + uint num=0; for (; num idi (ii, idFunc); TransformIter 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 @@ -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 diff --git a/tests/lib/meta/function-composition-test.cpp b/tests/lib/meta/function-composition-test.cpp index 050c43053..cd0569223 100644 --- a/tests/lib/meta/function-composition-test.cpp +++ b/tests/lib/meta/function-composition-test.cpp @@ -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 - Num - fun11 ( Num val1 - ) - { - return val1; - } - - template - Num - fun12 ( Num val1 - , Num val2 - ) - { - val1.o_ += val2.o_; - return val1; - } - - template - Num - fun13 ( Num val1 - , Num val2 - , Num val3 - ) - { - val1.o_ += val2.o_ + val3.o_; - return val1; - } - - template - Num - fun14 ( Num val1 - , Num val2 - , Num val3 - , Num val4 - ) - { - val1.o_ += val2.o_ + val3.o_ + val4.o_; - return val1; - } - - template - Num - fun15 ( Num val1 - , Num val2 - , Num val3 - , Num val4 - , Num val5 - ) - { - val1.o_ += val2.o_ + val3.o_ + val4.o_ + val5.o_; - return val1; - } - - - /** "Function-2" can be chained behind fun1 */ - template - 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 + Num + fun11 ( Num val1 + ) + { + return val1; + } + + template + Num + fun12 ( Num val1 + , Num val2 + ) + { + val1.o_ += val2.o_; + return val1; + } + + template + Num + fun13 ( Num val1 + , Num val2 + , Num val3 + ) + { + val1.o_ += val2.o_ + val3.o_; + return val1; + } + + template + Num + fun14 ( Num val1 + , Num val2 + , Num val3 + , Num val4 + ) + { + val1.o_ += val2.o_ + val3.o_ + val4.o_; + return val1; + } + + template + Num + fun15 ( Num val1 + , Num val2 + , Num val3 + , Num val4 + , Num val5 + ) + { + val1.o_ += val2.o_ + val3.o_ + val4.o_ + val5.o_; + return val1; + } + + + /** "Function-2" can be chained behind fun1 */ + template + 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 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, 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 > ArgTypes; // now package just the argument(s) to be applied into a tuple Tuple args_to_bind (Num<1>(18)); - + fun_23 = PApply::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 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<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<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 fun_54 = PApply::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 f5_fun = f5; // also works with function objects... function 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 > argT(55); - + function f_bound_1 = BindToArgument::reduced (f, argT); function f_bound_2 = BindToArgument::reduced (f, argT); function f_bound_3 = BindToArgument::reduced (f, argT); function f_bound_4 = BindToArgument::reduced (f, argT); function f_bound_5 = BindToArgument::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 f_bound_X = BindToArgument::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 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 diff --git a/tests/lib/meta/generator-test.cpp b/tests/lib/meta/generator-test.cpp index 61580eaea..a43a76183 100644 --- a/tests/lib/meta/generator-test.cpp +++ b/tests/lib/meta/generator-test.cpp @@ -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 - struct Block + + /** template for generating lots of different test types */ + template + struct Block + { + static string name; + string talk() { return "__"+name+"__"; } + }; + + + boost::format fmt ("Block<%2i>"); + + template + string Block::name = str (fmt % I); + + + + /** Use this building block for assembling an abstract interface */ + template + class TakeIt + { + public: + virtual void eat (X& x) = 0; + virtual ~TakeIt() { } + }; + + /** Use this building block for chaining corresponding implementation classes. */ + template + 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 TheInterface; + + + struct BaseImpl : public TheInterface + { + void eat() { cout << "gulp!\n"; } + }; + + typedef InstantiateChained 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 + */ + class TypeListGenerator_test : public Test + { + virtual void run(Arg) { - static string name; - string talk() { return "__"+name+"__"; } - }; - - - boost::format fmt ("Block<%2i>"); - - template - string Block::name = str (fmt % I); - - - - /** Use this building block for assembling an abstract interface */ - template - class TakeIt - { - public: - virtual void eat (X& x) = 0; - virtual ~TakeIt() { } - }; - - /** Use this building block for chaining corresponding implementation classes. */ - template - 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 TheInterface; - - - struct BaseImpl : public TheInterface - { - void eat() { cout << "gulp!\n"; } - }; - - typedef InstantiateChained 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
  • - *
- */ - 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 >& 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 >& 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 diff --git a/tests/lib/meta/type-tuple-test.cpp b/tests/lib/meta/type-tuple-test.cpp index f5cf2d5f9..e02ed392c 100644 --- a/tests/lib/meta/type-tuple-test.cpp +++ b/tests/lib/meta/type-tuple-test.cpp @@ -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 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 T_L1; // ListType based tuple type typedef Tuple::TupleType T1; // corresponding plain tuple type typedef Tuple::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 > 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 > NulT; // plain-flat empty Tuple typedef Tuple NulL; // list-style empty Tuple - + CHECK ( is_Tuple::value); CHECK ( is_TuplePlain::value); CHECK (! is_TupleListType::value); CHECK (! is_NullTuple::value); - + CHECK ( is_Tuple::value); CHECK (! is_TuplePlain::value); CHECK ( is_TupleListType::value); CHECK (! is_NullTuple::value); - + CHECK ( is_Tuple::value); CHECK ( is_TuplePlain::value); CHECK (! is_TupleListType::value); CHECK ( is_NullTuple::value); - + CHECK ( is_Tuple::value); CHECK (! is_TuplePlain::value); CHECK ( is_TupleListType::value); CHECK ( is_NullTuple::value); - + CHECK (! is_Tuple::value); CHECK (! is_TuplePlain::value); CHECK (!is_TupleListType::value); CHECK (! is_NullTuple::value); - + CHECK (! is_Tuple::value); CHECK (! is_TuplePlain::value); CHECK (!is_TupleListType::value); CHECK (! is_NullTuple::value); - + } - - + + void check_sub_tuple_types() { cout << "\t:\n\t: ---Sub-Tuple-Types----\n"; - + typedef Append::List L2; - + typedef Tuple T_L2; // list-style Tuple typedef Types Head; typedef T_L2::TailType Tail; DISPLAY (T_L2); DISPLAY (Head); DISPLAY (Tail); - + typedef T_L2::TupleType T2; // plain-flat Tuple typedef Types Head2; typedef T2::TailType Tail2; DISPLAY (T2); DISPLAY (Head2); DISPLAY (Tail2); - + typedef Tuple > NulT; // plain-flat empty Tuple typedef Tuple 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::List L3; typedef Tuple::Type Ty3; typedef Tuple T3; - - typedef Shifted::Type Ty_0; DISPLAY (Ty_0); - typedef Shifted::Type Ty_1; DISPLAY (Ty_1); - typedef Shifted::Type Ty_2; DISPLAY (Ty_2); - typedef Shifted::Type Ty_3; DISPLAY (Ty_3); - typedef Shifted::Type Ty_4; DISPLAY (Ty_4); - + + typedef Shifted::Type Ty_0; DISPLAY (Ty_0); + typedef Shifted::Type Ty_1; DISPLAY (Ty_1); + typedef Shifted::Type Ty_2; DISPLAY (Ty_2); + typedef Shifted::Type Ty_3; DISPLAY (Ty_3); + typedef Shifted::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 tup1 ; Tuple tup11 (Num<1>(11) ); Tuple tup12 (Num<1>(), Num<3>(33) ); @@ -283,22 +283,22 @@ namespace test { DUMPVAL (tup11); DUMPVAL (tup12); DUMPVAL (tup13); - + typedef Tuple > > 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 > T0T; typedef Tuple 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::List TL; typedef Tuple::Type TT; typedef Tuple T1357L; typedef Tuple T1357T; DISPLAY (T1357L); DISPLAY (T1357T); - + typedef Tuple T135L; typedef Tuple,Num<7> > > T57T; typedef Tuple,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::create(sub135); DUMPVAL (b_135); @@ -346,113 +346,113 @@ namespace test { DUMPVAL (b_135); b_135 = tuple::BuildTuple::create(sub135); DUMPVAL (b_135); // all variations of type specification lead to the same result - + DUMPVAL (sub57); T1357T b_57 = tuple::BuildTuple::create(sub57); DUMPVAL (b_57); - + DUMPVAL (sub35); T1357T b_35 = tuple::BuildTuple::create(sub35); DUMPVAL (b_35); - + b_35 = tuple::BuildTuple::create(sub35); DUMPVAL (b_35); // note: wrong start position, argument tuple ignored completely b_35 = tuple::BuildTuple::create(sub35); DUMPVAL (b_35); - + // use an argument tuple beyond the last argument of the target tuple... typedef Tuple,Num<8> > > T78T; T78T sub78 (Num<7>(77),Num<8>(88)); DUMPVAL (sub78); T1357T b_78 = tuple::BuildTuple::create(sub78); DUMPVAL (b_78); // note: superfluous arguments ignored - + typedef Tuple > NulT; NulT nult; T1357T b_nul = tuple::BuildTuple::create(nult); DUMPVAL (b_nul); b_nul = tuple::BuildTuple::create(nult); DUMPVAL (b_nul); - + NulT b_nul2 = tuple::BuildTuple::create(sub78); DUMPVAL (b_nul2) b_nul2 = tuple::BuildTuple::create(sub78); DUMPVAL (b_nul2) } - - + + void check_tuple_copy() { cout << "\t:\n\t: ---copy-operations---\n"; - + Tuple tup1 (Num<1>(11), Num<3>(33), Num<5>() ); - + Tuple tup11 (tup1); tup11.getAt<2>().o_ = 44; DUMPVAL (tup1); DUMPVAL (tup11); - + tup1 = tup11; DUMPVAL (tup1); - + Tuple tupL = tup11.getShifted<0>(); Tuple 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::List T2424; typedef Tuple TupX; TupX tupX; DISPLAY (TupX); DUMPVAL (tupX); - + Tuple 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::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 diff --git a/tests/lib/scoped-holder-test.cpp b/tests/lib/scoped-holder-test.cpp index 382aa477b..ff913c60e 100644 --- a/tests/lib/scoped-holder-test.cpp +++ b/tests/lib/scoped-holder-test.cpp @@ -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 - diff --git a/tests/lib/scopedholdertransfertest.cpp b/tests/lib/scoped-holder-transfer-test.cpp similarity index 97% rename from tests/lib/scopedholdertransfertest.cpp rename to tests/lib/scoped-holder-transfer-test.cpp index 7aca8165a..eafefb390 100644 --- a/tests/lib/scopedholdertransfertest.cpp +++ b/tests/lib/scoped-holder-transfer-test.cpp @@ -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 @@ -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) } }; diff --git a/tests/lib/singleton-subclass-test.cpp b/tests/lib/singleton-subclass-test.cpp index f46f24e7f..113385cfd 100644 --- a/tests/lib/singleton-subclass-test.cpp +++ b/tests/lib/singleton-subclass-test.cpp @@ -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; friend class singleton::HeapCreate; }; - + 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(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 typeinfo; - + // define an instance of the Singleton factory, // Specialised to create the concrete Type passed in SingletonSubclassFactory 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 more_special_type; - + VERIFY_ERROR (ASSERTION, SingletonSubclassFactory 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 yet_another_type; // SingletonSubclassFactory instance (yet_another_type); } }; - - - + + + /** Register this test class... */ LAUNCHER (SingletonSubclass_test, "unit common"); - - - + + + }} // namespace lib::test diff --git a/tests/lib/symbol-hashtable-test.cpp b/tests/lib/symbol-hashtable-test.cpp index 92e7a38a2..501aa8579 100644 --- a/tests/lib/symbol-hashtable-test.cpp +++ b/tests/lib/symbol-hashtable-test.cpp @@ -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 > 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 - diff --git a/tests/lib/symbol-test.cpp b/tests/lib/symbol-test.cpp index cedf77ca4..08dd79197 100644 --- a/tests/lib/symbol-test.cpp +++ b/tests/lib/symbol-test.cpp @@ -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 - diff --git a/tests/lib/sync-classlock-test.cpp b/tests/lib/sync-classlock-test.cpp index 24430d7a4..59377ae16 100644 --- a/tests/lib/sync-classlock-test.cpp +++ b/tests/lib/sync-classlock-test.cpp @@ -85,7 +85,7 @@ namespace test { } ClassLock get_class_lock; - CHECK ( 1 == get_class_lock.use_count()); // embedded PerClassMonitor got created exactly once + CHECK ( 1 == get_class_lock.use_count()); // embedded PerClassMonitor got created exactly once } // and stays alive until static dtors are called.... }; diff --git a/tests/lib/sync-timedwait-test.cpp b/tests/lib/sync-timedwait-test.cpp index cb1565d37..91d8918cc 100644 --- a/tests/lib/sync-timedwait-test.cpp +++ b/tests/lib/sync-timedwait-test.cpp @@ -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 { - + 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 diff --git a/tests/lib/testdummy.hpp b/tests/lib/testdummy.hpp index afa810f79..605a92fc7 100644 --- a/tests/lib/testdummy.hpp +++ b/tests/lib/testdummy.hpp @@ -23,6 +23,7 @@ #include +#include 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() diff --git a/tests/lib/vectortransfertest.cpp b/tests/lib/vector-transfer-test.cpp similarity index 99% rename from tests/lib/vectortransfertest.cpp rename to tests/lib/vector-transfer-test.cpp index 59a35b0c2..3d5a3b771 100644 --- a/tests/lib/vectortransfertest.cpp +++ b/tests/lib/vector-transfer-test.cpp @@ -24,7 +24,7 @@ #include "lib/test/run.hpp" -#include "lib/scopedholdertransfer.hpp" +#include "lib/scoped-holder-transfer.hpp" #include "testdummy.hpp" #include diff --git a/uml/lumiera/128901 b/uml/lumiera/128901 index 5a7cdb03b..300f66d4c 100644 --- a/uml/lumiera/128901 +++ b/uml/lumiera/128901 @@ -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 "" - on pin_ref 128133 // inFixture + on pin_ref 128133 // inContent end flow 131717 "" - 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 "" + on pin_ref 128133 // inContent + end + end end classdiagram 129285 "Builder Tool (Visitor)" diff --git a/uml/lumiera/129413.diagram b/uml/lumiera/129413.diagram index c8fd505f1..655fa1d29 100644 --- a/uml/lumiera/129413.diagram +++ b/uml/lumiera/129413.diagram @@ -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 // @@ -92,8 +88,8 @@ end flowcanvas 133765 flow_ref 130949 // 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 // 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 // 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 // - - 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 // from ref 134405 z 2006 to ref 136581 @@ -131,9 +122,16 @@ flowcanvas 136709 flow_ref 131845 // end flowcanvas 136837 flow_ref 131973 // - 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 // + 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 diff --git a/uml/lumiera/5.session b/uml/lumiera/5.session index 87b65616c..5e7b8f6a0 100644 --- a/uml/lumiera/5.session +++ b/uml/lumiera/5.session @@ -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 // 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 diff --git a/uml/lumiera/lumiera.prj b/uml/lumiera/lumiera.prj index 35bcc31a2..ae9d839be 100644 --- a/uml/lumiera/lumiera.prj +++ b/uml/lumiera/lumiera.prj @@ -1,6 +1,6 @@ format 58 "lumiera" - revision 64 + revision 65 modified_by 5 "hiv" cpp_root_dir "../../src/" diff --git a/wiki/draw/Fixture1.png b/wiki/draw/Fixture1.png new file mode 100644 index 000000000..d59421731 Binary files /dev/null and b/wiki/draw/Fixture1.png differ diff --git a/wiki/draw/SegmentationSteps1.png b/wiki/draw/SegmentationSteps1.png new file mode 100644 index 000000000..98933cfd0 Binary files /dev/null and b/wiki/draw/SegmentationSteps1.png differ diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 2ab329a32..5837913f4 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -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.// +
+
//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]]
+
+
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
 
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).
 
-
-
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
+
+
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.
 
@@ -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
-
-
a specially configured sequence list
+
+
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.//
 
@@ -2784,12 +2823,41 @@ These are used as token for dealing with other objects and have no identity of t
-
-
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.
+
+
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.
+
+
+
+
+
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.
 
@@ -4611,6 +4679,44 @@ We need to detect attaching and detaching of * root &harr; [[Track]]
+
+
//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
+
+
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.