Refactorings regarding use of smart-ptr, Placement and BuilderTool

This commit is contained in:
Fischlurch 2008-05-19 08:46:19 +02:00
parent 3e8996005e
commit 6b1be6b7e7
49 changed files with 1329 additions and 236 deletions

168
src/common/accesscasted.hpp Normal file
View file

@ -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 <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file 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<TAR>, we get a template static function
** \c AcessCasted<TAR>::access<SRC>(SRC& elm), but the actual implementation
** is choosed using boost::type_traits. If no viable implementatino can be
** selected, \c EmptyVal<TAR>::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 <boost/utility/enable_if.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_polymorphic.hpp>
#include <boost/type_traits/is_base_of.hpp>
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 <typename SRC, typename TAR>
struct can_cast : boost::false_type {};
template <typename SRC, typename TAR>
struct can_cast<SRC*,TAR*> { enum { value = is_base_of<SRC,TAR>::value };};
template <typename SRC, typename TAR>
struct can_cast<SRC*&,TAR*> { enum { value = is_base_of<SRC,TAR>::value };};
template <typename SRC, typename TAR>
struct can_cast<SRC&,TAR&> { enum { value = is_base_of<SRC,TAR>::value };};
template <typename T>
struct has_RTTI
{
typedef typename remove_pointer<
typename remove_reference<T>::type>::type TPlain;
enum { value = is_polymorphic<TPlain>::value };
};
template <typename SRC, typename TAR>
struct use_dynamic_downcast
{
enum { value = can_cast<SRC,TAR>::value
&& has_RTTI<SRC>::value
&& has_RTTI<TAR>::value
};
};
template <typename SRC, typename TAR>
struct use_static_downcast
{
enum { value = can_cast<SRC,TAR>::value
&& ( !has_RTTI<SRC>::value
|| !has_RTTI<TAR>::value
)
};
};
template <typename SRC, typename TAR>
struct use_conversion
{
enum { value = is_convertible<SRC,TAR>::value
&& !( use_static_downcast<SRC,TAR>::value
||use_dynamic_downcast<SRC,TAR>::value
)
};
};
template<typename X>
struct EmptyVal
{
static X create() { return X(); }
};
template<typename X>
struct EmptyVal<X*&>
{
static X*& create() { static X* nullP(0); return nullP; }
};
template<typename RET>
struct NullAccessor
{
typedef RET Ret;
static RET access (...) { return ifEmpty(); }
static RET ifEmpty () { return EmptyVal<RET>::create(); }
};
template<typename TAR>
struct AccessCasted : NullAccessor<TAR>
{
using NullAccessor<TAR>::access;
template<typename ELM>
static typename enable_if< use_dynamic_downcast<ELM&,TAR>, TAR>::type
access (ELM& elem)
{
return dynamic_cast<TAR> (elem);
}
template<typename ELM>
static typename enable_if< use_static_downcast<ELM&,TAR>, TAR>::type
access (ELM& elem)
{
return static_cast<TAR> (elem);
}
template<typename ELM>
static typename enable_if< use_conversion<ELM&,TAR>, TAR>::type
access (ELM& elem)
{
return elem;
}
};
} // namespace util
#endif

View file

@ -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 <string>
#include <tr1/memory>
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<TY>& solution, const Query<TY>& q) = 0;
virtual bool resolve (P<TY>& solution, const Query<TY>& 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<Pipe> but a Placement<Track>, using the appropriate factory.
// e.g. return a P<Pipe> but a Placement<Track>, using the appropriate factory.
// Of course then the definitions need to be split up in separate headers.

View file

@ -74,7 +74,7 @@ namespace lumiera
/** a traits-class to define the smart-ptr to wrap the result */
template<class TY>
struct WrapReturn { typedef shared_ptr<TY> Wrapper; };
struct WrapReturn { typedef P<TY> Wrapper; };
template<>
struct WrapReturn<ProcPatt> { typedef PProcPatt Wrapper; };

View file

@ -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<TYPES,_X_> Next;
typedef InstantiateChained<TYPES,_X_,BASE> Next;
typedef _X_<TY,Next> 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,class,uint> 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,class,uint> class _X_
, class BASE
, uint i
>
class InstantiateWithIndex<NullType, _X_, BASE, i>
: public BASE
{
public:
typedef BASE Unit;
typedef NullType Next;
enum{ COUNT = i };
};
template
< class TY, typename TYPES
, template<class,class,uint> class _X_
, class BASE
, uint i
>
class InstantiateWithIndex<Node<TY, TYPES>, _X_, BASE, i>
: public _X_< TY
, InstantiateWithIndex<TYPES, _X_, BASE, i+1 >
, i
>
{
public:
typedef InstantiateWithIndex<TYPES,_X_,BASE,i+1> Next;
typedef _X_<TY,Next,i> Unit;
enum{ COUNT = Next::COUNT };
};
/**
* Metafunction counting the number of Types in the collection
*/
template<class TYPES>
struct count;
template<>
struct count<NullType>
{
enum{ value = 0 };
};
template<class TY, class TYPES>
struct count<Node<TY,TYPES> >
{
enum{ value = 1 + count<TYPES>::value };
};
/**
* Metafunction " max( sizeof(T) ) for T in TYPES "
*/
template<class TYPES>
struct maxSize;
template<>
struct maxSize<NullType>
{
enum{ value = 0 };
};
template<class TY, class TYPES>
struct maxSize<Node<TY,TYPES> >
{
enum{ thisval = sizeof(TY)
, nextval = maxSize<TYPES>::value
, value = nextval > thisval? nextval:thisval
};
};
} // namespace typelist
} // namespace lumiera

