From 86162ad314d291f7b190fa17a64b2dc584255067 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 19 May 2008 08:38:13 +0200 Subject: [PATCH] moved new code into library modules and adapted BuilderTool to use it. BuilderTool_test now passed. --- src/common/accesscasted.hpp | 168 +++++ src/common/typelistutil.hpp | 93 ++- src/common/variant.hpp | 276 +++++++ src/common/wrapperptr.hpp | 63 ++ .../builder/applicablebuildertargettypes.hpp | 70 ++ src/proc/mobject/builder/buildertool.hpp | 134 +++- src/proc/mobject/builder/nodecreatertool.cpp | 7 +- src/proc/mobject/builder/nodecreatertool.hpp | 23 +- src/proc/mobject/builder/segmentationtool.cpp | 6 +- src/proc/mobject/builder/segmentationtool.hpp | 22 +- src/proc/mobject/explicitplacement.hpp | 18 +- src/proc/mobject/mobject.hpp | 5 +- src/proc/mobject/placement.cpp | 32 +- src/proc/mobject/placement.hpp | 21 +- src/proc/mobject/session/clip.hpp | 4 +- src/proc/mobject/session/effect.hpp | 2 +- src/proc/mobject/session/meta.hpp | 2 +- src/proc/mobject/session/track.hpp | 2 +- tests/54builder.tests | 8 +- .../proc/mobject/builder/buildertooltest.cpp | 706 +++--------------- 20 files changed, 953 insertions(+), 709 deletions(-) create mode 100644 src/common/accesscasted.hpp create mode 100644 src/common/variant.hpp create mode 100644 src/common/wrapperptr.hpp create mode 100644 src/proc/mobject/builder/applicablebuildertargettypes.hpp diff --git a/src/common/accesscasted.hpp b/src/common/accesscasted.hpp new file mode 100644 index 000000000..58f2e2dbc --- /dev/null +++ b/src/common/accesscasted.hpp @@ -0,0 +1,168 @@ +/* + ACCESSCASTED.hpp - util template to access a value using conversion or cast as appropriate + + 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. + +*/ + + +/** @file accesscasted.hpp + ** Helper for accessing a value employing either conversion or downcast + ** depending on the relation of the source type (type of the original value) + ** and the target type (type we need within the usage context). + ** When instantiating AcessCasted, we get a template static function + ** \c AcessCasted::access(SRC& elm), but the actual implementation + ** is choosed using boost::type_traits. If no viable implementatino can be + ** selected, \c EmptyVal::create() is invoked instead, which by default + ** creates a NULL value or similar by using the no-argument ctor of the + ** type TAR. Alternatively, you may define an specialisation fo EmptyVal, + ** e.g. throwing an exception instead of creating a NULL value. + ** + ** @see lumiera::WrapperPtr usage example to access a variant record + ** + */ + + +#ifndef UTIL_ACCESSCASTED_H +#define UTIL_ACCESSCASTED_H + +#include +#include +#include +#include +#include +#include + + + +namespace util { + using boost::remove_pointer; + using boost::remove_reference; + using boost::is_convertible; + using boost::is_polymorphic; + using boost::is_base_of; + using boost::enable_if; + + + template + struct can_cast : boost::false_type {}; + + template + struct can_cast { enum { value = is_base_of::value };}; + + template + struct can_cast { enum { value = is_base_of::value };}; + + template + struct can_cast { enum { value = is_base_of::value };}; + + + template + struct has_RTTI + { + typedef typename remove_pointer< + typename remove_reference::type>::type TPlain; + + enum { value = is_polymorphic::value }; + }; + + template + struct use_dynamic_downcast + { + enum { value = can_cast::value + && has_RTTI::value + && has_RTTI::value + }; + }; + + template + struct use_static_downcast + { + enum { value = can_cast::value + && ( !has_RTTI::value + || !has_RTTI::value + ) + }; + }; + + template + struct use_conversion + { + enum { value = is_convertible::value + && !( use_static_downcast::value + ||use_dynamic_downcast::value + ) + }; + }; + + + + template + struct EmptyVal + { + static X create() { return X(); } + }; + template + struct EmptyVal + { + static X*& create() { static X* nullP(0); return nullP; } + }; + + + + + + template + struct NullAccessor + { + typedef RET Ret; + + static RET access (...) { return ifEmpty(); } + static RET ifEmpty () { return EmptyVal::create(); } + }; + + template + struct AccessCasted : NullAccessor + { + using NullAccessor::access; + + template + static typename enable_if< use_dynamic_downcast, TAR>::type + access (ELM& elem) + { + return dynamic_cast (elem); + } + + template + static typename enable_if< use_static_downcast, TAR>::type + access (ELM& elem) + { + return static_cast (elem); + } + + template + static typename enable_if< use_conversion, TAR>::type + access (ELM& elem) + { + return elem; + } + }; + + +} // namespace util +#endif diff --git a/src/common/typelistutil.hpp b/src/common/typelistutil.hpp index f7a716024..3fb6a531e 100644 --- a/src/common/typelistutil.hpp +++ b/src/common/typelistutil.hpp @@ -40,7 +40,10 @@ This code is heavily inspired by /** @file typelistutil.hpp ** Helpers for working with lumiera::typelist::Types (i.e. lists-of-types). - ** + ** The main purpose is to build interfaces and polymorphic implementations + ** (using virtual functions) based on templated Types or Collections of types, + ** which is not possible without Template Metaprogrmming. + ** ** @see lumiera::query::ConfigRules usage example ** @see typelist.hpp ** @@ -141,6 +144,94 @@ namespace lumiera }; + + /** + * A Variation of InstantiateChained providing an incremented + * Index value template parameter. This index can e.g. be used + * to store pointers in a dispatcher table in the Base class. + * Similar to InstantiateChained, this template builds a linear + * chain of inheritance. The user-provided template, which is + * to be instantiated for all types in the Typelist, now has to + * accept an additional third parameter (uint i). + */ + template + < class TYPES // List of Types + , template class _X_ // your-template-goes-here + , class BASE = NullType // Base class at end of chain + , uint i = 0 // incremented on each instantiaton + > + class InstantiateWithIndex; + + + template< template class _X_ + , class BASE + , uint i + > + class InstantiateWithIndex + : public BASE + { + public: + typedef BASE Unit; + typedef NullType Next; + enum{ COUNT = i }; + }; + + + template + < class TY, typename TYPES + , template class _X_ + , class BASE + , uint i + > + class InstantiateWithIndex, _X_, BASE, i> + : public _X_< TY + , InstantiateWithIndex + , i + > + { + public: + typedef InstantiateWithIndex Next; + typedef _X_ Unit; + enum{ COUNT = Next::COUNT }; + }; + + + /** + * Metafunction counting the number of Types in the collection + */ + template + struct count; + template<> + struct count + { + enum{ value = 0 }; + }; + template + struct count > + { + enum{ value = 1 + count::value }; + }; + + /** + * Metafunction " max( sizeof(T) ) for T in TYPES " + */ + template + struct maxSize; + template<> + struct maxSize + { + enum{ value = 0 }; + }; + template + struct maxSize > + { + enum{ thisval = sizeof(TY) + , nextval = maxSize::value + , value = nextval > thisval? nextval:thisval + }; + }; + + } // namespace typelist } // namespace lumiera diff --git a/src/common/variant.hpp b/src/common/variant.hpp new file mode 100644 index 000000000..561b7149c --- /dev/null +++ b/src/common/variant.hpp @@ -0,0 +1,276 @@ +/* + VARIANT.hpp - simple variant wrapper (typesafe union) + + 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. + +*/ + + +/** @file variant.hpp + ** This file defines a simple alternative to boost::variant. + ** It pulls in fewer headers and has a shorter code path, but also + ** doesn't deal with alignement issues and is not threadsafe. + ** + ** Values can be stored using \c operator= . In order to access the value + ** stored in lumiera::Variant, you additionally need to define a "functor" + **
  • with a typedef "Ret" for the return type
  • + **
  • providing a static Ret access(ELM&) function + ** for each of the types used in the Variant
  • + **
