add stubs to make it link, add some typelist utils

This commit is contained in:
Fischlurch 2008-01-27 23:40:45 +01:00
parent c3b1048fc4
commit 000538f6ef
9 changed files with 379 additions and 18 deletions

146
src/common/typelistutil.hpp Normal file
View file

@ -0,0 +1,146 @@
/*
TYPELISTUTIL.hpp - metaprogramming utilities for lists-of-types
Copyright (C) CinelerraCV
2007, 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.
====================================================================
This code is heavily inspired by
The Loki Library (loki-lib/trunk/include/loki/Sequence.h)
Copyright (c) 2001 by Andrei Alexandrescu
Copyright (c) 2005 by Peter Kümmel
This Loki code accompanies the book:
Alexandrescu, Andrei. "Modern C++ Design: Generic Programming
and Design Patterns Applied".
Copyright (c) 2001. Addison-Wesley. ISBN 0201704315
Loki Copyright Notice:
Permission to use, copy, modify, distribute and sell this software for any
purpose is hereby granted without fee, provided that the above copyright
notice appear in all copies and that both that copyright notice and this
permission notice appear in supporting documentation.
The author makes no representations about the suitability of this software
for any purpose. It is provided "as is" without express or implied warranty.
*/
/** @file typelistutil.hpp
** Helpers for working with cinelerra::typelist::Types (i.e. lists-of-types).
**
** @see cinelerra::query::ConfigRules usage example
** @see typelist.hpp
**
*/
#ifndef CINELERRA_TYPELISTUTIL_H
#define CINELERRA_TYPELISTUTIL_H
#include "common/typelist.hpp"
namespace cinelerra
{
namespace typelist
{
/**
* Apply a template to a collection of types.
* The resulting class ends up inheriting from an instantiation
* of the templace for each of the types in the list.
*/
template
< class TYPES // List of Types
, template<class> class _X_ // your-template-goes-here
, class BASE = NullType // Base class at end of chain
>
class InstantiateForEach;
template<template<class> class _X_, class BASE>
class InstantiateForEach<NullType, _X_, BASE>
: public BASE
{
public:
typedef BASE Unit;
typedef NullType Next;
};
template
< class TY, typename TYPES
, template<class> class _X_
, class BASE
>
class InstantiateForEach<Node<TY, TYPES>, _X_, BASE>
: public _X_<TY>,
public InstantiateForEach<TYPES, _X_, BASE>
{
public:
typedef _X_<TY> Unit;
typedef InstantiateForEach<TYPES,_X_> Next;
};
/**
* Build a single inheritance chain of template instantiations.
* Needs the help of the user provided Template, which now has
* to take a second parameter and use this as Base class.
* The resulting class ends up (single) inheriting from an
* instantiation of the templace for each of the types, while
* overrideing/implementing the provided base class.
*/
template
< class TYPES // List of Types
, template<class,class> class _X_ // your-template-goes-here
, class BASE = NullType // Base class at end of chain
>
class InstantiateChained;
template<template<class,class> class _X_, class BASE>
class InstantiateChained<NullType, _X_, BASE>
: public BASE
{
public:
typedef BASE Unit;
typedef NullType Next;
};
template
< class TY, typename TYPES
, template<class,class> class _X_
, class BASE
>
class InstantiateChained<Node<TY, TYPES>, _X_, BASE>
: public _X_< TY
, InstantiateChained<TYPES, _X_, BASE>
>
{
public:
typedef InstantiateChained<TYPES,_X_> Next;
typedef _X_<TY,Next> Unit;
};
} // namespace typelist
} // namespace cinelerra
#endif

View file