276
src/common/variant.hpp Normal file
View file

@ -0,0 +1,276 @@
/*
VARIANT.hpp - simple variant wrapper (typesafe union)
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @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 <b>not threadsafe</b>.
**
** Values can be stored using \c operator= . In order to access the value
** stored in lumiera::Variant, you additionally need to define a "functor"
** <ul><li>with a typedef "Ret" for the return type</li>
** <li>providing a <tt>static Ret access(ELM&)</tt> function
** for each of the types used in the Variant</li>
** </ul>
**
** @see wrapperptr.hpp usage example
*/
#ifndef LUMIERA_VARIANT_H
#define LUMIERA_VARIANT_H
#include "common/typelistutil.hpp"
#include <boost/noncopyable.hpp>
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<typename TYPES>
struct Holder
{
enum { TYPECNT = count<TYPES>::value
, SIZE = maxSize<TYPES>::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<typename T, class BASE, uint idx>
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<class FUNCTOR>
struct CaseSelect
{
typedef typename FUNCTOR::Ret Ret;
typedef Ret (*Func)(Buffer&);
Func table_[TYPECNT];
CaseSelect ()
{
for (uint i=0; i<TYPECNT; ++i)
table_[i] = 0;
}
template<typename T>
static Ret
trampoline (Buffer& storage)
{
T& content = reinterpret_cast<T&> (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<T>;
}
};
template<class FUNCTOR>
static typename FUNCTOR::Ret
access (Buffer& buf)
{
typedef InstantiateWithIndex< TYPES
, CasePrepare
, CaseSelect<FUNCTOR>
>
Accessor;
static Accessor select_case;
return select_case.invoke(buf);
}
struct Deleter
{
typedef void Ret;
template<typename T>
static void access (T& elem) { elem.~T(); }
static void ifEmpty () { }
};
};
template<typename TYPES>
inline void
Holder<TYPES>::Buffer::deleteCurrent ()
{
access<Deleter>(*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 <b>not threadsafe</b>
*
* @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<typename> class Access
>
class Variant
: boost::noncopyable
{
typedef variant::Holder<TYPES> 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<typename SRC>
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<typename TAR>
TAR
get ()
{
typedef Access<TAR> Extractor;
return Holder::template access<Extractor> (this->holder_);
}
};
} // namespace lumiera
#endif

View file

@ -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 */

View file

@ -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)
**
*/

63
src/common/wrapperptr.hpp Normal file
View file

@ -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 <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef 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<mobject::MObject>*
, P<asset::Asset>*
> ::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<T>: when retrieving
* a pointer, in case of mismatch NULL is returned.
*/
typedef lumiera::Variant<WrapperTypes, util::AccessCasted> WrapperPtr;
} // namespace lumiera
#endif

View file

@ -41,12 +41,13 @@ using std::string;
namespace asset
{
using lumiera::P;
class Proc;
class ProcPatt;
typedef shared_ptr<const asset::Proc> PProc;
typedef shared_ptr<const asset::ProcPatt> PProcPatt;
typedef P<const asset::Proc> PProc;
typedef P<const asset::ProcPatt> PProcPatt;
static Symbol CURRENT = "current";

View file

@ -53,7 +53,7 @@ namespace asset
};
typedef shared_ptr<const asset::Clip> PClipAsset;
typedef P<const asset::Clip> PClipAsset;
const string CLIP_SUBFOLDER = "clips"; // TODO: handling of hard-wired constants....

View file

@ -100,7 +100,7 @@ namespace asset
bool del (ID<Asset> hash) { return table.erase (hash); }
template<class KIND>
shared_ptr<KIND>
P<KIND>
get (ID<KIND> hash) const
{
return dynamic_pointer_cast<KIND,Asset> (find (hash));

View file

@ -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<asset::Clip>
P<asset::Clip>
MediaFactory::operator() (asset::Media& mediaref) throw(lumiera::error::Invalid)
{
if (mediaref.checkCompound())

View file

@ -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<Media> PMedia;
typedef shared_ptr<asset::Clip> PClip;
typedef shared_ptr<asset::ProcPatt> PProcPatt;
typedef P<Media> PMedia;
typedef P<asset::Clip> PClip;
typedef P<asset::ProcPatt> PProcPatt;
typedef mobject::session::PClipMO PClipMO;
@ -142,7 +143,7 @@ namespace asset
class MediaFactory : public lumiera::Factory<asset::Media>
{
public:
typedef shared_ptr<asset::Media> PType;
typedef P<asset::Media> 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<asset::Clip>
P<asset::Clip>
operator() (asset::Media& mediaref) throw(lumiera::error::Invalid);
};

View file

@ -95,7 +95,7 @@ namespace asset
class MetaFactory : public lumiera::Factory<asset::Meta>
{
public:
typedef shared_ptr<asset::Meta> PType;
typedef P<asset::Meta> PType;
PType operator() (Asset::Ident& key); ////////////TODO define actual operation

View file

@ -31,9 +31,10 @@
namespace asset
{
using lumiera::P;
class Pipe;
typedef shared_ptr<Pipe> PPipe;
typedef P<Pipe> PPipe;
template<>

View file

@ -48,7 +48,7 @@ namespace asset
class Proc;
class ProcFactory;
typedef shared_ptr<const Proc> PProc;
typedef P<const Proc> PProc;
@ -97,7 +97,7 @@ namespace asset
class ProcFactory : public lumiera::Factory<asset::Proc>
{
public:
typedef shared_ptr<asset::Proc> PType;
typedef P<asset::Proc> PType;
PType operator() (Asset::Ident& key); ////////////TODO define actual operation

View file

@ -60,7 +60,7 @@ namespace asset
* some ProcPatt as a template for creating more
* spezialized patterns.
*/
shared_ptr<ProcPatt>
P<ProcPatt>
ProcPatt::newCopy (string newID) const
{
TODO ("implement the Pattern-ID within the propDescriptor!");

View file

@ -35,13 +35,14 @@ using std::vector;
namespace asset
{
using lumiera::P;
using lumiera::Symbol;
class Proc;
class ProcPatt;
class BuildInstruct;
typedef shared_ptr<const asset::Proc> PProc;
typedef shared_ptr<const asset::ProcPatt> PProcPatt;
typedef P<const asset::Proc> PProc;
typedef P<const asset::ProcPatt> PProcPatt;
typedef vector<BuildInstruct> InstructionSequence;
@ -61,14 +62,13 @@ namespace asset
friend class StructFactoryImpl;
public:
shared_ptr<ProcPatt> newCopy (string newID) const;
P<ProcPatt> newCopy (string newID) const;
ProcPatt& attach (Symbol where, PProc& node);
ProcPatt& operator+= (PProcPatt& toReuse);
};
typedef shared_ptr<const asset::ProcPatt> PProcPatt;

View file

@ -89,10 +89,10 @@ namespace asset
* created as a side effect of calling the concrete Struct subclass ctor.
*/
template<class STRU>
shared_ptr<STRU>
P<STRU>
StructFactory::operator() (const Query<STRU>& capabilities)
{
shared_ptr<STRU> res;
P<STRU> res;
QueryHandler<STRU>& typeHandler = ConfigRules::instance();
typeHandler.resolve (res, capabilities);
@ -117,7 +117,7 @@ namespace asset
* @see ProcPatt
* @see DefaultsManager
*/
shared_ptr<Pipe>
P<Pipe>
StructFactory::operator() (string pipeID, string streamID)
{
normalizeID (pipeID);
@ -147,9 +147,9 @@ namespace asset
namespace asset
{
template shared_ptr<Pipe> StructFactory::operator() (const Query<Pipe>& query);
template shared_ptr<Track> StructFactory::operator() (const Query<Track>& query);
template PProcPatt StructFactory::operator() (const Query<const ProcPatt>& query);
template P<Pipe> StructFactory::operator() (const Query<Pipe>& query);
template P<Track> StructFactory::operator() (const Query<Track>& query);
template PProcPatt StructFactory::operator() (const Query<const ProcPatt>& query);
} // namespace asset

View file

@ -120,12 +120,12 @@ namespace asset
public:
typedef shared_ptr<asset::Struct> PType;
typedef P<asset::Struct> PType;
template<class STRU>
shared_ptr<STRU> operator() (const Query<STRU>& query); ////////////TODO actually do something sensible here
P<STRU> operator() (const Query<STRU>& query); ////////////TODO actually do something sensible here
shared_ptr<Pipe> operator() (string pipeID, string streamID);
P<Pipe> operator() (string pipeID, string streamID);
};

View file

@ -48,7 +48,7 @@ namespace asset
};
typedef shared_ptr<const Track> PTrack;
typedef P<const Track> PTrack;

View file

@ -130,11 +130,11 @@ namespace asset
* of the stored object differs and can't be casted.
*/
template<class KIND>
shared_ptr<KIND>
P<KIND>
AssetManager::getAsset (const ID<KIND>& id)
throw(lumiera::error::Invalid)
{
if (shared_ptr<KIND> obj = registry.get (id))
if (P<KIND> 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<Asset>), the call to registry.get()
* can bypass the dynamic cast, because the type of the asset
* is explicitely given by type KIND.
*/
template<class KIND>
shared_ptr<KIND>
P<KIND>
AssetManager::wrap (const KIND& asset)
{
ENSURE (instance().known(asset.id),
@ -169,7 +169,7 @@ namespace asset
{
return ( registry.get (ID<Asset>(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<Asset> AssetManager::reg (Asset* obj, const Asset::Ident& idi);
template shared_ptr<Asset> AssetManager::getAsset (const ID<Asset>& id) throw(lumiera::error::Invalid);
template shared_ptr<Media> AssetManager::getAsset (const ID<Media>& id) throw(lumiera::error::Invalid);
template shared_ptr<Proc> AssetManager::getAsset (const ID<Proc>& id) throw(lumiera::error::Invalid);
template shared_ptr<Struct> AssetManager::getAsset (const ID<Struct>& id) throw(lumiera::error::Invalid);
template shared_ptr<Meta> AssetManager::getAsset (const ID<Meta>& id) throw(lumiera::error::Invalid);
template P<Asset> AssetManager::getAsset (const ID<Asset>& id) throw(lumiera::error::Invalid);
template P<Media> AssetManager::getAsset (const ID<Media>& id) throw(lumiera::error::Invalid);
template P<Proc> AssetManager::getAsset (const ID<Proc>& id) throw(lumiera::error::Invalid);
template P<Struct> AssetManager::getAsset (const ID<Struct>& id) throw(lumiera::error::Invalid);
template P<Meta> AssetManager::getAsset (const ID<Meta>& id) throw(lumiera::error::Invalid);
template shared_ptr<Asset> AssetManager::wrap (const Asset& asset);
template shared_ptr<Media> AssetManager::wrap (const Media& asset);
template shared_ptr<Clip> AssetManager::wrap (const Clip& asset);
template shared_ptr<Track> AssetManager::wrap (const Track& asset);
template shared_ptr<Pipe> AssetManager::wrap (const Pipe& asset);
template shared_ptr<ProcPatt> AssetManager::wrap (const ProcPatt& asset);
template P<Asset> AssetManager::wrap (const Asset& asset);
template P<Media> AssetManager::wrap (const Media& asset);
template P<Clip> AssetManager::wrap (const Clip& asset);
template P<Track> AssetManager::wrap (const Track& asset);
template P<Pipe> AssetManager::wrap (const Pipe& asset);
template P<ProcPatt> AssetManager::wrap (const ProcPatt& asset);
} // namespace asset

View file

@ -73,13 +73,13 @@ namespace asset
/** provide the unique ID for given Asset::Ident tuple */
static ID<Asset> getID (const Asset::Ident&);
/** retrieve the registerd shared_ptr for any asset */
/** retrieve the registerd smart-ptr for any asset */
template<class KIND>
static shared_ptr<KIND> wrap (const KIND& asset);
static P<KIND> wrap (const KIND& asset);
/** find and return corresponging object */
template<class KIND>
shared_ptr<KIND> getAsset (const ID<KIND>& id) throw(lumiera::error::Invalid);
P<KIND> getAsset (const ID<KIND>& id) throw(lumiera::error::Invalid);
/** @return true if the given id is registered in the internal asset DB */

View file

@ -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

View file

@ -0,0 +1,70 @@
/*
ApplicableBuilderTargetTypes - definitinon header specifying all types treated by builder tools
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#ifndef MOBJECT_BUILDER_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 VAL> 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<class TOOL>
struct ApplicableBuilderTargetTypes
: Applicable<TOOL, BuilderTargetTypes>
{ };
} // namespace mobject::builder
} // namespace mobject
#endif

View file

@ -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.
** <ul><li>each concrete Buildable subtype to be treated specifically needs to
** declare \c DEFINE_PROCESSABLE_BY(BuilderTool) </li>
** <li>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</li>
** <li>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.</li>
** </ul>
**
** @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 <b>not threadsafe</b> and <b>not reentrant</b>,
* as we simply store a pointer within the BuilderTool instance.
*/
typedef lumiera::visitor::Tool<void, InvokeCatchAllFunction> BuilderTool;
class BuilderTool
: public lumiera::visitor::Tool<void, InvokeCatchAllFunction>
{
lumiera::WrapperPtr currentWrapper_;
public:
template<template<class> class WRA, class TAR>
void rememberWrapper (WRA<TAR>* ptr_toWrappedTarget)
{
currentWrapper_ = ptr_toWrappedTarget;
}
void forgetWrapper ()
{
currentWrapper_.reset();
}
protected: /* == interface for accessing the wrapper from within tool application == */
template<class TAR>
Placement<TAR>&
getPlacement ()
{
Placement<TAR>* pPlacement = currentWrapper_.get<Placement<TAR>*>();
ENSURE (pPlacement, "wrong target type when invoking %s", __PRETTY_FUNCTION__);
return *pPlacement;
}
ExplicitPlacement
getExplicitPlacement ()
{
return getPlacement<MObject>().resolve();
}
template<class TAR>
lumiera::P<TAR>
getPtr ()
{
P<TAR>* pP = currentWrapper_.get<P<TAR>*>();
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<builder::BuilderTool>
{ };
namespace builder { // to be found by ADL
template<typename WRA>
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

View file

@ -31,11 +31,8 @@ using mobject::session::Clip;
using mobject::session::Effect;
using mobject::session::Auto;
namespace mobject
{
namespace builder
{
namespace mobject {
namespace builder {

View file

@ -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 VAL> 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<NodeCreatorTool>
{
//////////////////////////////////////////////TODO: switch to acyclic visitior!!!!!!!!!!!!!
public:
virtual void treat (mobject::session::Clip& clip) ;
virtual void treat (mobject::session::Effect& effect) ;

View file

@ -31,10 +31,8 @@ using mobject::session::Clip;
using mobject::session::Effect;
namespace mobject
{
namespace builder
{
namespace mobject {
namespace builder {

View file

@ -24,26 +24,18 @@
#ifndef MOBJECT_BUILDER_SEGMENTATIONTOOL_H
#define MOBJECT_BUILDER_SEGMENTATIONTOOL_H
#include <list>
#include "proc/mobject/builder/buildertool.hpp"
#include "proc/mobject/builder/applicablebuildertargettypes.hpp"
#include "proc/mobject/session/segment.hpp"
#include <list>
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<SegmentationTool>
{
//////////////////////////////////////////////TODO: switch to acyclic visitior!!!!!!!!!!!!!
public:
void treat (mobject::session::Clip& clip) ;

View file

@ -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<Time,Pipe> 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

View file

@ -26,17 +26,18 @@
#include "pre.hpp"
#include <list>
#include <tr1/memory>
#include "proc/lumiera.hpp"
#include "proc/mobject/builder/buildertool.hpp"
#include "proc/mobject/placement.hpp"
#include "proc/asset.hpp" // TODO finally not needed?
#include <boost/noncopyable.hpp>
#include <boost/operators.hpp>
#include <list>
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<MObject> PMO;

View file

@ -23,25 +23,39 @@
#include "proc/mobject/placement.hpp"
#include "proc/mobject/explicitplacement.hpp"
#include "proc/mobject/mobject.hpp"
#include <boost/format.hpp>
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<MObject>, so they
* will inherit this function.
*/
template<>
template<class MO>
ExplicitPlacement
Placement<MObject>::resolve () const
Placement<MO>::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<MObject>,
* so they will inherit this function.
*/
template ExplicitPlacement Placement<MObject>::resolve() const;
template<>
Placement<MObject>::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

View file

@ -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 <tr1/memory>
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<MO>
{
protected:
typedef shared_ptr<MO> Base;
typedef lumiera::Time Time;
typedef asset::shared_ptr<asset::Pipe> Pipe;
@ -99,13 +99,14 @@ namespace mobject
operator-> () const
{
ENSURE (*this);
return shared_ptr<MO>::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<MObject> PMO;
/* === defining specialisations to be subclasses === */
#define DEFINE_SPECIALIZED_PLACEMENT(SUBCLASS) \
#define DEFINE_SPECIALIZED_PLACEMENT(SUBCLASS, BASE) \
template<> \
class Placement<SUBCLASS> : public Placement<MObject> \
class Placement<SUBCLASS> : public Placement<BASE> \
{ \
protected: \
Placement (SUBCLASS & m, void (*moKiller)(MObject*)) \
: Placement<MObject>::Placement (m, moKiller) \
: Placement<BASE>::Placement (m, moKiller) \
{ }; \
friend class session::MObjectFactory; \
\
@ -154,7 +154,6 @@ namespace mobject
(shared_ptr<MObject>::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<MObject>!

View file

@ -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

View file

@ -49,6 +49,8 @@ namespace mobject
DEFINE_PROCESSABLE_BY (builder::BuilderTool);
virtual bool operator== (const MObject& oo) const;
};

View file

@ -38,8 +38,8 @@ namespace mobject
namespace session
{
using asset::Media;
typedef shared_ptr<Media> PMedia;
typedef shared_ptr<asset::Clip> PClipAsset;
typedef P<Media> PMedia;
typedef P<asset::Clip> 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<Clip> defined to be subclass of Placement<MObject> */
DEFINE_SPECIALIZED_PLACEMENT (session::Clip);
DEFINE_SPECIALIZED_PLACEMENT (session::Clip, MObject);
} // namespace mobject

View file

@ -39,7 +39,7 @@ namespace mobject
{
namespace session
{
using std::tr1::shared_ptr;
using lumiera::P;
@ -52,10 +52,10 @@ namespace mobject
template<class TAR>
shared_ptr<TAR>
P<TAR>
DefsManager::search (const Query<TAR>& capabilities)
{
shared_ptr<TAR> res;
P<TAR> res;
QueryHandler<TAR>& typeHandler = ConfigRules::instance();
for (DefsRegistry::Iter<TAR> i = defsRegistry->candidates(capabilities);
res = *i ; ++i )
@ -69,10 +69,10 @@ namespace mobject
template<class TAR>
shared_ptr<TAR>
P<TAR>
DefsManager::create (const Query<TAR>& capabilities)
{
shared_ptr<TAR> res;
P<TAR> res;
QueryHandler<TAR>& typeHandler = ConfigRules::instance();
typeHandler.resolve (res, capabilities);
if (res)
@ -83,9 +83,9 @@ namespace mobject
template<class TAR>
bool
DefsManager::define (const shared_ptr<TAR>& defaultObj, const Query<TAR>& capabilities)
DefsManager::define (const P<TAR>& defaultObj, const Query<TAR>& capabilities)
{
shared_ptr<TAR> candidate (defaultObj);
P<TAR> candidate (defaultObj);
QueryHandler<TAR>& typeHandler = ConfigRules::instance();
typeHandler.resolve (candidate, capabilities);
if (!candidate)
@ -97,17 +97,17 @@ namespace mobject
template<class TAR>
bool
DefsManager::forget (const shared_ptr<TAR>& defaultObj)
DefsManager::forget (const P<TAR>& defaultObj)
{
return defsRegistry->forget (defaultObj);
}
template<class TAR>
shared_ptr<TAR>
P<TAR>
DefsManager::operator() (const Query<TAR>& capabilities)
{
shared_ptr<TAR> res (search (capabilities));
P<TAR> res (search (capabilities));
if (res)
return res;
else

View file

@ -25,11 +25,11 @@
#define MOBJECT_SESSION_DEFSMANAGER_H
#include "common/p.hpp"
#include "common/query.hpp"
#include <boost/scoped_ptr.hpp>
#include <boost/utility.hpp>
#include <tr1/memory>
@ -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<class TAR>
shared_ptr<TAR> operator() (const lumiera::Query<TAR>&);
P<TAR> operator() (const lumiera::Query<TAR>&);
/** search through the registered defaults, never create anything.
* @return object fulfilling the query, \c empty ptr if not found.
*/
template<class TAR>
shared_ptr<TAR> search (const lumiera::Query<TAR>&);
P<TAR> search (const lumiera::Query<TAR>&);
/** 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<class TAR>
shared_ptr<TAR> create (const lumiera::Query<TAR>&);
P<TAR> create (const lumiera::Query<TAR>&);
/** 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<class TAR>
bool define (const shared_ptr<TAR>&, const lumiera::Query<TAR>&);
bool define (const P<TAR>&, const lumiera::Query<TAR>&);
/** 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<class TAR>
bool forget (const shared_ptr<TAR>&);
bool forget (const P<TAR>&);
// Q: can we have something along the line of...?

View file

@ -28,6 +28,7 @@
#include "common/multithread.hpp"
#include "common/query.hpp"
#include "common/util.hpp"
#include "common/p.hpp"
#include <set>
#include <vector>
@ -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<shared_ptr<TableEntry> > Table;
typedef std::vector< P<TableEntry> > Table;
uint maxSlots (0); ///< number of different registered Types
@ -76,7 +77,7 @@ namespace mobject
Query<TAR> query;
weak_ptr<TAR> objRef;
Record (const Query<TAR>& q, const shared_ptr<TAR>& obj)
Record (const Query<TAR>& q, const P<TAR>& 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<TAR>& obj)
Search (const P<TAR>& obj)
: obj_(obj) { }
const shared_ptr<TAR>& obj_;
const P<TAR>& obj_;
bool
operator() (const Record& rec)
{
shared_ptr<TAR> storedObj (rec.objRef.lock());
P<TAR> 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<TAR> o (objRef.lock()); return o? string(*o):"dead"; }
string dumpObj () const { P<TAR> 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<TAR>::Registry::iterator II;
II p,i,e;
shared_ptr<TAR> next, ptr;
P<TAR> 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<TAR> findNext () throw()
P<TAR> findNext () throw()
{
while (!next)
{
@ -214,9 +215,9 @@ namespace mobject
public:
shared_ptr<TAR> operator* () { return ptr; }
bool hasNext () { return next || findNext(); }
Iter operator++ (int) { Iter tmp=*this; operator++(); return tmp; }
P<TAR> 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<class TAR>
Iter<TAR> candidates (const Query<TAR>& query)
{
shared_ptr<TAR> dummy;
P<TAR> dummy;
Record<TAR> entry (query, dummy);
typedef typename Slot<TAR>::Registry Registry;
Registry& registry = Slot<TAR>::access(table_);
@ -261,7 +262,7 @@ namespace mobject
* case, also the param obj shared-ptr is rebound!
*/
template<class TAR>
bool put (shared_ptr<TAR>& obj, const Query<TAR>& query)
bool put (P<TAR>& obj, const Query<TAR>& query)
{
Record<TAR> entry (query, obj);
typedef typename Slot<TAR>::Registry Registry;
@ -272,7 +273,7 @@ namespace mobject
if ( pos!=registry.end()
&& pos->query == query)
{
shared_ptr<TAR> storedObj (pos->objRef.lock());
P<TAR> 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<class TAR>
bool forget (const shared_ptr<TAR>& obj)
bool forget (const P<TAR>& obj)
{
typedef typename Slot<TAR>::Registry Registry;
typedef typename Record<TAR>::Search SearchFunc;

View file

@ -51,7 +51,7 @@ namespace mobject
} // namespace mobject::session
/** Placement<Effect> defined to be subclass of Placement<MObject> */
DEFINE_SPECIALIZED_PLACEMENT (session::Effect);
DEFINE_SPECIALIZED_PLACEMENT (session::Effect, MObject);
} // namespace mobject
#endif

View file

@ -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<MObject>;
/**

View file

@ -50,7 +50,7 @@ namespace mobject
} // namespace mobject::session
/** Placement<Meta> defined to be subclass of Placement<MObject> */
DEFINE_SPECIALIZED_PLACEMENT (session::Meta);
DEFINE_SPECIALIZED_PLACEMENT (session::Meta, MObject);
} // namespace mobject
#endif

View file

@ -45,7 +45,7 @@ namespace mobject
class Track;
class Effect;
typedef shared_ptr<asset::Track> PTrackAsset;
typedef P<asset::Track> PTrackAsset;
class MObjectFactory

View file

@ -34,11 +34,13 @@ namespace mobject
{
namespace session
{
using lumiera::P;
class Track;
typedef asset::Track TrackAsset;
typedef shared_ptr<Track> PTrack;
typedef shared_ptr<TrackAsset> PTrackAsset;
typedef P<Track> PTrack;
typedef P<TrackAsset> PTrackAsset;
/**
@ -81,7 +83,7 @@ namespace mobject
} // namespace mobject::session
/** Placement<Track> defined to be subclass of Placement<MObject> */
DEFINE_SPECIALIZED_PLACEMENT (session::Track);
DEFINE_SPECIALIZED_PLACEMENT (session::Track, session::Meta);
} // namespace mobject
#endif

View file

@ -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<Asset>
// 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 <nobug.h>
#include <iostream>
#include <typeinfo>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/type_traits/is_polymorphic.hpp>
#include <boost/type_traits/is_base_of.hpp>
#include <boost/type_traits/remove_pointer.hpp>
#include <boost/type_traits/remove_reference.hpp>
#include <boost/utility/enable_if.hpp>
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 <typename SRC, typename TAR>
struct can_cast : boost::false_type {};
template <typename SRC, typename TAR>
struct can_cast<SRC*,TAR*> { enum { value = is_base_of<SRC,TAR>::value };};
template <typename SRC, typename TAR>
struct can_cast<SRC*&,TAR*> { enum { value = is_base_of<SRC,TAR>::value };};
template <typename SRC, typename TAR>
struct can_cast<SRC&,TAR&> { enum { value = is_base_of<SRC,TAR>::value };};
template <typename T>
struct has_RTTI
{
typedef typename remove_pointer<
typename remove_reference<T>::type>::type TPlain;
enum { value = is_polymorphic<TPlain>::value };
};
template <typename SRC, typename TAR>
struct use_dynamic_downcast
{
enum { value = can_cast<SRC,TAR>::value
&& has_RTTI<SRC>::value
&& has_RTTI<TAR>::value
};
};
template <typename SRC, typename TAR>
struct use_static_downcast
{
enum { value = can_cast<SRC,TAR>::value
&& ( !has_RTTI<SRC>::value
|| !has_RTTI<TAR>::value
)
};
};
template <typename SRC, typename TAR>
struct use_conversion
{
enum { value = is_convertible<SRC,TAR>::value
&& !( use_static_downcast<SRC,TAR>::value
||use_dynamic_downcast<SRC,TAR>::value
)
};
};
template<typename X>
struct EmptyVal
{
static X create()
{
cout << " NULL() " << __PRETTY_FUNCTION__ <<"\n";
return X();
}
};
template<typename X>
struct EmptyVal<X*&>
{
static X*& create()
{
cout << " NULL & " << __PRETTY_FUNCTION__ <<"\n";
static X* null(0);
return null;
}
};
template<typename RET>
struct NullAccessor
{
typedef RET Ret;
static RET access (...) { return ifEmpty(); }
static RET ifEmpty () { return EmptyVal<RET>::create(); }
};
template<typename TAR>
struct AccessCasted : NullAccessor<TAR>
{
using NullAccessor<TAR>::access;
template<typename ELM>
static typename enable_if< use_dynamic_downcast<ELM&,TAR>, TAR>::type
access (ELM& elem)
{
cout << " dynamic " << __PRETTY_FUNCTION__ <<"\n";
return dynamic_cast<TAR> (elem);
}
template<typename ELM>
static typename enable_if< use_static_downcast<ELM&,TAR>, TAR>::type
access (ELM& elem)
{
cout << " static " << __PRETTY_FUNCTION__ <<"\n";
return static_cast<TAR> (elem);
}
template<typename ELM>
static typename enable_if< use_conversion<ELM&,TAR>, 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<B,D> = " << is_base_of<B ,D >::value << "\n";
cout << "is_base_of<B*,D*> = " << is_base_of<B*,D*>::value << "\n";
cout << "is_base_of<B&,D&> = " << is_base_of<B&,D&>::value << "\n";
cout << "can_cast<B,D> = " << can_cast<B,D>::value << "\n";
cout << "can_cast<B*,D*> = " << can_cast<B*,D*>::value << "\n";
cout << "can_cast<B&,D&> = " << can_cast<B&,D&>::value << "\n";
cout << "can_cast<B&,D*> = " << can_cast<B&,D*>::value << "\n";
cout << "can_cast<B*,D&> = " << can_cast<B*,D&>::value << "\n";
cout << "can_cast<B*&,D*&> = " << can_cast<B*&,D*&>::value << "\n";
cout << "can_cast<D*&,D*&> = " << can_cast<D*&,D*&>::value << "\n";
cout << "can_cast<D*,E*> = " << can_cast<D*,E*>::value << "\n";
cout << "can_cast<E*,F*> = " << can_cast<E*,F*>::value << "\n";
cout << "has_RTTI<D*> = " << has_RTTI<D*>::value << "\n";
cout << "has_RTTI<E*> = " << has_RTTI<E*>::value << "\n";
cout << "has_RTTI<F*> = " << has_RTTI<F*>::value << "\n";
cout << "use_dynamic_downcast<B*,D*> = " << use_dynamic_downcast<B*,D*>::value << "\n";
cout << "use_static_downcast<B*,D*> = " << use_static_downcast<B*,D*>::value << "\n";
cout << "use_conversion<D*,B*> = " << use_conversion<D*,B*>::value << "\n";
cout << "use_static_downcast<D*&,D*&> = " << use_static_downcast<D*&,D*&>::value << "\n";
cout << "use_static_downcast<D*,E*> = " << use_static_downcast<D*,E*>::value << "\n";
cout << "use_dynamic_downcast<D*&,E*> = " << use_dynamic_downcast<D*&,E*>::value << "\n";
cout << "Access(D as D&) --->" << AccessCasted<D&>::access(d) << "\n";
cout << "Access(D& as D&) --->" << AccessCasted<D&>::access(rD) << "\n";
cout << "Access(B& as D&) --->" << AccessCasted<D&>::access(rB) << "\n";
cout << "Access(D* as D*) --->" << AccessCasted<D*>::access(pD) << "\n";
cout << "Access(B* as D*) --->" << AccessCasted<D*>::access(pB) << "\n";
cout << "Access(D*& as D*&) --->" << AccessCasted<D*&>::access(rpD) << "\n";
cout << "Access(B*& as D*&) --->" << AccessCasted<D*&>::access(rpB) << "\n";
cout << "Access(D as B&) --->" << AccessCasted<B&>::access(d) << "\n";
cout << "Access(D& as B&) --->" << AccessCasted<B&>::access(rD) << "\n";
cout << "Access(B& as B&) --->" << AccessCasted<D&>::access(rB) << "\n";
cout << "Access(D* as B*) --->" << AccessCasted<B*>::access(pD) << "\n";
cout << "Access(B* as B*) --->" << AccessCasted<B*>::access(pB) << "\n";
cout << "Access(D*& as B*&) --->" << AccessCasted<B*&>::access(rpD) << "\n";
cout << "Access(B*& as B*&) --->" << AccessCasted<B*&>::access(rpB) << "\n";
cout << "Access(D as E&) --->" << AccessCasted<E&>::access(d) << "\n";
cout << "Access(E& as F&) --->" << AccessCasted<F&>::access(rE) << "\n";
cout << "Access(D(E)* as E*) --->" << AccessCasted<E*>::access(pDE) << "\n";
cout << "Access(D(E)* as F*) --->" << AccessCasted<F*>::access(pDE) << "\n";
cout << "Access(E* as F*) --->" << AccessCasted<F*>::access(pE) << "\n";
cout << "\ngulp\n";

View file

@ -4,8 +4,12 @@ TESTING "Component Test Suite: Builder" ./test-components --group=builder
TEST "BuilderTool_test" BuilderTool_test <<END
out: media is: Asset(VIDEO:lumi.test-1 v1)
out: catch-all-function called.
out: apply (tool, clip);
out: Clip on media : Asset(VIDEO:lumi.test-1 v1)
out: apply (tool, test1);
out: treat (AbstractMO&);
out: apply (tool, test2);
out: catch-all-function called...
END

View file

@ -1,5 +1,5 @@
/*
BuilderTool(Test) - specialized form of the acyclic visitor
BuilderTool(Test) - specialized visitor used within the builder for processing Placements
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
@ -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 <iostream>
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<TestTool, Types<Clip,AbstractMO>::List>
template<class MO>
class TestPlacement : public Placement<MO>
{
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<MO>::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<TestTool, Types<Clip, TestMO>::List>
{
public:
string log_;
void treat (Clip& c)
{
Placement<Clip>& pC = getPlacement<Clip>();
cout << "Clip on media : "<< str(pC->getMedia()) <<"\n";
log_ = string (pC);
}
void treat (AbstractMO&)
{
cout << "treat (AbstractMO&);\n";
log_ = string (getPlacement<MObject>());
}
void onUnknown (Buildable& bxx)
{
cout << "catch-all-function called...\n";
log_ = string (getPlacement<MObject>());
}
};
/*************************************************************************************
* @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> clip = asset::Media::create("test-1", asset::VIDEO)->createClip();
TestPlacement<MObject> test1(*new TestSubMO1);
TestPlacement<MObject> 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

View file

@ -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 <cstdlib>
#include <map>
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<DefsRegistry> reg_;
typedef shared_ptr<Dummy<13> > O;
typedef shared_ptr<Dummy<23> > P;
typedef P<Dummy<13> > O;
typedef P<Dummy<23> > P;
typedef Query<Dummy<13> > Q13;
typedef Query<Dummy<23> > Q23;