+ ** + ** @see wrapperptr.hpp usage example + */ + + +#ifndef LUMIERA_VARIANT_H +#define LUMIERA_VARIANT_H + + +#include "common/typelistutil.hpp" + +#include + + + +namespace lumiera { + + namespace variant { + + using lumiera::typelist::count; + using lumiera::typelist::maxSize; + using lumiera::typelist::InstantiateWithIndex; + + /** + * internal helper used to build a variant storage wrapper. + * Parametrized with a collection of types, it provides functionality + * to copy a value of one of these types into an internal buffer, while + * remembering which of these types was used to place this copy. + * The value can be later on extracted using a visitation like mechanism, + * which takes a functor class and invokes a function \c access(T&) with + * the type matching the current value in storage + */ + template + struct Holder + { + + enum { TYPECNT = count::value + , SIZE = maxSize::value + }; + + + /** Storage to hold the actual value */ + struct Buffer + { + char buffer_[SIZE]; + uint which_; + + Buffer() : which_(TYPECNT) {} + + void* + put (void) + { + deleteCurrent(); + return 0; + } + + void + deleteCurrent (); // depends on the Deleter, see below + }; + + template + struct PlacementAdapter : BASE + { + T& + put (T const& toStore) + { + BASE::deleteCurrent(); // remove old content, if any + + T& storedObj = *new(BASE::buffer_) T (toStore); + BASE::which_ = idx; // remember the actual type selected + return storedObj; + } + + using BASE::put; + }; + + typedef InstantiateWithIndex< TYPES + , PlacementAdapter + , Buffer + > + Storage; + + + + /** provide a dispatcher table based visitation mechanism */ + template + struct CaseSelect + { + typedef typename FUNCTOR::Ret Ret; + typedef Ret (*Func)(Buffer&); + + Func table_[TYPECNT]; + + CaseSelect () + { + for (uint i=0; i + static Ret + trampoline (Buffer& storage) + { + T& content = reinterpret_cast (storage.buffer_); + return FUNCTOR::access (content); + } + + Ret + invoke (Buffer& storage) + { + if (TYPECNT <= storage.which_) + return FUNCTOR::ifEmpty (); + else + return (*table_[storage.which_]) (storage); + } + }; + + + template< class T, class BASE, uint i > + struct CasePrepare + : BASE + { + CasePrepare () : BASE() + { + BASE::table_[i] = &BASE::template trampoline; + } + }; + + + template + static typename FUNCTOR::Ret + access (Buffer& buf) + { + typedef InstantiateWithIndex< TYPES + , CasePrepare + , CaseSelect + > + Accessor; + static Accessor select_case; + return select_case.invoke(buf); + } + + + struct Deleter + { + typedef void Ret; + + template + static void access (T& elem) { elem.~T(); } + + static void ifEmpty () { } + }; + }; + + + template + inline void + Holder::Buffer::deleteCurrent () + { + access(*this); // remove old content, if any + which_ = TYPECNT; // mark as empty + } + + } // namespace variant + + + + + + + + + /** + * A variant wrapper (typesafe union) capable of holding a value of any + * of a bounded collection of types. The value is stored in a local buffer + * directly within the object and may be accessed by a typesafe visitation. + * + * \par + * This utility class is similar to boost::variant and indeed was implemented + * (5/08) in an effort to replace the latter in a draft solution for the problem + * of typesafe access to the correct wrapper class from within some builder tool. + * Well -- after finisihng this "exercise" I must admit that it is not really + * much more simple than what boost::variant does internally. At least we are + * pulling in fewer headers and the actual code path is shorter compared with + * boost::variant, at the price of beeing not so generic, not caring for + * alignment issues within the buffer and being not threadsafe + * + * @param TYPES collection of possible types to be stored in this variant object + * @param Access policy how to access the stored value + */ + template< typename TYPES + , template class Access + > + class Variant + : boost::noncopyable + { + + typedef variant::Holder Holder; + typedef typename Holder::Deleter Deleter; + + + /** storage: buffer holding either and "empty" marker, + * or one of the configured pointer to wrapper types */ + typename Holder::Storage holder_; + + + public: + void reset () { holder_.deleteCurrent();} + + /** store a copy of the given argument within the + * variant holder buffer, thereby typically casting + * or converting the given source type to the best + * suited (base) type (out of the collection of possible + * types for this Variant instance) + */ + template + Variant& + operator= (SRC src) + { + if (src) holder_.put (src); // see Holder::PlacementAdaptor::put + else reset(); + return *this; + } + + /** retrieve current content of the variant, + * trying to cast or convert it to the given type. + * Actually, the function \c access(T&) on the + * Access-policy (template param) is invoked with the + * type currently stored in the holder buffer. + * May return NULL if conversion fails. + */ + template + TAR + get () + { + typedef Access Extractor; + return Holder::template access (this->holder_); + } + }; + +} // namespace lumiera +#endif diff --git a/src/common/wrapperptr.hpp b/src/common/wrapperptr.hpp new file mode 100644 index 000000000..e17963eff --- /dev/null +++ b/src/common/wrapperptr.hpp @@ -0,0 +1,63 @@ +/* + WRAPPERPTR.hpp - variant record able to hold a pointer to some smart-ptr/wrapper types, providing conversions + + 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 LUMIERA_WRAPPERPTR_H +#define LUMIERA_WRAPPERPTR_H + + +#include "common/variant.hpp" +#include "common/accesscasted.hpp" + +#include "common/typelist.hpp" +#include "proc/mobject/placement.hpp" +#include "common/p.hpp" + + +namespace asset { class Asset; } +namespace mobject { class MObject; } + +namespace lumiera { + + + typedef typelist::Types < mobject::Placement* + , P* + > ::List + WrapperTypes; + + /** + * helper to treat various sorts of smart-ptrs uniformly. + * Implemented as a variant-type value object, it is preconfigured + * with the possible hierarchy-base classes used within this application. + * Thus, when passing in an arbitrary smart-ptr, the best fitting smart-ptr + * type pointing to the corresponding base class is selected for internal storage. + * Later on, stored values can be retrieved either utilitzing static or dynamic casts; + * error reporting is similar to the bahaviour of dynamic_cast: when retrieving + * a pointer, in case of mismatch NULL is returned. + */ + typedef lumiera::Variant WrapperPtr; + + + +} // namespace lumiera +#endif diff --git a/src/proc/mobject/builder/applicablebuildertargettypes.hpp b/src/proc/mobject/builder/applicablebuildertargettypes.hpp new file mode 100644 index 000000000..e51fa1251 --- /dev/null +++ b/src/proc/mobject/builder/applicablebuildertargettypes.hpp @@ -0,0 +1,70 @@ +/* + ApplicableBuilderTargetTypes - definitinon header specifying all types treated by builder tools + + 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_APPLICABLEBUILDERTARGETTYPES_H +#define MOBJECT_BUILDER_APPLICABLEBUILDERTARGETTYPES_H + +#include "proc/mobject/builder/buildertool.hpp" + + + +namespace mobject { + namespace session { + + class Clip; + class Effect; + class AbstractMO; + template class Auto; + // Forward declarations sufficient here... + // actual definitions necessary only in the + // implementation file (*cpp) of the builder tool. + } + + namespace builder { + + typedef Types< session::Clip, + session::Effect, + session::AbstractMO + > ::List + BuilderTargetTypes; + + + /** + * Marker used to declare some visiting Tool class to be actually a + * mobject::builder::BuilderTool and to possibly accept and treat the + * common selection of types to be handled by any such builder tool. + * The actual BuilderTool impl should inherit from this template by + * feeding back its type (CRTP), this causes a dispatcher table entry + * be generated for this concrete BuilderTool implementation. + */ + template + struct ApplicableBuilderTargetTypes + : Applicable + { }; + + + + } // namespace mobject::builder + +} // namespace mobject +#endif diff --git a/src/proc/mobject/builder/buildertool.hpp b/src/proc/mobject/builder/buildertool.hpp index 0985567d1..1801bc2ef 100644 --- a/src/proc/mobject/builder/buildertool.hpp +++ b/src/proc/mobject/builder/buildertool.hpp @@ -20,20 +20,54 @@ */ +/** @file buildertool.hpp + ** Visiting-tool mechanism configured specifically for the Builder. + ** The Builder creates the render nodes network by applying several Builder Tools + ** to the objects found in the Session, EDL and Fixture. These BuilderTool instances + ** contain the details of the builder implementation. + ** + ** As the objects to be treated are normally handled by smart-ptrs, BuilderTool provides + ** a special facility for dealing with these wrapped objects. There are some liabilities. + **
  • each concrete Buildable subtype to be treated specifically needs to + ** declare \c DEFINE_PROCESSABLE_BY(BuilderTool)
  • + **
  • at the same time, the concrete BuilderTool subclass has to declare + ** being Applicable to this concrete Buildable subtype. The recommended way + ** of ensuring this, is to add an entry to applicablebuildertargettypes.hpp + ** and then derive the concrete BuilderTool subclass from + ** ApplicableBuilderTargetTypes
  • + **
  • when accessing the wrapper from within a \c treat() function, a suitable + ** concrete wrapper type has to be specified. If the wrapper type used for + ** invoking the BuilderTool (function \c apply(BuilderTool&l, WrappedObject&) ) + ** can not be converted to this type requested from within the call, an + ** assertion failure (or segmentation fault in a release build) will result.
  • + **