@ -291,8 +291,19 @@ namespace asset
};
/** promote subtype-ptr to PAsset, e.g. for comparing */
template<class A>
inline const PcAsset
pAsset (const shared_ptr<A>& subPtr)
{
return static_pointer_cast<const Asset,A> (subPtr);
}
/** ordering of Asset smart ptrs based on Ident tuple.
* @todo currently supporting only smart_ptr<Asset>. */
* @todo currently supporting only smart_ptr<Asset>.
* @todo should better be done using boost::operator */
inline bool operator== (const PcAsset& a1, const PcAsset& a2) { return a1 && a2 && ( 0==a1->ident.compare(a2->ident));}
inline bool operator< (const PcAsset& a1, const PcAsset& a2) { return a1 && a2 && (-1==a1->ident.compare(a2->ident));}
inline bool operator> (const PcAsset& a1, const PcAsset& a2) { return a2 < a1; }
@ -300,6 +311,13 @@ namespace asset
inline bool operator<= (const PcAsset& a1, const PcAsset& a2) { return !(a1 > a2); }
inline bool operator!= (const PcAsset& a1, const PcAsset& a2) { return !(a1== a2); }
inline bool operator== (const PAsset& a1, const PAsset& a2) { return pAsset(a1) == pAsset(a2); }
inline bool operator< (const PAsset& a1, const PAsset& a2) { return pAsset(a1) < pAsset(a2); }
inline bool operator> (const PAsset& a1, const PAsset& a2) { return pAsset(a1) > pAsset(a2); }
inline bool operator>= (const PAsset& a1, const PAsset& a2) { return pAsset(a1) >= pAsset(a2); }
inline bool operator<= (const PAsset& a1, const PAsset& a2) { return pAsset(a1) <= pAsset(a2); }
inline bool operator!= (const PAsset& a1, const PAsset& a2) { return pAsset(a1) != pAsset(a2); }
/** ordering of Asset Ident tuples.
* @note version is irrelevant */
inline int
@ -311,14 +329,6 @@ namespace asset
return name.compare (oi.name);
}
/** promote to PAsset, e.g. for comparing */
template<class A>
inline PcAsset
pAsset (shared_ptr<A>& subPtr)
{
return static_pointer_cast<const Asset,A> (subPtr);
}
/** convienient for debugging */
inline string str (const PcAsset& a)

View file

@ -54,6 +54,12 @@ namespace asset
PPort
Port::query (string properties)
{
return Struct::create (Query<Port> (properties));
}
void
Port::switchProcPatt (PProcPatt& another)
{

View file

@ -78,7 +78,7 @@ namespace asset
void switchProcPatt (PProcPatt& another);
/** convienience shortcut for retrieving default configured ports */
static PPort query (string properties) { return Struct::create (Query<Port> (properties)); }
static PPort query (string properties) ;
};

View file

