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/configrules.hpp b/src/common/configrules.hpp index 81da041ae..0968c88d4 100644 --- a/src/common/configrules.hpp +++ b/src/common/configrules.hpp @@ -46,6 +46,7 @@ #ifndef LUMIERA_CONFIGRULES_H #define LUMIERA_CONFIGRULES_H +#include "common/p.hpp" #include "common/query.hpp" #include "common/typelistutil.hpp" #include "common/singletonsubclass.hpp" @@ -57,14 +58,13 @@ #include "proc/asset/track.hpp" #include -#include namespace lumiera { using std::string; - using std::tr1::shared_ptr; + using lumiera::P; @@ -148,13 +148,13 @@ namespace lumiera * @query any goals to be fulfilled by the solution. * @return false if resolution failed. In this case, solution ptr is empty. */ - virtual bool resolve (shared_ptr& solution, const Query& q) = 0; + virtual bool resolve (P& solution, const Query& q) = 0; }; // TODO: the Idea is to provide specialisations for the concrete types // we want to participate in the ConfigRules system.... // Thus we get the possibility to create a specific return type, - // e.g. return a shared_ptr but a Placement, using the appropriate factory. + // e.g. return a P but a Placement, using the appropriate factory. // Of course then the definitions need to be split up in separate headers. diff --git a/src/common/query/mockconfigrules.hpp b/src/common/query/mockconfigrules.hpp index f5bea3264..f56519ed6 100644 --- a/src/common/query/mockconfigrules.hpp +++ b/src/common/query/mockconfigrules.hpp @@ -74,7 +74,7 @@ namespace lumiera /** a traits-class to define the smart-ptr to wrap the result */ template - struct WrapReturn { typedef shared_ptr Wrapper; }; + struct WrapReturn { typedef P Wrapper; }; template<> struct WrapReturn { typedef PProcPatt Wrapper; }; diff --git a/src/common/typelistutil.hpp b/src/common/typelistutil.hpp index 4e382df3d..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 ** @@ -136,11 +139,99 @@ namespace lumiera > { public: - typedef InstantiateChained Next; + typedef InstantiateChained Next; typedef _X_ Unit; }; + + /** + * 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/visitor.hpp b/src/common/visitor.hpp index 837ddf713..3d22f11e6 100644 --- a/src/common/visitor.hpp +++ b/src/common/visitor.hpp @@ -105,7 +105,7 @@ namespace lumiera typedef RET ReturnType; ///< Tool function invocation return type typedef Tool ToolBase; ///< for templating the Tag and Dispatcher - virtual ~Tool () { }; ///< use RTTI for all visiting tools + virtual ~Tool () { }; ///< use RTTI for all visiting tools /** allows discovery of the concrete Tool type when dispatching a * visitor call. Can be implemented by inheriting from ToolTag */ diff --git a/src/common/visitorpolicies.hpp b/src/common/visitorpolicies.hpp index e59a2f5b2..829dd5546 100644 --- a/src/common/visitorpolicies.hpp +++ b/src/common/visitorpolicies.hpp @@ -23,7 +23,7 @@ /** @file visitorpolicies.hpp ** Policies usable for configuring the lumiera::visitor::Tool for different kinds of error handling. - ** @see buildertool.hpp for another flavor (calling and catch-all-function) + ** @see buildertool.hpp for another flavour (calling an catch-all-function there) ** */ 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/asset/buildinstruct.hpp b/src/proc/asset/buildinstruct.hpp index 577a108c1..8b1162103 100644 --- a/src/proc/asset/buildinstruct.hpp +++ b/src/proc/asset/buildinstruct.hpp @@ -41,12 +41,13 @@ using std::string; namespace asset { + using lumiera::P; class Proc; class ProcPatt; - typedef shared_ptr PProc; - typedef shared_ptr PProcPatt; + typedef P PProc; + typedef P PProcPatt; static Symbol CURRENT = "current"; diff --git a/src/proc/asset/clip.hpp b/src/proc/asset/clip.hpp index f5e1ea629..53a74faa5 100644 --- a/src/proc/asset/clip.hpp +++ b/src/proc/asset/clip.hpp @@ -53,7 +53,7 @@ namespace asset }; - typedef shared_ptr PClipAsset; + typedef P PClipAsset; const string CLIP_SUBFOLDER = "clips"; // TODO: handling of hard-wired constants.... diff --git a/src/proc/asset/db.hpp b/src/proc/asset/db.hpp index cb32868d7..f35785e5e 100644 --- a/src/proc/asset/db.hpp +++ b/src/proc/asset/db.hpp @@ -100,7 +100,7 @@ namespace asset bool del (ID hash) { return table.erase (hash); } template - shared_ptr + P get (ID hash) const { return dynamic_pointer_cast (find (hash)); diff --git a/src/proc/asset/media.cpp b/src/proc/asset/media.cpp index a91e8284b..68fcb0b56 100644 --- a/src/proc/asset/media.cpp +++ b/src/proc/asset/media.cpp @@ -219,7 +219,7 @@ namespace asset * @throw Invalid if the given media asset is not top-level, * but rather part or a multichannel (compound) media */ - shared_ptr + P MediaFactory::operator() (asset::Media& mediaref) throw(lumiera::error::Invalid) { if (mediaref.checkCompound()) diff --git a/src/proc/asset/media.hpp b/src/proc/asset/media.hpp index 4e122cd53..b14399ce5 100644 --- a/src/proc/asset/media.hpp +++ b/src/proc/asset/media.hpp @@ -52,6 +52,7 @@ namespace asset class MediaFactory; class ProcPatt; + using lumiera::P; using lumiera::Time; @@ -74,9 +75,9 @@ namespace asset const Time len_; public: - typedef shared_ptr PMedia; - typedef shared_ptr PClip; - typedef shared_ptr PProcPatt; + typedef P PMedia; + typedef P PClip; + typedef P PProcPatt; typedef mobject::session::PClipMO PClipMO; @@ -142,7 +143,7 @@ namespace asset class MediaFactory : public lumiera::Factory { public: - typedef shared_ptr PType; + typedef P PType; PType operator() (Asset::Ident& key, const string& file=""); PType operator() (const string& file, const Category& cat); @@ -152,7 +153,7 @@ namespace asset PType operator() (const char* file, const Category& cat); PType operator() (const char* file, asset::Kind); - shared_ptr + P operator() (asset::Media& mediaref) throw(lumiera::error::Invalid); }; diff --git a/src/proc/asset/meta.hpp b/src/proc/asset/meta.hpp index 02be992db..c15f14fbf 100644 --- a/src/proc/asset/meta.hpp +++ b/src/proc/asset/meta.hpp @@ -95,7 +95,7 @@ namespace asset class MetaFactory : public lumiera::Factory { public: - typedef shared_ptr PType; + typedef P PType; PType operator() (Asset::Ident& key); ////////////TODO define actual operation diff --git a/src/proc/asset/pipe.hpp b/src/proc/asset/pipe.hpp index 110dd1975..c2a9a8ff0 100644 --- a/src/proc/asset/pipe.hpp +++ b/src/proc/asset/pipe.hpp @@ -31,9 +31,10 @@ namespace asset { + using lumiera::P; class Pipe; - typedef shared_ptr PPipe; + typedef P PPipe; template<> diff --git a/src/proc/asset/proc.hpp b/src/proc/asset/proc.hpp index 05eca4ddf..724c8a786 100644 --- a/src/proc/asset/proc.hpp +++ b/src/proc/asset/proc.hpp @@ -48,7 +48,7 @@ namespace asset class Proc; class ProcFactory; - typedef shared_ptr PProc; + typedef P PProc; @@ -97,7 +97,7 @@ namespace asset class ProcFactory : public lumiera::Factory { public: - typedef shared_ptr PType; + typedef P PType; PType operator() (Asset::Ident& key); ////////////TODO define actual operation diff --git a/src/proc/asset/procpatt.cpp b/src/proc/asset/procpatt.cpp index 1adf8736c..d5173b9ea 100644 --- a/src/proc/asset/procpatt.cpp +++ b/src/proc/asset/procpatt.cpp @@ -60,7 +60,7 @@ namespace asset * some ProcPatt as a template for creating more * spezialized patterns. */ - shared_ptr + P ProcPatt::newCopy (string newID) const { TODO ("implement the Pattern-ID within the propDescriptor!"); diff --git a/src/proc/asset/procpatt.hpp b/src/proc/asset/procpatt.hpp index 6c8cf37e0..65f832b41 100644 --- a/src/proc/asset/procpatt.hpp +++ b/src/proc/asset/procpatt.hpp @@ -35,13 +35,14 @@ using std::vector; namespace asset { + using lumiera::P; using lumiera::Symbol; class Proc; class ProcPatt; class BuildInstruct; - typedef shared_ptr PProc; - typedef shared_ptr PProcPatt; + typedef P PProc; + typedef P PProcPatt; typedef vector InstructionSequence; @@ -61,14 +62,13 @@ namespace asset friend class StructFactoryImpl; public: - shared_ptr newCopy (string newID) const; + P newCopy (string newID) const; ProcPatt& attach (Symbol where, PProc& node); ProcPatt& operator+= (PProcPatt& toReuse); }; - typedef shared_ptr PProcPatt; diff --git a/src/proc/asset/struct.cpp b/src/proc/asset/struct.cpp index 6e85c50c2..5813ce339 100644 --- a/src/proc/asset/struct.cpp +++ b/src/proc/asset/struct.cpp @@ -89,10 +89,10 @@ namespace asset * created as a side effect of calling the concrete Struct subclass ctor. */ template - shared_ptr + P StructFactory::operator() (const Query& capabilities) { - shared_ptr res; + P res; QueryHandler& typeHandler = ConfigRules::instance(); typeHandler.resolve (res, capabilities); @@ -117,7 +117,7 @@ namespace asset * @see ProcPatt * @see DefaultsManager */ - shared_ptr + P StructFactory::operator() (string pipeID, string streamID) { normalizeID (pipeID); @@ -147,9 +147,9 @@ namespace asset namespace asset { - template shared_ptr StructFactory::operator() (const Query& query); - template shared_ptr StructFactory::operator() (const Query& query); - template PProcPatt StructFactory::operator() (const Query& query); + template P StructFactory::operator() (const Query& query); + template P StructFactory::operator() (const Query& query); + template PProcPatt StructFactory::operator() (const Query& query); } // namespace asset diff --git a/src/proc/asset/struct.hpp b/src/proc/asset/struct.hpp index 7c4c4367b..5941bd13a 100644 --- a/src/proc/asset/struct.hpp +++ b/src/proc/asset/struct.hpp @@ -120,12 +120,12 @@ namespace asset public: - typedef shared_ptr PType; + typedef P PType; template - shared_ptr operator() (const Query& query); ////////////TODO actually do something sensible here + P operator() (const Query& query); ////////////TODO actually do something sensible here - shared_ptr operator() (string pipeID, string streamID); + P operator() (string pipeID, string streamID); }; diff --git a/src/proc/asset/track.hpp b/src/proc/asset/track.hpp index a36a6242c..01abe5e8e 100644 --- a/src/proc/asset/track.hpp +++ b/src/proc/asset/track.hpp @@ -48,7 +48,7 @@ namespace asset }; - typedef shared_ptr PTrack; + typedef P PTrack; diff --git a/src/proc/assetmanager.cpp b/src/proc/assetmanager.cpp index fcdf45dc0..9acb29daa 100644 --- a/src/proc/assetmanager.cpp +++ b/src/proc/assetmanager.cpp @@ -130,11 +130,11 @@ namespace asset * of the stored object differs and can't be casted. */ template - shared_ptr + P AssetManager::getAsset (const ID& id) throw(lumiera::error::Invalid) { - if (shared_ptr obj = registry.get (id)) + if (P obj = registry.get (id)) return obj; else if (known (id)) // provide Ident tuple of existing Asset @@ -143,14 +143,14 @@ namespace asset throw UnknownID (id); } - /** convienience shortcut for fetching the registered shared_ptr + /** convienience shortcut for fetching the registered smart-ptr * which is in charge of the given asset instance. By querying * directly asset.id (of type ID), the call to registry.get() * can bypass the dynamic cast, because the type of the asset * is explicitely given by type KIND. */ template - shared_ptr + P AssetManager::wrap (const KIND& asset) { ENSURE (instance().known(asset.id), @@ -169,7 +169,7 @@ namespace asset { return ( registry.get (ID(id)) ); } // query most general Asset ID-kind and use implicit - // conversion from shared_ptr to bool (test if empty) + // conversion from smart-ptr to bool (test if empty) /** @@ -245,18 +245,18 @@ namespace asset template ID AssetManager::reg (Asset* obj, const Asset::Ident& idi); - template shared_ptr AssetManager::getAsset (const ID& id) throw(lumiera::error::Invalid); - template shared_ptr AssetManager::getAsset (const ID& id) throw(lumiera::error::Invalid); - template shared_ptr AssetManager::getAsset (const ID& id) throw(lumiera::error::Invalid); - template shared_ptr AssetManager::getAsset (const ID& id) throw(lumiera::error::Invalid); - template shared_ptr AssetManager::getAsset (const ID& id) throw(lumiera::error::Invalid); + template P AssetManager::getAsset (const ID& id) throw(lumiera::error::Invalid); + template P AssetManager::getAsset (const ID& id) throw(lumiera::error::Invalid); + template P AssetManager::getAsset (const ID& id) throw(lumiera::error::Invalid); + template P AssetManager::getAsset (const ID& id) throw(lumiera::error::Invalid); + template P AssetManager::getAsset (const ID& id) throw(lumiera::error::Invalid); - template shared_ptr AssetManager::wrap (const Asset& asset); - template shared_ptr AssetManager::wrap (const Media& asset); - template shared_ptr AssetManager::wrap (const Clip& asset); - template shared_ptr AssetManager::wrap (const Track& asset); - template shared_ptr AssetManager::wrap (const Pipe& asset); - template shared_ptr AssetManager::wrap (const ProcPatt& asset); + template P AssetManager::wrap (const Asset& asset); + template P AssetManager::wrap (const Media& asset); + template P AssetManager::wrap (const Clip& asset); + template P AssetManager::wrap (const Track& asset); + template P AssetManager::wrap (const Pipe& asset); + template P AssetManager::wrap (const ProcPatt& asset); } // namespace asset diff --git a/src/proc/assetmanager.hpp b/src/proc/assetmanager.hpp index 22138065d..3f62d2ecd 100644 --- a/src/proc/assetmanager.hpp +++ b/src/proc/assetmanager.hpp @@ -73,13 +73,13 @@ namespace asset /** provide the unique ID for given Asset::Ident tuple */ static ID getID (const Asset::Ident&); - /** retrieve the registerd shared_ptr for any asset */ + /** retrieve the registerd smart-ptr for any asset */ template - static shared_ptr wrap (const KIND& asset); + static P wrap (const KIND& asset); /** find and return corresponging object */ template - shared_ptr getAsset (const ID& id) throw(lumiera::error::Invalid); + P getAsset (const ID& id) throw(lumiera::error::Invalid); /** @return true if the given id is registered in the internal asset DB */ diff --git a/src/proc/lumiera.hpp b/src/proc/lumiera.hpp index b56ab69b6..c00a70254 100644 --- a/src/proc/lumiera.hpp +++ b/src/proc/lumiera.hpp @@ -30,6 +30,7 @@ /* common types frequently used... */ +#include "common/p.hpp" #include "common/util.hpp" #include "common/time.hpp" #include "common/error.hpp" ///< pulls in NoBug via nobugcfg.hpp 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 388a0ac82..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. */ @@ -60,7 +60,8 @@ namespace mobject { return *this; } - + + protected: /* @todo ichthyo considers a much more elegant implementation utilizing a subclass * of FixedLocation, which would serve as Placement::LocatingSolution, and @@ -79,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 a8c02c761..eb481489f 100644 --- a/src/proc/mobject/mobject.hpp +++ b/src/proc/mobject/mobject.hpp @@ -26,17 +26,18 @@ #include "pre.hpp" -#include -#include #include "proc/lumiera.hpp" #include "proc/mobject/builder/buildertool.hpp" #include "proc/mobject/placement.hpp" #include "proc/asset.hpp" // TODO finally not needed? +#include +#include +#include + using std::list; -using std::tr1::shared_ptr; #include "proc/assetmanager.hpp" using proc_interface::IDA; // TODO finally not needed? @@ -45,6 +46,7 @@ using proc_interface::AssetManager; namespace mobject { + using lumiera::P; namespace session { @@ -58,7 +60,10 @@ namespace mobject * manipulated and finally rendered within Lumiera's EDL * are MObjects. */ - class MObject : public Buildable + class MObject + : public Buildable, + boost::noncopyable, + boost::equality_comparable< MObject > { protected: typedef lumiera::Time Time; @@ -79,11 +84,14 @@ namespace mobject virtual bool isValid() const =0; virtual Time& getLength() =0; ///< @todo how to deal with the time/length field?? + + 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 c5d56169d..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; @@ -85,6 +84,7 @@ namespace mobject 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/abstractmo.cpp b/src/proc/mobject/session/abstractmo.cpp index e484eee6e..e3ebffd4f 100644 --- a/src/proc/mobject/session/abstractmo.cpp +++ b/src/proc/mobject/session/abstractmo.cpp @@ -28,8 +28,14 @@ namespace mobject namespace session { - /** */ - + /** default/fallback implementation of equality + * using literal object identity (same address) + */ + bool + AbstractMO::operator== (const MObject& oo) const + { + return (this == &oo); + } } // namespace mobject::session diff --git a/src/proc/mobject/session/abstractmo.hpp b/src/proc/mobject/session/abstractmo.hpp index 45942986d..5de61737f 100644 --- a/src/proc/mobject/session/abstractmo.hpp +++ b/src/proc/mobject/session/abstractmo.hpp @@ -49,6 +49,8 @@ namespace mobject DEFINE_PROCESSABLE_BY (builder::BuilderTool); + virtual bool operator== (const MObject& oo) const; + }; diff --git a/src/proc/mobject/session/clip.hpp b/src/proc/mobject/session/clip.hpp index 75cac3ef7..174a86cbf 100644 --- a/src/proc/mobject/session/clip.hpp +++ b/src/proc/mobject/session/clip.hpp @@ -38,8 +38,8 @@ namespace mobject namespace session { using asset::Media; - typedef shared_ptr PMedia; - typedef shared_ptr PClipAsset; + typedef P PMedia; + typedef P PClipAsset; /** @@ -66,6 +66,7 @@ namespace mobject and the unlink() function of the asset should take it into account when breaking circular references. */ + const Media & mediaDef_; const asset::Clip & clipDef_; @@ -98,7 +99,7 @@ namespace mobject } // 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/defsmanager.cpp b/src/proc/mobject/session/defsmanager.cpp index c84e5116d..b60e38064 100644 --- a/src/proc/mobject/session/defsmanager.cpp +++ b/src/proc/mobject/session/defsmanager.cpp @@ -39,7 +39,7 @@ namespace mobject { namespace session { - using std::tr1::shared_ptr; + using lumiera::P; @@ -52,10 +52,10 @@ namespace mobject template - shared_ptr + P DefsManager::search (const Query& capabilities) { - shared_ptr res; + P res; QueryHandler& typeHandler = ConfigRules::instance(); for (DefsRegistry::Iter i = defsRegistry->candidates(capabilities); res = *i ; ++i ) @@ -69,10 +69,10 @@ namespace mobject template - shared_ptr + P DefsManager::create (const Query& capabilities) { - shared_ptr res; + P res; QueryHandler& typeHandler = ConfigRules::instance(); typeHandler.resolve (res, capabilities); if (res) @@ -83,9 +83,9 @@ namespace mobject template bool - DefsManager::define (const shared_ptr& defaultObj, const Query& capabilities) + DefsManager::define (const P& defaultObj, const Query& capabilities) { - shared_ptr candidate (defaultObj); + P candidate (defaultObj); QueryHandler& typeHandler = ConfigRules::instance(); typeHandler.resolve (candidate, capabilities); if (!candidate) @@ -97,17 +97,17 @@ namespace mobject template bool - DefsManager::forget (const shared_ptr& defaultObj) + DefsManager::forget (const P& defaultObj) { return defsRegistry->forget (defaultObj); } template - shared_ptr + P DefsManager::operator() (const Query& capabilities) { - shared_ptr res (search (capabilities)); + P res (search (capabilities)); if (res) return res; else diff --git a/src/proc/mobject/session/defsmanager.hpp b/src/proc/mobject/session/defsmanager.hpp index 753b452d2..eb2ca1502 100644 --- a/src/proc/mobject/session/defsmanager.hpp +++ b/src/proc/mobject/session/defsmanager.hpp @@ -25,11 +25,11 @@ #define MOBJECT_SESSION_DEFSMANAGER_H +#include "common/p.hpp" #include "common/query.hpp" #include #include -#include @@ -37,7 +37,7 @@ namespace mobject { namespace session { - using std::tr1::shared_ptr; + using lumiera::P; using boost::scoped_ptr; class DefsRegistry; @@ -69,14 +69,14 @@ namespace mobject * is considered \e misconfiguration. */ template - shared_ptr operator() (const lumiera::Query&); + P operator() (const lumiera::Query&); /** search through the registered defaults, never create anything. * @return object fulfilling the query, \c empty ptr if not found. */ template - shared_ptr search (const lumiera::Query&); + P search (const lumiera::Query&); /** retrieve an object fulfilling the query and register it as default. * The resolution is delegated to the ConfigQuery system (which may cause @@ -84,7 +84,7 @@ namespace mobject * @return object fulfilling the query, \c empty ptr if no solution. */ template - shared_ptr create (const lumiera::Query&); + P create (const lumiera::Query&); /** register the given object as default, after ensuring it fulfills the * query. The latter may cause some properties of the object to be set, @@ -93,13 +93,13 @@ namespace mobject * @note only a weak ref to the object is stored */ template - bool define (const shared_ptr&, const lumiera::Query&); + bool define (const P&, const lumiera::Query&); /** remove the defaults registration of the given object, if there was such * @return false if nothing has been changed because the object wasn't registered */ template - bool forget (const shared_ptr&); + bool forget (const P&); // Q: can we have something along the line of...? diff --git a/src/proc/mobject/session/defsregistry.hpp b/src/proc/mobject/session/defsregistry.hpp index 4aca10868..7d7589110 100644 --- a/src/proc/mobject/session/defsregistry.hpp +++ b/src/proc/mobject/session/defsregistry.hpp @@ -28,6 +28,7 @@ #include "common/multithread.hpp" #include "common/query.hpp" #include "common/util.hpp" +#include "common/p.hpp" #include #include @@ -41,10 +42,10 @@ namespace mobject { namespace session { - using std::tr1::shared_ptr; - using std::tr1::weak_ptr; - using lumiera::Thread; + using lumiera::P; using lumiera::Query; + using lumiera::Thread; + using std::tr1::weak_ptr; using std::string; using boost::format; @@ -60,7 +61,7 @@ namespace mobject /** we maintain an independent defaults registry * for every participating kind of objects */ - typedef std::vector > Table; + typedef std::vector< P > Table; uint maxSlots (0); ///< number of different registered Types @@ -76,7 +77,7 @@ namespace mobject Query query; weak_ptr objRef; - Record (const Query& q, const shared_ptr& obj) + Record (const Query& q, const P& obj) : degree (lumiera::query::countPraed (q)), query (q), objRef (obj) @@ -85,15 +86,15 @@ namespace mobject struct Search ///< Functor searching for a specific object { - Search (const shared_ptr& obj) + Search (const P& obj) : obj_(obj) { } - const shared_ptr& obj_; + const P& obj_; bool operator() (const Record& rec) { - shared_ptr storedObj (rec.objRef.lock()); + P storedObj (rec.objRef.lock()); return storedObj && (storedObj == obj_); } }; @@ -110,7 +111,7 @@ namespace mobject }; operator string () const { return str (dumpRecord % degree % query % dumpObj()); } - string dumpObj () const { shared_ptr o (objRef.lock()); return o? string(*o):"dead"; } + string dumpObj () const { P o (objRef.lock()); return o? string(*o):"dead"; } }; /** every new kind of object (Type) creates a new @@ -186,7 +187,7 @@ namespace mobject typedef typename Slot::Registry::iterator II; II p,i,e; - shared_ptr next, ptr; + P next, ptr; Iter (II from, II to) ///< just ennumerates the given range : p(from), i(from), e(to) @@ -201,7 +202,7 @@ namespace mobject operator++ (); // init to first element (or to null if emty) } - shared_ptr findNext () throw() + P findNext () throw() { while (!next) { @@ -214,9 +215,9 @@ namespace mobject public: - shared_ptr operator* () { return ptr; } - bool hasNext () { return next || findNext(); } - Iter operator++ (int) { Iter tmp=*this; operator++(); return tmp; } + P operator* () { return ptr; } + bool hasNext () { return next || findNext(); } + Iter operator++ (int) { Iter tmp=*this; operator++(); return tmp; } Iter& operator++ () { ptr=findNext(); @@ -237,7 +238,7 @@ namespace mobject template Iter candidates (const Query& query) { - shared_ptr dummy; + P dummy; Record entry (query, dummy); typedef typename Slot::Registry Registry; Registry& registry = Slot::access(table_); @@ -261,7 +262,7 @@ namespace mobject * case, also the param obj shared-ptr is rebound! */ template - bool put (shared_ptr& obj, const Query& query) + bool put (P& obj, const Query& query) { Record entry (query, obj); typedef typename Slot::Registry Registry; @@ -272,7 +273,7 @@ namespace mobject if ( pos!=registry.end() && pos->query == query) { - shared_ptr storedObj (pos->objRef.lock()); + P storedObj (pos->objRef.lock()); if (storedObj) return (storedObj == obj); else @@ -290,7 +291,7 @@ namespace mobject * @return false if the object wasn't registered at all. */ template - bool forget (const shared_ptr& obj) + bool forget (const P& obj) { typedef typename Slot::Registry Registry; typedef typename Record::Search SearchFunc; 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/locatingpin.hpp b/src/proc/mobject/session/locatingpin.hpp index f978d4f4e..ecd82ab30 100644 --- a/src/proc/mobject/session/locatingpin.hpp +++ b/src/proc/mobject/session/locatingpin.hpp @@ -111,9 +111,12 @@ namespace mobject virtual LocatingPin* clone () const; virtual ~LocatingPin() {}; - protected: +// protected: LocatingPin () {}; +//TODO (for working out the buildable interface; ctor should be protected) +protected: + friend class Placement; /** 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/mobjectfactory.hpp b/src/proc/mobject/session/mobjectfactory.hpp index cff884ca7..427385194 100644 --- a/src/proc/mobject/session/mobjectfactory.hpp +++ b/src/proc/mobject/session/mobjectfactory.hpp @@ -45,7 +45,7 @@ namespace mobject class Track; class Effect; - typedef shared_ptr PTrackAsset; + typedef P PTrackAsset; class MObjectFactory diff --git a/src/proc/mobject/session/track.hpp b/src/proc/mobject/session/track.hpp index 2b8f090b9..f8b2c0017 100644 --- a/src/proc/mobject/session/track.hpp +++ b/src/proc/mobject/session/track.hpp @@ -34,11 +34,13 @@ namespace mobject { namespace session { + using lumiera::P; + class Track; typedef asset::Track TrackAsset; - typedef shared_ptr PTrack; - typedef shared_ptr PTrackAsset; + typedef P PTrack; + typedef P PTrackAsset; /** @@ -81,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/src/tool/try.cpp b/src/tool/try.cpp index 90bdfadf8..85a3286a0 100644 --- a/src/tool/try.cpp +++ b/src/tool/try.cpp @@ -8,25 +8,236 @@ // 1/08 - working out a static initialisation problem for Visitor (Tag creation) // 1/08 - check 64bit longs // 4/08 - comparison operators on shared_ptr +// 4/08 - conversions on the value_type used for boost::any +// 5/08 - how to guard a downcasting access, so it is compiled in only if the involved types are convertible #include #include #include +#include +#include +#include +#include +#include +#include using std::string; using std::cout; +using std::ostream; + + + 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() + { + cout << " NULL() " << __PRETTY_FUNCTION__ <<"\n"; + return X(); + } + }; + template + struct EmptyVal + { + static X*& create() + { + cout << " NULL & " << __PRETTY_FUNCTION__ <<"\n"; + static X* null(0); + return null; + } + }; + + + 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) + { + cout << " dynamic " << __PRETTY_FUNCTION__ <<"\n"; + return dynamic_cast (elem); + } + + template + static typename enable_if< use_static_downcast, TAR>::type + access (ELM& elem) + { + cout << " static " << __PRETTY_FUNCTION__ <<"\n"; + return static_cast (elem); + } + + template + static typename enable_if< use_conversion, TAR>::type + access (ELM& elem) + { + cout << " convert " << __PRETTY_FUNCTION__ <<"\n"; + return elem; + } + + }; -int main (int argc, char* argv[]) +struct B {}; +struct D : B {}; + +struct E : D + { + virtual ~E() {}; + }; +struct F : E {}; + + +ostream& operator<< (ostream& s, const B& b) { return s << "B{} adr="<<&b; } +ostream& operator<< (ostream& s, const D& d) { return s << "D{} adr="<<&d; } +ostream& operator<< (ostream& s, const E& e) { return s << "E{} adr="<<&e; } +ostream& operator<< (ostream& s, const F& f) { return s << "F{} adr="<<&f; } + +int +main (int argc, char* argv[]) { NOBUG_INIT; + D d; + D* pD =&d; + B* pB =pD; + D& rD = *pD; + B& rB = *pB; + + D*& rpD = pD; + B*& rpB = pB; + + F f; + E& rE = f; + E* pE = &f; + D* pDE = pE; + + cout << "is_base_of = " << is_base_of::value << "\n"; + cout << "is_base_of = " << is_base_of::value << "\n"; + cout << "is_base_of = " << is_base_of::value << "\n"; + + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + + cout << "can_cast = " << can_cast::value << "\n"; + cout << "can_cast = " << can_cast::value << "\n"; + + cout << "has_RTTI = " << has_RTTI::value << "\n"; + cout << "has_RTTI = " << has_RTTI::value << "\n"; + cout << "has_RTTI = " << has_RTTI::value << "\n"; + + + cout << "use_dynamic_downcast = " << use_dynamic_downcast::value << "\n"; + cout << "use_static_downcast = " << use_static_downcast::value << "\n"; + cout << "use_conversion = " << use_conversion::value << "\n"; + + cout << "use_static_downcast = " << use_static_downcast::value << "\n"; + cout << "use_static_downcast = " << use_static_downcast::value << "\n"; + cout << "use_dynamic_downcast = " << use_dynamic_downcast::value << "\n"; + + + cout << "Access(D as D&) --->" << AccessCasted::access(d) << "\n"; + cout << "Access(D& as D&) --->" << AccessCasted::access(rD) << "\n"; + cout << "Access(B& as D&) --->" << AccessCasted::access(rB) << "\n"; + cout << "Access(D* as D*) --->" << AccessCasted::access(pD) << "\n"; + cout << "Access(B* as D*) --->" << AccessCasted::access(pB) << "\n"; + cout << "Access(D*& as D*&) --->" << AccessCasted::access(rpD) << "\n"; + cout << "Access(B*& as D*&) --->" << AccessCasted::access(rpB) << "\n"; + + cout << "Access(D as B&) --->" << AccessCasted::access(d) << "\n"; + cout << "Access(D& as B&) --->" << AccessCasted::access(rD) << "\n"; + cout << "Access(B& as B&) --->" << AccessCasted::access(rB) << "\n"; + cout << "Access(D* as B*) --->" << AccessCasted::access(pD) << "\n"; + cout << "Access(B* as B*) --->" << AccessCasted::access(pB) << "\n"; + cout << "Access(D*& as B*&) --->" << AccessCasted::access(rpD) << "\n"; + cout << "Access(B*& as B*&) --->" << AccessCasted::access(rpB) << "\n"; + + cout << "Access(D as E&) --->" << AccessCasted::access(d) << "\n"; + cout << "Access(E& as F&) --->" << AccessCasted::access(rE) << "\n"; + cout << "Access(D(E)* as E*) --->" << AccessCasted::access(pDE) << "\n"; + cout << "Access(D(E)* as F*) --->" << AccessCasted::access(pDE) << "\n"; + cout << "Access(E* as F*) --->" << AccessCasted::access(pE) << "\n"; + cout << "\ngulp\n"; 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 < @@ -22,63 +22,127 @@ #include "common/test/run.hpp" + #include "proc/mobject/builder/buildertool.hpp" +#include "proc/mobject/placement.hpp" #include "proc/asset/category.hpp" #include "proc/asset/media.hpp" #include "proc/mobject/session/clip.hpp" +#include "common/util.hpp" #include + +using util::cStr; using std::string; using std::cout; -namespace mobject - { - namespace builder - { - namespace test - { + +namespace mobject { + namespace builder { + namespace test { using session::Clip; using session::AbstractMO; - - class DummyMO : public AbstractMO + + + /** + * 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;} + TestMO() { }; + + DEFINE_PROCESSABLE_BY (BuilderTool); + + virtual bool isValid() const { return true;} + static void killDummy (MObject* dum) { delete (TestMO*)dum; } + }; + + /** + * 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); }; - - class TestTool - : public Applicable::List> + + + template + class TestPlacement : public Placement { public: - void treat (Clip& c) { cout << "media is: "<< str(c.getMedia()) <<"\n"; } - void treat (AbstractMO&){ cout << "unspecific MO.\n"; } - void onUnknown (Buildable&){ cout << "catch-all-function called.\n"; } + TestPlacement(TestMO& testObject) + : Placement::Placement(testObject, &TestMO::killDummy) + { } }; - - - /******************************************************************* - * @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 + /** + * 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 Applicable::List> + { + public: + string log_; + + void treat (Clip& c) + { + Placement& pC = getPlacement(); + cout << "Clip on media : "<< str(pC->getMedia()) <<"\n"; + log_ = string (pC); + } + void treat (AbstractMO&) + { + cout << "treat (AbstractMO&);\n"; + log_ = string (getPlacement()); + } + void onUnknown (Buildable& bxx) + { + cout << "catch-all-function called...\n"; + log_ = string (getPlacement()); + } + }; + + + + + + + /************************************************************************************* + * @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 { @@ -86,13 +150,27 @@ namespace mobject { TestTool t1; - BuilderTool& tool (t1); + BuilderTool& tool = t1; - DummyMO dumm; - PMO clip = asset::Media::create("test-1", asset::VIDEO)->createClip(); + Placement clip = asset::Media::create("test-1", asset::VIDEO)->createClip(); + TestPlacement test1(*new TestSubMO1); + TestPlacement test2(*new TestSubMO2); + - clip->apply (tool); - dumm.apply (tool); + cout << "apply (tool, clip);\n"; + apply (tool, clip); + 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)); } }; @@ -105,5 +183,5 @@ namespace mobject } // namespace test } // namespace builder - + } // namespace mobject diff --git a/tests/components/proc/mobject/session/defsregistryimpltest.cpp b/tests/components/proc/mobject/session/defsregistryimpltest.cpp index 0aae90b3a..e605880a1 100644 --- a/tests/components/proc/mobject/session/defsregistryimpltest.cpp +++ b/tests/components/proc/mobject/session/defsregistryimpltest.cpp @@ -27,6 +27,7 @@ #include "proc/mobject/session/defsregistry.hpp" #include "common/factory.hpp" #include "common/query.hpp" +#include "common/p.hpp" #include "../common/query/querydiagnostics.hpp" @@ -35,11 +36,11 @@ #include #include +using lumiera::P; using lumiera::Query; using lumiera::query::test::garbage_query; using util::isnil; -using std::tr1::shared_ptr; using boost::scoped_ptr; using boost::format; using std::string; @@ -75,7 +76,9 @@ namespace mobject { static string name; string instanceID; - operator string () const { return instanceID; } + operator string () const { return instanceID; } + bool operator== (const Dummy& odu) const { return this == &odu; } + Dummy () : instanceID (newID (name)) {} }; @@ -99,8 +102,8 @@ namespace mobject { scoped_ptr reg_; - typedef shared_ptr > O; - typedef shared_ptr > P; + typedef P > O; + typedef P > P; typedef Query > Q13; typedef Query > Q23;