diff --git a/src/common/typelistutil.hpp b/src/common/typelistutil.hpp new file mode 100644 index 000000000..6aeae1870 --- /dev/null +++ b/src/common/typelistutil.hpp @@ -0,0 +1,146 @@ +/* + TYPELISTUTIL.hpp - metaprogramming utilities for lists-of-types + + Copyright (C) CinelerraCV + 2007, 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. + +==================================================================== +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 _X_ // your-template-goes-here + , class BASE = NullType // Base class at end of chain + > + class InstantiateForEach; + + + template class _X_, class BASE> + class InstantiateForEach + : public BASE + { + public: + typedef BASE Unit; + typedef NullType Next; + }; + + + template + < class TY, typename TYPES + , template class _X_ + , class BASE + > + class InstantiateForEach, _X_, BASE> + : public _X_, + public InstantiateForEach + { + public: + typedef _X_ Unit; + typedef InstantiateForEach 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 _X_ // your-template-goes-here + , class BASE = NullType // Base class at end of chain + > + class InstantiateChained; + + + template class _X_, class BASE> + class InstantiateChained + : public BASE + { + public: + typedef BASE Unit; + typedef NullType Next; + }; + + + template + < class TY, typename TYPES + , template class _X_ + , class BASE + > + class InstantiateChained, _X_, BASE> + : public _X_< TY + , InstantiateChained + > + { + public: + typedef InstantiateChained Next; + typedef _X_ Unit; + }; + + + } // namespace typelist + +} // namespace cinelerra +#endif diff --git a/src/proc/asset.hpp b/src/proc/asset.hpp index f6f8a8d98..7375d25af 100644 --- a/src/proc/asset.hpp +++ b/src/proc/asset.hpp @@ -291,8 +291,19 @@ namespace asset }; + + + /** promote subtype-ptr to PAsset, e.g. for comparing */ + template + inline const PcAsset + pAsset (const shared_ptr& subPtr) + { + return static_pointer_cast (subPtr); + } + /** ordering of Asset smart ptrs based on Ident tuple. - * @todo currently supporting only smart_ptr. */ + * @todo currently supporting only smart_ptr. + * @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 - inline PcAsset - pAsset (shared_ptr& subPtr) - { - return static_pointer_cast (subPtr); - } - /** convienient for debugging */ inline string str (const PcAsset& a) diff --git a/src/proc/asset/port.cpp b/src/proc/asset/port.cpp index f574dbd39..08b7dd38f 100644 --- a/src/proc/asset/port.cpp +++ b/src/proc/asset/port.cpp @@ -54,6 +54,12 @@ namespace asset + PPort + Port::query (string properties) + { + return Struct::create (Query (properties)); + } + void Port::switchProcPatt (PProcPatt& another) { diff --git a/src/proc/asset/port.hpp b/src/proc/asset/port.hpp index 8784b629b..8bb359789 100644 --- a/src/proc/asset/port.hpp +++ b/src/proc/asset/port.hpp @@ -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 (properties)); } + static PPort query (string properties) ; }; diff --git a/src/proc/asset/struct.cpp b/src/proc/asset/struct.cpp index 3f9a911f5..dd8f71aa5 100644 --- a/src/proc/asset/struct.cpp +++ b/src/proc/asset/struct.cpp @@ -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 PortIDs; + + PortIDs + createPortIdent (const Query& 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 + StructFactory::operator() (const Query& 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. diff --git a/src/proc/mobject/session/defsmanager.cpp b/src/proc/mobject/session/defsmanager.cpp index 305db5cab..291233ce0 100644 --- a/src/proc/mobject/session/defsmanager.cpp +++ b/src/proc/mobject/session/defsmanager.cpp @@ -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 - DefsManager::operator() (const Query& properties) + DefsManager::operator() (const Query& capabilities) { - + UNIMPLEMENTED ("query for default port with capabilities"); + } + + + /** create or retrieve a default-configured processing pattern. + */ + template<> + shared_ptr + DefsManager::operator() (const Query& capabilities) + { + UNIMPLEMENTED ("query for default processing pattern with capabilities"); } diff --git a/tests/50components.tests b/tests/50components.tests index 7737d7fce..c0addaf23 100644 --- a/tests/50components.tests +++ b/tests/50components.tests @@ -189,6 +189,27 @@ return: 0 END +TEST "TypeListUtil_test" TypeListUtil_test < > +out: ctor DoIt > +out: ctor DoIt > +out: ctor DoIt > +out: ctor DoIt > +out: ctor DoIt > +out: Block< 2>::eat(..) +out: Block< 5>::eat(..) +out: Block<13>::eat(..) +out: gulp! +out: dtor DoIt > +out: dtor DoIt > +out: dtor DoIt > +out: dtor DoIt > +out: dtor DoIt > +out: dtor DoIt > +return: 0 +END + + TEST "VisitingTool_test" VisitingTool_test < + + 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 +#include +#include + +using std::string; +using std::cout; + + +namespace cinelerra + { + namespace typelist + { + namespace test + { + + /** template for generating lots of different test types */ + template + struct Block + { + static string name; + string talk() { return name+"::eat(..)"; } + }; + + + boost::format fmt ("Block<%2i>"); + + template + string Block::name = str (fmt % I); + + + + /** Use this building block for assembling an abstract interface */ + template + class TakeIt + { + public: + virtual void eat (X& x) = 0; + virtual ~TakeIt() { } + }; + + /** Use this building block for chaining corresponding implementation classes. */ + template + class DoIt + : public BASE + { + protected: + DoIt () { cout << "ctor DoIt<"<< X::name << " >\n";} + virtual ~DoIt() { cout << "dtor DoIt<"<< X::name << " >\n";} + public: + void eat (X& x) { cout << 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 TheInterface; + + + struct BaseImpl : public TheInterface + { + void eat() { cout << "gulp!\n"; } + }; + + typedef InstantiateChained NumberBabbler; + + + /************************************************************************* + * @test check the helpers for dealing with lists-of-types. + *
  • build an interface and an implementation class + * by inheriting template instantiations + * for a collection of classes
  • + *
+ */ + class 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 >& 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 diff --git a/wiki/renderengine.html b/wiki/renderengine.html index 8d57363ad..a066a89cc 100644 --- a/wiki/renderengine.html +++ b/wiki/renderengine.html @@ -2450,26 +2450,26 @@ Like all [[structural assets|StructAsset]], ~ProcPatt employs a special naming s
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
 
-
+
//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 ("declarative") 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 "mpeg" 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 "stream(P,mpeg)" implemented (natively) for the port object. So, "Cap" is the query issued from calling code &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 "stream(P,mpeg)" implemented (natively) for the port object. So, "Cap" is the query issued from calling code &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 "Cap" (and consequently run as a goal by {{{call(Q)}}}). The implementation needs to provide a symbol table associating variable terms (like "T" or "P") 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 "type" 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 "executed", 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 "condiguration data" (including the actual plugin implementation to be loaded)