@ -25,6 +25,7 @@
#include "proc/asset/struct.hpp"
#include "proc/asset/procpatt.hpp"
#include "proc/asset/track.hpp"
#include "proc/asset/port.hpp"
#include "proc/mobject/session.hpp"
#include "common/query.hpp"
@ -37,6 +38,9 @@ using cinelerra::query::normalizeID;
namespace asset
{
/****** NOTE: not implemented yet. What follows is a hack to build simple tests *******/
namespace // common Struct Asset implementation details
{
/** @internal derive a sensible asset ident tuple when creating
@ -51,6 +55,16 @@ namespace asset
Category category (STRUCT,"tracks");
return Asset::Ident (name, category );
}
typedef std::pair<string,string> PortIDs;
PortIDs
createPortIdent (const Query<Port>& query)
{
string name ("port-" + query); // TODO get some more sensible dummy values
TODO ("port naming scheme??");
return PortIDs (name, "mpeg"); // dummy stream type
}
}
@ -74,6 +88,19 @@ namespace asset
}
/** Similar instance for Port Query....
* @todo better a generic implementation utilizing ConfigQuery....
*/
template<>
shared_ptr<Port>
StructFactory::operator() (const Query<Port>& query)
{
TODO ("actually evaluate the query...");
PortIDs ids (createPortIdent (query));
return operator() (ids.first, ids.second);
}
/** Factory method for creating Ports explicitly.
* Normalizes port- and streamID, then retrieves the
* default processing pattern (ProcPatt) for this streamID.

View file

@ -22,10 +22,12 @@
#include "proc/mobject/session/defsmanager.hpp"
#include "proc/asset/procpatt.hpp"
#include "proc/asset/port.hpp"
using asset::Query;
using asset::Port;
using asset::ProcPatt;
namespace mobject
{
@ -40,13 +42,22 @@ namespace mobject
/** create or retrieve a default-configured port asset.
* @param
*/
template<>
shared_ptr<Port>
DefsManager::operator() (const Query<Port>& properties)
DefsManager::operator() (const Query<Port>& capabilities)
{
UNIMPLEMENTED ("query for default port with capabilities");
}
/** create or retrieve a default-configured processing pattern.
*/
template<>
shared_ptr<ProcPatt>
DefsManager::operator() (const Query<ProcPatt>& capabilities)
{
UNIMPLEMENTED ("query for default processing pattern with capabilities");
}

View file

@ -189,6 +189,27 @@ return: 0
END
TEST "TypeListUtil_test" TypeListUtil_test <<END
out: ctor DoIt<Block<13> >
out: ctor DoIt<Block< 8> >
out: ctor DoIt<Block< 5> >
out: ctor DoIt<Block< 3> >
out: ctor DoIt<Block< 2> >
out: ctor DoIt<Block< 1> >
out: Block< 2>::eat(..)
out: Block< 5>::eat(..)
out: Block<13>::eat(..)
out: gulp!
out: dtor DoIt<Block< 1> >
out: dtor DoIt<Block< 2> >
out: dtor DoIt<Block< 3> >
out: dtor DoIt<Block< 5> >
out: dtor DoIt<Block< 8> >
out: dtor DoIt<Block<13> >
return: 0
END
TEST "VisitingTool_test" VisitingTool_test <<END
out: === Babbler meets Boss and BigBoss ===
out: Hello Boss, nice to meet you...

View file

@ -0,0 +1,140 @@
/*
TypeListUtil(Test) - check the typelist helpers
Copyright (C) CinelerraCV
2007, Hermann Vosseler <Ichthyostega@web.de>
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
* *****************************************************/
#include "common/test/run.hpp"
#include "common/typelistutil.hpp"
#include <boost/format.hpp>
#include <iostream>
#include <typeinfo>
using std::string;
using std::cout;
namespace cinelerra
{
namespace typelist
{
namespace test
{
/** template for generating lots of different test types */
template<int I>
struct Block
{
static string name;
string talk() { return name+"::eat(..)"; }
};
boost::format fmt ("Block<%2i>");
template<int I>
string Block<I>::name = str (fmt % I);
/** Use this building block for assembling an abstract interface */
template<class X>
class TakeIt
{
public:
virtual void eat (X& x) = 0;
virtual ~TakeIt() { }
};
/** Use this building block for chaining corresponding implementation classes. */
template<class X, class BASE>
class DoIt
: public BASE
{
protected:
DoIt () { cout << "ctor DoIt<"<< X::name << " >\n";}
virtual ~DoIt() { cout << "dtor DoIt<"<< X::name << " >\n";}
public:
void eat (X& x) { cout << x.talk() << "\n";}
using BASE::eat; // prevent shaddowing
};
typedef Types< Block<1>
, Block<2>
, Block<3>
, Block<5>
, Block<8>
, Block<13>
>::List TheTypes;
typedef InstantiateForEach<TheTypes,TakeIt> TheInterface;
struct BaseImpl : public TheInterface
{
void eat() { cout << "gulp!\n"; }
};
typedef InstantiateChained<TheTypes,DoIt, BaseImpl> NumberBabbler;
/*************************************************************************
* @test check the helpers for dealing with lists-of-types.
* <ul><li>build an interface and an implementation class
* by inheriting template instantiations
* for a collection of classes</li>
* </ul>
*/
class TypeListUtil_test : public Test
{
virtual void run(Arg arg)
{
NumberBabbler me_can_has_more_numberz;
ASSERT (INSTANCEOF (TheInterface, &me_can_has_more_numberz));
TheTypes::Tail::Head b2; // Block<2>
TheTypes::Tail::Tail::Tail::Head b5; // Block<5>
TheTypes::Tail::Tail::Tail::Tail::Tail::Head b13; // Block<13>
me_can_has_more_numberz.eat (b2);
me_can_has_more_numberz.eat (b5);
TakeIt<Block<13> >& subInterface = me_can_has_more_numberz;
subInterface.eat (b13);
me_can_has_more_numberz.eat();
INFO (test, "SizeOf = %i", sizeof(me_can_has_more_numberz));
}
};
/** Register this test class... */
LAUNCHER (TypeListUtil_test, "unit common");
} // namespace test
} // namespace typelist
} // namespace cinelerra

View file

@ -2450,26 +2450,26 @@ Like all [[structural assets|StructAsset]], ~ProcPatt employs a special naming s
<pre>a given Render Engine configuration is a list of Processors. Each Processor in turn contains a Graph of ProcNode.s to do the acutal data processing. In order to cary out any calculations, the Processor needs to be called with a StateProxy containing the state information for this RenderProcess
</pre>
</div>
<div title="QueryImplProlog" modifier="Ichthyostega" modified="200801210153" created="200801202321" tags="draft design" changecount="11">
<div title="QueryImplProlog" modifier="Ichthyostega" modified="200801270339" created="200801202321" tags="draft design" changecount="14">
<pre>//obviously, getting this one to work requires quite a lot of technical details to be planned and implemented.// This said...
The intention is to get much more readable (&quot;declarative&quot;) and changeable configuration as by programming it directly within the implementation of some object.
!Draft
As an example, specifying how a Track can be configured for connecting automatically to some &quot;mpeg&quot; bus (=port)
{{{
retrieve(O, Cap) :- find(T), capabilities(Cap).
retrieve(O, Cap) :- make(T), capabilities(Cap).
retrieve(O, Cap) :- find(O), capabilities(Cap).
retrieve(O, Cap) :- make(O), capabilities(Cap).
capabilities(Q) :- call(Q).
stream(T, mpeg) :- type(T, track), type(P, port), retrieve(P, stream(P,mpeg)), place_to(P, T).
}}}
Then, running the goal {{{:-retrieve(T, stream(T,mpeg)).}}} would search a Track object, try to retrieve a port object with stream-type=mpeg and associate the track with this Port. This relies on a predicate &quot;stream(P,mpeg)&quot; implemented (natively) for the port object. So, &quot;Cap&quot; is the query issued from calling code &amp;mdash; here {{{stream(T,mpeg)}}}, the type guard {{{type(T, track)}}} will probably be handled or inserted inserted automatically, while the predicate implementations for find/1, make/1, stream/2, and place_to/2 are to be provided by the target types.
Then, running the goal {{{:-retrieve(T, stream(T,mpeg)).}}} would search a Track object, try to retrieve a port object with stream-type=mpeg and associate the track with this Port. This relies on a predicate &quot;stream(P,mpeg)&quot; implemented (natively) for the port object. So, &quot;Cap&quot; is the query issued from calling code &amp;mdash; here {{{stream(T,mpeg)}}}, the type guard {{{type(T, track)}}} will probably be handled or inserted automatically, while the predicate implementations for find/1, make/1, stream/2, and place_to/2 are to be provided by the target types.
* __The supporting system__ had to combine several code snippets into one rule system to be used for running queries, with some global base rules, rules injected by each individual participating object kind and finally user provided rules added by the current session. The actual query is bound to &quot;Cap&quot; (and consequently run as a goal by {{{call(Q)}}}). The implementation needs to provide a symbol table associating variable terms (like &quot;T&quot; or &quot;P&quot;) to C/C++ object types, enabling the participating object kinds to register their specific predicate implementations. This is crucial, because there can be no general scheme of object-provided predicates (for each object kind different predicates make sense, e.g. [[ports|PortHandling]] have other possibilities than [[wiring requests|WiringRequest]]). Basically, a query issues a Prolog goal, which in turn evaluates domain specific predicates provided by the participating objects and thus calls back into C/C++ code. The supporting system maintains the internal connection (via the &quot;type&quot; predicate) such that from Prolog viewpoint it looks as if we were binding Variables directly to object instances. (there are some nasty technical details because of the backtracking nature of Prolog evaluations which need to be hidden away)
* Any __participating object kind__ needs a way to declare domain specific predicates, thus triggering the registration of the necessary hooks within the supporting system. Moreover, it should be able to inject further prolog code (as shown in the example above with the {{{strem(T, mpeg)}}} predicate. For each of these new domain specific predicates, there needs to be a functor which can be invoked when the C implementation of the predicate is called from Prolog (in some cases even later, when the final solution is &quot;executed&quot;, e.g. a new instance has been created and now some properties need to be set).
!!a note on Plugins
In the design of the Cinelerra-3 Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Port, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used.
In the design of the Cinelerra-3 Proc Layer done thus far, we provide //no possibility to introduce a new object kind// into the system via plugin interface. The system uses a fixed collection of classes intended to cover all needs (Clip, Effect, Track, Port, Label, Automation, ~Macro-Clips). Thus, plugins will only be able to provide new parametrisations of existing classes. This should not be any real limitation, because the whole system is designed to achieve most of its functionality by freely combining rather basic object kinds. As a plus, it plays nicely with any plain-C based plugin interface. For example, we will have C++ adapter classes for the most common sorts of effect plugin (pull system and synchronous frame-by-frame push with buffering) with a thin C adaptation layer for the specific external plugin systems used. Everything beyond this point can be considered &quot;condiguration data&quot; (including the actual plugin implementation to be loaded)
</pre>
</div>
<div title="RSSReaderPlugin" modifier="Ichthyostega" created="200708081515" tags="systemConfig" changecount="1">