+ ** + ** @see visitor.hpp + ** @see applicablebuildertargettypes.hpp + ** @see buildertooltest.hpp + ** @see nodecreatertool.hpp + */ + + #ifndef MOBJECT_BUILDER_TOOL_H #define MOBJECT_BUILDER_TOOL_H #include "common/visitor.hpp" +#include "common/wrapperptr.hpp" + +#include "common/p.hpp" +#include "proc/mobject/placement.hpp" +#include "proc/mobject/explicitplacement.hpp" +namespace mobject { -namespace mobject - { class Buildable; - namespace builder - { + namespace builder { + + using lumiera::P; /** * Policy invoking an catch-all function for processing @@ -49,19 +83,79 @@ namespace mobject virtual RET onUnknown (Buildable& target) = 0; }; - - + + /** * Base class of all BuilderTools, used according to the visitor pattern: * each Tool contains the concrete implementation for one task to be done * to the various MObject classes. The concrete builder tool implementation * should not diretcly inherit from this base interface, but rather through * an instantiation of the "Applicable" template parametrized with all - * concrete Buildable classes, for which it wants calls to be dispatched. + * concrete Buildable classes, for which it wants calls to be dispatched. + * \par + * In addition to lumiera::visitor::Tool, BuilderTool adds support for dealing + * with objects normally handled by means of smart-pointers or similar + * wrappers, most notably mobject::Placement. The visitaion is initiated + * by calling the stand-alone function \c (BuilderTool& tool, WRA& wrappedTargetObj) , + * which forwards to the visitation mechanism supported by the type contained + * in the wrapper, but stores away a pointer to the wrapped object, which can + * be retrieved in a typesafe manner from within the \c treat(ConcreteType&) + * function. + * @note retrieving the wrapper is not threadsafe and not reentrant, + * as we simply store a pointer within the BuilderTool instance. */ - typedef lumiera::visitor::Tool BuilderTool; + class BuilderTool + : public lumiera::visitor::Tool + { + lumiera::WrapperPtr currentWrapper_; + + public: + + template class WRA, class TAR> + void rememberWrapper (WRA* ptr_toWrappedTarget) + { + currentWrapper_ = ptr_toWrappedTarget; + } + + void forgetWrapper () + { + currentWrapper_.reset(); + } + + + protected: /* == interface for accessing the wrapper from within tool application == */ + + template + Placement& + getPlacement () + { + Placement* pPlacement = currentWrapper_.get*>(); + ENSURE (pPlacement, "wrong target type when invoking %s", __PRETTY_FUNCTION__); + return *pPlacement; + } + + ExplicitPlacement + getExplicitPlacement () + { + return getPlacement().resolve(); + } + + template + lumiera::P + getPtr () + { + P* pP = currentWrapper_.get*>(); + ENSURE (pP, "wrong target type when invoking %s", __PRETTY_FUNCTION__); + return *pP; + } + }; + + /** + * declare the concrete types a BuilderTool may recievee and treat. + * @note it is recommended to use ApplicableBuilderTargetTypes + */ template < class TOOLImpl, // concrete BuilderTool implementation class TYPELIST // list of all concrete Buildables to be treated @@ -71,17 +165,33 @@ namespace mobject { } ; - using lumiera::typelist::Types; // convienience for the users of "Applicable" - + using lumiera::typelist::Types; // convenience for the users of "Applicable" + } // namespace mobject::builder /** - * Marker Interface for classes Visitable by Builder tools. + * Marker Interface for classes visitable by Builder tools. */ class Buildable : public lumiera::visitor::Visitable { }; - + + + + + namespace builder { // to be found by ADL + + template + inline Buildable::ReturnType + apply (BuilderTool& tool, WRA& wrappedTargetObj) + { + tool.rememberWrapper(&wrappedTargetObj); + wrappedTargetObj->apply (tool); // dispatch to suitable treat() function + tool.forgetWrapper(); + } + + } // namespace mobject::builder + } // namespace mobject #endif diff --git a/src/proc/mobject/builder/nodecreatertool.cpp b/src/proc/mobject/builder/nodecreatertool.cpp index 89a35fa46..93362ef25 100644 --- a/src/proc/mobject/builder/nodecreatertool.cpp +++ b/src/proc/mobject/builder/nodecreatertool.cpp @@ -31,11 +31,8 @@ using mobject::session::Clip; using mobject::session::Effect; using mobject::session::Auto; -namespace mobject - { - - namespace builder - { +namespace mobject { + namespace builder { diff --git a/src/proc/mobject/builder/nodecreatertool.hpp b/src/proc/mobject/builder/nodecreatertool.hpp index 26a033d26..e37d0d14f 100644 --- a/src/proc/mobject/builder/nodecreatertool.hpp +++ b/src/proc/mobject/builder/nodecreatertool.hpp @@ -24,23 +24,15 @@ #ifndef MOBJECT_BUILDER_NODECREATERTOOL_H #define MOBJECT_BUILDER_NODECREATERTOOL_H -#include "proc/mobject/builder/buildertool.hpp" + +#include "proc/mobject/builder/applicablebuildertargettypes.hpp" + #include "proc/engine/processor.hpp" -namespace mobject - { - namespace session - { - // Forward declarations - class Effect; - class Clip; - template class Auto; - } - - namespace builder - { +namespace mobject { + namespace builder { @@ -52,11 +44,10 @@ namespace mobject * render engine under construction such as to reflect the properties * of the MObject in the actual render. */ - class NodeCreatorTool : public BuilderTool + class NodeCreatorTool + : public ApplicableBuilderTargetTypes { - //////////////////////////////////////////////TODO: switch to acyclic visitior!!!!!!!!!!!!! - public: virtual void treat (mobject::session::Clip& clip) ; virtual void treat (mobject::session::Effect& effect) ; diff --git a/src/proc/mobject/builder/segmentationtool.cpp b/src/proc/mobject/builder/segmentationtool.cpp index 6f07e7d4f..7b6c29747 100644 --- a/src/proc/mobject/builder/segmentationtool.cpp +++ b/src/proc/mobject/builder/segmentationtool.cpp @@ -31,10 +31,8 @@ using mobject::session::Clip; using mobject::session::Effect; -namespace mobject - { - namespace builder - { +namespace mobject { + namespace builder { diff --git a/src/proc/mobject/builder/segmentationtool.hpp b/src/proc/mobject/builder/segmentationtool.hpp index aa09d80d3..eaf74c1c6 100644 --- a/src/proc/mobject/builder/segmentationtool.hpp +++ b/src/proc/mobject/builder/segmentationtool.hpp @@ -24,26 +24,18 @@ #ifndef MOBJECT_BUILDER_SEGMENTATIONTOOL_H #define MOBJECT_BUILDER_SEGMENTATIONTOOL_H -#include -#include "proc/mobject/builder/buildertool.hpp" +#include "proc/mobject/builder/applicablebuildertargettypes.hpp" + #include "proc/mobject/session/segment.hpp" +#include using std::list; -namespace mobject - { - namespace session - { - // Forward declarations - class Clip; - class Effect; - } - - namespace builder - { +namespace mobject { + namespace builder { /** @@ -53,10 +45,10 @@ namespace mobject * can be represented by automation solely, without the need * to change the node connections. */ - class SegmentationTool : public BuilderTool + class SegmentationTool + : public ApplicableBuilderTargetTypes { - //////////////////////////////////////////////TODO: switch to acyclic visitior!!!!!!!!!!!!! public: void treat (mobject::session::Clip& clip) ; diff --git a/src/proc/mobject/explicitplacement.hpp b/src/proc/mobject/explicitplacement.hpp index cb5e424b5..0e5b20bfd 100644 --- a/src/proc/mobject/explicitplacement.hpp +++ b/src/proc/mobject/explicitplacement.hpp @@ -30,9 +30,9 @@ namespace mobject { - - - + + + /** * Special kind of Placement, where the location of the * MObject has been nailed down to a fixed position. @@ -51,7 +51,7 @@ namespace mobject const Pipe pipe; typedef std::pair SolutionData; //TODO (ichthyo consideres better passing of solution by subclass) - + /** no need to resolve any further, as this ExplicitPlacement * already \e is the result of a resolve()-call. */ @@ -61,9 +61,7 @@ namespace mobject return *this; } - /** */ /////////////////////////////////////////////////////////////TODO: wip-wip... - DEFINE_PROCESSABLE_BY (builder::BuilderTool); - + protected: /* @todo ichthyo considers a much more elegant implementation utilizing a subclass * of FixedLocation, which would serve as Placement::LocatingSolution, and @@ -82,8 +80,8 @@ namespace mobject /** copying prohibited, ExplicitPlacement is effectively const! */ ExplicitPlacement& operator= (const ExplicitPlacement&); }; - - - + + + } // namespace mobject #endif diff --git a/src/proc/mobject/mobject.hpp b/src/proc/mobject/mobject.hpp index 28ab788ed..eb481489f 100644 --- a/src/proc/mobject/mobject.hpp +++ b/src/proc/mobject/mobject.hpp @@ -88,9 +88,10 @@ namespace mobject virtual bool operator== (const MObject& oo) const =0; }; + - - + + typedef Placement PMO; diff --git a/src/proc/mobject/placement.cpp b/src/proc/mobject/placement.cpp index 452528627..58e145e72 100644 --- a/src/proc/mobject/placement.cpp +++ b/src/proc/mobject/placement.cpp @@ -23,25 +23,39 @@ #include "proc/mobject/placement.hpp" #include "proc/mobject/explicitplacement.hpp" +#include "proc/mobject/mobject.hpp" + +#include +using boost::str; namespace mobject { - /** @note we know we need only this single - * specialisation, because we define - * the Placements of more specific - * MObject kinds to be subclasses - * of Placement, so they - * will inherit this function. - */ - template<> + template ExplicitPlacement - Placement::resolve () const + Placement::resolve () const { return ExplicitPlacement (*this, chain.resolve()); } + + /** @note we know we need only this single specialisation, + * because we define the Placements of more specific + * MObject kinds to be subclasses of Placement, + * so they will inherit this function. + */ + template ExplicitPlacement Placement::resolve() const; + + template<> + Placement::operator string () const + { + static boost::format fmt("Placement<%s> %|50T.| use-cnt=%x adr=%x pointee=%x"); + return str(fmt % typeid(*get()).name() % use_count() % this % get() ); + } + + + } // namespace mobject diff --git a/src/proc/mobject/placement.hpp b/src/proc/mobject/placement.hpp index 7bd3a9ce4..df71f0d75 100644 --- a/src/proc/mobject/placement.hpp +++ b/src/proc/mobject/placement.hpp @@ -58,12 +58,10 @@ #define MOBJECT_PLACEMENT_H #include "pre.hpp" -#include "proc/mobject/mobject.hpp" #include "proc/mobject/session/locatingpin.hpp" #include "proc/asset/pipe.hpp" #include -using std::tr1::shared_ptr; namespace mobject @@ -72,6 +70,7 @@ namespace mobject class ExplicitPlacement; + using std::tr1::shared_ptr; @@ -82,9 +81,10 @@ namespace mobject * be within the Session/EDL */ template - class Placement : public Buildable, protected shared_ptr + class Placement : protected shared_ptr { protected: + typedef shared_ptr Base; typedef lumiera::Time Time; typedef asset::shared_ptr Pipe; @@ -99,13 +99,14 @@ namespace mobject operator-> () const { ENSURE (*this); - return shared_ptr::operator-> (); + return Base::operator-> (); } + operator string() const ; + size_t use_count() const { return Base::use_count(); } + virtual ~Placement() {}; - /** */ /////////////////////////////////////////////////////////////TODO: totmachen? - DEFINE_PROCESSABLE_BY (builder::BuilderTool); /** interface for defining the kind of placement @@ -128,20 +129,19 @@ namespace mobject friend class session::MObjectFactory; }; - typedef Placement PMO; /* === defining specialisations to be subclasses === */ -#define DEFINE_SPECIALIZED_PLACEMENT(SUBCLASS) \ +#define DEFINE_SPECIALIZED_PLACEMENT(SUBCLASS, BASE) \ template<> \ - class Placement : public Placement \ + class Placement : public Placement \ { \ protected: \ Placement (SUBCLASS & m, void (*moKiller)(MObject*)) \ - : Placement::Placement (m, moKiller) \ + : Placement::Placement (m, moKiller) \ { }; \ friend class session::MObjectFactory; \ \ @@ -154,7 +154,6 @@ namespace mobject (shared_ptr::operator-> ()); \ } \ }; - // DEFINE_PROCESSABLE_BY (builder::BuilderTool); /* a note to the maintainer: please don't add any fields or methods to * these subclasses which aren't also present in Placement! diff --git a/src/proc/mobject/session/clip.hpp b/src/proc/mobject/session/clip.hpp index 7f1fe23c0..174a86cbf 100644 --- a/src/proc/mobject/session/clip.hpp +++ b/src/proc/mobject/session/clip.hpp @@ -66,7 +66,7 @@ namespace mobject and the unlink() function of the asset should take it into account when breaking circular references. */ -public: ////////////////////////////////////TODO: temporarily for buildertooltest + const Media & mediaDef_; const asset::Clip & clipDef_; @@ -99,7 +99,7 @@ public: ////////////////////////////////////TODO: temporarily for buildertoolt } // namespace mobject::session /** Placement defined to be subclass of Placement */ - DEFINE_SPECIALIZED_PLACEMENT (session::Clip); + DEFINE_SPECIALIZED_PLACEMENT (session::Clip, MObject); } // namespace mobject diff --git a/src/proc/mobject/session/effect.hpp b/src/proc/mobject/session/effect.hpp index 5831098d4..e4cdbee16 100644 --- a/src/proc/mobject/session/effect.hpp +++ b/src/proc/mobject/session/effect.hpp @@ -51,7 +51,7 @@ namespace mobject } // namespace mobject::session /** Placement defined to be subclass of Placement */ - DEFINE_SPECIALIZED_PLACEMENT (session::Effect); + DEFINE_SPECIALIZED_PLACEMENT (session::Effect, MObject); } // namespace mobject #endif diff --git a/src/proc/mobject/session/meta.hpp b/src/proc/mobject/session/meta.hpp index b45d30eb5..db679a904 100644 --- a/src/proc/mobject/session/meta.hpp +++ b/src/proc/mobject/session/meta.hpp @@ -50,7 +50,7 @@ namespace mobject } // namespace mobject::session /** Placement defined to be subclass of Placement */ - DEFINE_SPECIALIZED_PLACEMENT (session::Meta); + DEFINE_SPECIALIZED_PLACEMENT (session::Meta, MObject); } // namespace mobject #endif diff --git a/src/proc/mobject/session/track.hpp b/src/proc/mobject/session/track.hpp index 2b9801273..f8b2c0017 100644 --- a/src/proc/mobject/session/track.hpp +++ b/src/proc/mobject/session/track.hpp @@ -83,7 +83,7 @@ namespace mobject } // namespace mobject::session /** Placement defined to be subclass of Placement */ - DEFINE_SPECIALIZED_PLACEMENT (session::Track); + DEFINE_SPECIALIZED_PLACEMENT (session::Track, session::Meta); } // namespace mobject #endif diff --git a/tests/54builder.tests b/tests/54builder.tests index 3b6825651..3ec3bd325 100644 --- a/tests/54builder.tests +++ b/tests/54builder.tests @@ -4,8 +4,12 @@ TESTING "Component Test Suite: Builder" ./test-components --group=builder TEST "BuilderTool_test" BuilderTool_test < -#include -#include -#include -#include -#include +#include "common/util.hpp" #include + +using util::cStr; using std::string; using std::cout; -namespace util { - using boost::remove_pointer; - using boost::remove_reference; - using boost::is_convertible; - using boost::is_polymorphic; - using boost::is_base_of; - using boost::enable_if; - - template - struct can_cast : boost::false_type {}; - template - struct can_cast { enum { value = is_base_of::value };}; - - template - struct can_cast { enum { value = is_base_of::value };}; - - template - struct can_cast { enum { value = is_base_of::value };}; - - - template - struct has_RTTI - { - typedef typename remove_pointer< - typename remove_reference::type>::type TPlain; - - enum { value = is_polymorphic::value }; - }; - - template - struct use_dynamic_downcast - { - enum { value = can_cast::value - && has_RTTI::value - && has_RTTI::value - }; - }; - - template - struct use_static_downcast - { - enum { value = can_cast::value - && ( !has_RTTI::value - || !has_RTTI::value - ) - }; - }; - - template - struct use_conversion - { - enum { value = is_convertible::value - && !( use_static_downcast::value - ||use_dynamic_downcast::value - ) - }; - }; - - - - template - struct EmptyVal - { - static X create() { return X(); } - }; - template - struct EmptyVal - { - static X*& create() { static X* nullP(0); return nullP; } - }; - - - - - - template - struct NullAccessor - { - typedef RET Ret; - - static RET access (...) { return ifEmpty(); } - static RET ifEmpty () { return EmptyVal::create(); } - }; - - template - struct AccessCasted : NullAccessor - { - using NullAccessor::access; - - template - static typename enable_if< use_dynamic_downcast, TAR>::type - access (ELM& elem) - { - return dynamic_cast (elem); - } - - template - static typename enable_if< use_static_downcast, TAR>::type - access (ELM& elem) - { - return static_cast (elem); - } - - template - static typename enable_if< use_conversion, TAR>::type - access (ELM& elem) - { - return elem; - } - }; - - -} - -namespace lumiera { - - namespace typelist { - - - template - < class TYPES // List of Types - , template class _X_ // your-template-goes-here - , class BASE = NullType // Base class at end of chain - , uint i = 0 // incremented on each instantiaton - > - class InstantiateWithIndex; - - - template< template class _X_ - , class BASE - , uint i - > - class InstantiateWithIndex - : public BASE - { - public: - typedef BASE Unit; - typedef NullType Next; - enum{ COUNT = i }; - }; - - - template - < class TY, typename TYPES - , template class _X_ - , class BASE - , uint i - > - class InstantiateWithIndex, _X_, BASE, i> - : public _X_< TY - , InstantiateWithIndex - , i - > - { - public: - typedef InstantiateWithIndex Next; - typedef _X_ Unit; - enum{ COUNT = Next::COUNT }; - }; - - template - struct count; - template<> - struct count - { - enum{ value = 0 }; - }; - template - struct count > - { - enum{ value = 1 + count::value }; - }; - - template - struct maxSize; - template<> - struct maxSize - { - enum{ value = 0 }; - }; - template - struct maxSize > - { - enum{ nextval = maxSize::value - , thisval = sizeof(TY) - , value = nextval > thisval? nextval:thisval - }; - }; - - } // namespace typelist - - - - - - namespace variant { - - using lumiera::typelist::count; - using lumiera::typelist::maxSize; - using lumiera::typelist::InstantiateWithIndex; - - /** - * internal helper used to build a variant storage wrapper. - * Parametrized with a collection of types, it provides functionality - * to copy a value of one of these types into an internal buffer, while - * remembering which of these types was used to place this copy. - * The value can be later on extracted using a visitation like mechanism, - * which takes a functor object and invokes a function \c access(T&) with - * the type matching the current value in storage - */ - template - struct Holder - { - - enum { TYPECNT = count::value - , SIZE = maxSize::value - }; - - - /** Storage to hold the actual value */ - struct Buffer - { - char buffer_[SIZE]; - uint which; - - Buffer() : which(TYPECNT) {} - - void* - put (void) - { - deleteCurrent(); - return 0; - } - - void - deleteCurrent (); // depends on the Deleter, see below - }; - - template - struct PlacementAdapter : BASE - { - T& - put (T const& toStore) - { - BASE::deleteCurrent(); // remove old content, if any - - T& storedObj = *new(BASE::buffer_) T (toStore); - this->which = idx; // remember the actual type selected - return storedObj; - } - - using BASE::put; - }; - - typedef InstantiateWithIndex< TYPES - , PlacementAdapter - , Buffer - > - Storage; - - - - /** provide a dispatcher table based visitation mechanism */ - template - struct CaseSelect - { - typedef typename FUNCTOR::Ret Ret; - typedef Ret (*Func)(Buffer&); - - Func table_[TYPECNT]; - - CaseSelect () - { - for (uint i=0; i - static Ret - trampoline (Buffer& storage) - { - T& content = reinterpret_cast (storage.buffer_); - return FUNCTOR::access (content); - } - - Ret - invoke (Buffer& storage) - { - if (TYPECNT <= storage.which) - return FUNCTOR::ifEmpty (); - else - return (*table_[storage.which]) (storage); - } - }; - - - template< class T, class BASE, uint i > - struct CasePrepare - : BASE - { - CasePrepare () : BASE() - { - BASE::table_[i] = &BASE::template trampoline; - } - }; - - - template - static typename FUNCTOR::Ret - access (Buffer& buf) - { - typedef InstantiateWithIndex< TYPES - , CasePrepare - , CaseSelect - > - Accessor; - static Accessor select_case; - return select_case.invoke(buf); - } - - - struct Deleter - { - typedef void Ret; - - template - static void access (T& elem) { elem.~T(); } - - static void ifEmpty () { } - }; - }; - - - template - void - Holder::Buffer::deleteCurrent () - { - access(*this); // remove old content, if any - which = TYPECNT; // mark as empty - } - - } // namespace variant - - - - - - - - - - - - - /** - * A variant wrapper (typesafe union) capable of holding a value of any - * of a bounded collection of types. The value is stored in a local buffer - * directly within the object and may be accessed by a typesafe visitation. - * - * \par - * This utility class is similar to boost::variant and indeed was implemented - * (5/08) in an effort to replace the latter in a draft solution for the problem - * of typesafe access to the correct wrapper class from within some builder tool. - * Well -- after finisihng this "exercise" I must admit that it is not really - * much more simple than what boost::variant does internally. At least we are - * pulling in fewer headers and the actual code path is shorter compared with - * boost::variant, at the price of beeing not so generic, not caring for - * alignment issues within the buffer and being not threadsafe - * - * @param TYPES collection of possible types to be stored in this variant object - * @param Access policy how to access the stored value - */ - template< typename TYPES - , template class Access = util::AccessCasted - > - class Variant - : boost::noncopyable - { - - typedef variant::Holder Holder; - typedef typename Holder::Deleter Deleter; - - - /** storage: buffer holding either and "empty" marker, - * or one of the configured pointer to wrapper types */ - typename Holder::Storage holder_; - - - public: - void reset () { holder_.deleteCurrent();} - - /** store a copy of the given argument within the - * variant holder buffer, thereby typically casting - * or converting the given source type to the best - * suited (base) type (out of the collection of possible - * types for this Variant instance) - */ - template - Variant& - operator= (SRC src) - { - if (src) holder_.put (src); // see Holder::PlacementAdaptor::put - else reset(); - return *this; - } - - /** retrieve current content of the variant, - * trying to cast or convert it to the given type. - * Actually, the function \c access(T&) on the - * Access-policy (template param) is invoked with the - * type currently stored in the holder buffer. - * May return NULL if conversion fails. - */ - template - TAR - get () - { - typedef Access Extractor; - return Holder::template access (this->holder_); - } - }; - -} // namespace lumiera - - - -namespace mobject - { - - DEFINE_SPECIALIZED_PLACEMENT (session::AbstractMO); - - - namespace builder - { - namespace test - { +namespace mobject { + namespace builder { + namespace test { using session::Clip; using session::AbstractMO; - -/////////////////////////////////////////////////////TODO: move to buildertool.hpp - - using lumiera::P; - using lumiera::typelist::Types; - - - - typedef Types < Placement* - , P* - > ::List - WrapperTypes; - - /** - * helper to treat various sorts of smart-ptrs uniformly. - * Implemented as a variant-type value object, it is preconfigured - * with the possible hierarchy-base classes used within this application. - * Thus, when passing in an arbitrary smart-ptr, the best fitting smart-ptr - * type pointing to the corresponding base class is selected for internal storage. - * Later on, stored values can be retrieved either utilitzing static or dynamic casts; - * error reporting is similar to the bahaviour of dynamic_cast: when retrieving - * a pointer, in case of mismatch NULL is returned. - */ - typedef lumiera::Variant WrapperPtr; - - - - class BuTuul - : public lumiera::visitor::Tool - { - WrapperPtr currentWrapper_; - - public: - - template class WRA, class TAR> - void rememberWrapper (WRA* argument) - { - currentWrapper_ = argument; - } - - void forgetWrapper () - { - currentWrapper_.reset(); - } - template - Placement& - getPlacement () - { - Placement* pPlacement = currentWrapper_.get*>(); - return *pPlacement; - } - ExplicitPlacement - getExplicitPlacement () - { - return getPlacement().resolve(); - } - template - P - getPtr () - { - P* pP = currentWrapper_.get*>(); - return *pP; - } - }; - - - - - - - - template - < class TOOLImpl, // concrete BuilderTool implementation - class TYPELIST // list of all concrete Buildables to be treated - > - class Appli - : public lumiera::visitor::Applicable - { } - ; - - using lumiera::typelist::Types; // convienience for the users of "Applicable" - - class BDable : public lumiera::visitor::Visitable - { - - }; -/////////////////////////////////////////////////////TODO: move to buildertool.hpp - - class DummyMO : public AbstractMO, public BDable + /** + * Test MObject subclass, which, contrary to any real MObject, + * can be created directly without involving MObjectFactory. + */ + class TestMO : public AbstractMO { public: - DummyMO() { }; - virtual bool isValid() const { return true;} -// DEFINE_PROCESSABLE_BY (BuilderTool); + TestMO() { }; - static void killDummy (MObject* dum) { delete (DummyMO*)dum; } - - virtual void - apply (BuTuul& tool) - { - return BDable::dispatchOp (*this, tool); - } + DEFINE_PROCESSABLE_BY (BuilderTool); + virtual bool isValid() const { return true;} + static void killDummy (MObject* dum) { delete (TestMO*)dum; } }; - class Clop : public Clip, public BDable - { - Clop (Clip& base) : Clip (base.clipDef_, base.mediaDef_) {} - - virtual void - apply (BuTuul& tool) - { - return BDable::dispatchOp (*this, tool); - } + /** + * Subclass-1 is \em not defined "processable", + * thus will always be handled as TestMO... + */ + class TestSubMO1 : public TestMO + { }; + + /** + * Subclass-2 \em is defined "processable", + * but we omit the necessary "applicable" definition in TestTool, + * resulting in an invocation of the error (catch-all) function... + */ + class TestSubMO2 : public TestMO + { + DEFINE_PROCESSABLE_BY (BuilderTool); }; - template - inline BDable::ReturnType - apply (BuTuul& tool, WRA& wrappedTargetObj) - { - WRA* ptr = &wrappedTargetObj; - (*ptr)->isValid(); - tool.rememberWrapper(ptr); - wrappedTargetObj->apply (tool); - tool.forgetWrapper(); - } - - //////////////////////////////////////////////////////TODO: wip-wip - - class DummyPlacement : public Placement + template + class TestPlacement : public Placement { public: - DummyPlacement() - : Placement::Placement(*new DummyMO, &DummyMO::killDummy) + TestPlacement(TestMO& testObject) + : Placement::Placement(testObject, &TestMO::killDummy) { } }; - //////////////////////////////////////////////////////TODO: wip-wip - + /** + * BuilderTool implementation for checking the invokation of the correct + * \c treat() function and for accessing the original Placement from + * within this invocation. It is declared to be applicable to Clip + * and TestMO objects (wrapped into any acceptable shared-ptr). + * Intentionally, we omit to declare it applicable to TestSubMO2 instances. + * In reality this would be a case of misconfiguration, because TestSubMO2 + * is defined to be processable and consequently has an \apply() function, + * which, due to this ommission can't find a dispatcher entry when invoked, + * so it will call the \c onUnknown(Buildable&) instead + */ class TestTool - : public Appli::List> + : public Applicable::List> { public: + string log_; + void treat (Clip& c) { Placement& pC = getPlacement(); - cout << "media is: "<< str(pC->getMedia()) <<"\n" - << "Placement(adr) " << &pC <<"\n"; + cout << "Clip on media : "<< str(pC->getMedia()) <<"\n"; + log_ = string (pC); } void treat (AbstractMO&) { - Placement& placement = getPlacement(); - cout << "unspecific MO; Placement(adr) " << &placement <<"\n"; + cout << "treat (AbstractMO&);\n"; + log_ = string (getPlacement()); } - void onUnknown (Buildable&) + void onUnknown (Buildable& bxx) { - cout << "catch-all-function called.\n"; + cout << "catch-all-function called...\n"; + log_ = string (getPlacement()); } }; - - - /******************************************************************* - * @test the generic visitor pattern specialized for treating - * MObjects in the builder. Because the generic visitor - * implementation is already covered by - * \link VisitingTool_test, it is sufficient to test - * the specialisation to the builder. - * \par + + + + + /************************************************************************************* + * @test the generic visitor pattern specialized for treating MObjects in the builder. * Besides using existing MObject types (at the moment session::Clip), - * we create inline a yet-unknown new MObject subclass. When passing - * such to any BuilderTool subclass, the compiler enforces the definition - * of a catch-all function, which is called, when there is no other - * applicable \c treat(MO&) function. Note further, whithin the specific - * treat-functions we get direct references, whithout interfering with - * Placements and memory management. (Is this a good idea? it allows - * client code to bypass the Placement (Handle). At least, I think - * it is not really a problem...) + * we create a yet-unknown new MObject subclass. When passing such to any + * BuilderTool subclass, the compiler enforces the definition of a catch-all + * function, which is called, when there is no other applicable \c treat(MO&) + * function. Note further, whithin the specific treat-functions we get direct + * references, whithout interfering with Placements and memory management. + * But from within the \c treat() function, we may access the wrapper object + * (i.e. shared_ptr, or lumiera::P or Placement) used when invoking the + * BuilderTool by using the protected interface on BuilderTool. + * + * @see VisitingTool_test for checking general visitor functionality */ class BuilderTool_test : public Test { @@ -677,18 +150,27 @@ namespace mobject { TestTool t1; - BuTuul& tool (t1); + BuilderTool& tool = t1; - DummyPlacement dumm; - Placement& dummy(dumm); - Placement clip = asset::Media::create("test-1", asset::VIDEO)->createClip(); + TestPlacement test1(*new TestSubMO1); + TestPlacement test2(*new TestSubMO2); - cout << "Placement(adr) " << &clip <<"\n"; + cout << "apply (tool, clip);\n"; apply (tool, clip); - cout << "Placement(adr) " << &dumm <<"\n"; - apply (tool, dummy); + INFO (test, "got Wrapper = %s", t1.log_.c_str()); + ASSERT (t1.log_ == string(clip)); + + cout << "apply (tool, test1);\n"; + apply (tool, test1); + INFO (test, "got Wrapper = %s", t1.log_.c_str()); + ASSERT (t1.log_ == string(test1)); + + cout << "apply (tool, test2);\n"; + apply (tool, test2); + INFO (test, "got Wrapper = %s", t1.log_.c_str()); + ASSERT (t1.log_ == string(test2)); } }; @@ -702,14 +184,4 @@ namespace mobject } // namespace builder - //////////////////////////////////////////////////////TODO: wip-wip -/* template<> - ExplicitPlacement - Placement::resolve () const - { - UNIMPLEMENTED ("just a test"); - } -*/ //////////////////////////////////////////////////////TODO: wip-wip - - } // namespace mobject