/* CommandBasic(Test) - checking simple ProcDispatcher command definition and execution Copyright (C) Lumiera.org 2009, 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. * *****************************************************/ #include "lib/test/run.hpp" #include "lib/test/test-helper.hpp" //#include "proc/asset/media.hpp" //#include "proc/mobject/session.hpp" //#include "proc/mobject/session/edl.hpp" //#include "proc/mobject/session/testclip.hpp" //#include "proc/mobject/test-dummy-mobject.hpp" #include "lib/p.hpp" //#include "proc/mobject/placement.hpp" //#include "proc/mobject/placement-index.hpp" //#include "proc/mobject/explicitplacement.hpp" #include "proc/control/command-def.hpp" #include "lib/lumitime.hpp" //#include "lib/util.hpp" #include "lib/meta/typelist.hpp" #include "lib/meta/typelistutil.hpp" #include "lib/meta/generator.hpp" #include //#include #include #include using std::tr1::bind; //using std::tr1::placeholders::_1; //using std::tr1::placeholders::_2; using std::tr1::function; //using boost::format; using lumiera::Time; //using util::contains; using std::string; using std::cout; using std::endl; namespace lumiera { namespace typelist{ ////////////////////////////////////////////TODO braindump template< typename SIG> struct FunctionSignature; template< typename RET> struct FunctionSignature< function > { typedef RET Ret; typedef Types<> Args; }; template< typename RET , typename A1 > struct FunctionSignature< function > { typedef RET Ret; typedef Types Args; }; template< typename RET , typename A1 , typename A2 > struct FunctionSignature< function > { typedef RET Ret; typedef Types Args; }; template< typename RET , typename A1 , typename A2 , typename A3 > struct FunctionSignature< function > { typedef RET Ret; typedef Types Args; }; template< typename RET , typename A1 , typename A2 , typename A3 , typename A4 > struct FunctionSignature< function > { typedef RET Ret; typedef Types Args; }; template< typename RET , typename A1 , typename A2 , typename A3 , typename A4 , typename A5 > struct FunctionSignature< function > { typedef RET Ret; typedef Types Args; }; template struct FunctionTypedef; template< typename RET> struct FunctionTypedef > { typedef function Func; typedef RET Sig(); }; template< typename RET , typename A1 > struct FunctionTypedef > { typedef function Func; typedef RET Sig(A1); }; template< typename RET , typename A1 , typename A2 > struct FunctionTypedef > { typedef function Func; typedef RET Sig(A1,A2); }; template< typename RET , typename A1 , typename A2 , typename A3 > struct FunctionTypedef > { typedef function Func; typedef RET Sig(A1,A2,A3); }; template< typename RET , typename A1 , typename A2 , typename A3 , typename A4 > struct FunctionTypedef > { typedef function Func; typedef RET Sig(A1,A2,A3,A4); }; template< typename RET , typename A1 , typename A2 , typename A3 , typename A4 , typename A5 > struct FunctionTypedef > { typedef function Func; typedef RET Sig(A1,A2,A3,A4,A5); }; /////////////////////////very basic facility: Typed tuples template struct Prepend; template< typename A1 , typename A2 , typename A3 , typename A4 , typename A5 , typename IGN > struct Prepend > { typedef Types Tuple; }; template struct Tuple; template<> struct Tuple { typedef NullType HeadType; typedef Types<> TailType; typedef Types<> Type; typedef NullType ArgList_; typedef Tuple ThisTuple; typedef Tuple Tail; }; template struct Tuple > : Tuple { typedef TY HeadType; typedef typename Tuple::Type TailType; typedef typename Prepend::Tuple Type; typedef typename Node ArgList_; typedef Tuple ThisTuple; typedef Tuple Tail; Tuple ( TY a1 =TY() , Tail tail =Tail() ) : Tuple (tail.getHead(), tail.getTail()), val_(a1) { } TY & getHead() { return val_; } Tail& getTail() { return static_cast (*this); } private: T1 val_; }; template< typename T1 , typename T2 =NullType , typename T3 =NullType , typename T4 =NullType , typename T5 =NullType > struct Tuple > : Tuple::List> { typedef T1 HeadType; typedef Types TailType; typedef Types Type; typedef typename Type::List ArgList_; typedef Tuple ThisTuple; typedef Tuple Tail; Tuple ( T1 a1 =T1() , T2 a2 =T2() , T3 a3 =T3() , T4 a4 =T4() , T5 a5 =T5() ) : Tuple(a1,makeTuple(a2,a3,a4,a5)) { } using ArgList_::getHead; using ArgList_::getTail; template struct Shifted { typedef typename Tail::Shifted::Type Tuple; }; template<> struct Shifted<0>{ typedef ThisTuple Tuple; }; template typename Shifted::Tuple& getShifted () { typedef typename Shifted::Tuple TailI; return static_cast (*this); } template typename Shifted::Tuple::HeadType& getAt () { return getShifted().getHead(); } }; /** * Decorating a tuple type with auxiliary data access operations. * This helper template builds up a subclass of the given BASE type * (which is assumed to be a Tuple or at least need to be copy constructible * from \c Tuple ). The purpose is to use the Tuple as storage, but * to add a layer of access functions, which in turn might rely on the exact * type of the individual elements within the Tuple. To achieve this, for each * type within the Tuple, the BASE type is decorated with an instance of the * template passed in as template template parameter _X_. Each of these * decorating instances is provided with a member pointer to access "his" * specific element within the underlying tuple. * * The decorating template _X_ need to take its own base class as template * parameter. Typically, operations on _X_ will be defined in a recursive fashion, * calling down into this templated base class. To support this, an instantiation * of _X_ with the 0 member ptr is generated for detecting recursion end * (built as innermost decorator, i.e. immediate subclass of BASE) */ template < typename TYPES , template class _X_ , class BASE =Tuple > class BuildTupleAccessor { typedef typename Tuple Tuple; typedef typename Tuple::TailType Tail; typedef typename Tuple::HeadType Head; typedef Head Tuple::*getElm(); typedef BuildTupleAccessor NextBuilder; typedef typename NextBuilder::Accessor NextAccessor; Tuple& argData_; public: /** type of the product created by this template. * Will be a subclass of BASE */ typedef _X_ Accessor; BuildTupleAccessor (Tuple& tup) : argData_(tup) { } operator Accessor() { return Accessor(argData_); } }; template < class BASE , template class _X_ > class BuildTupleAccessor >, _X_> { typedef typename Tuple > Tuple; typedef NullType Tuple::*getElm(); public: typedef _X_ Accessor; }; ///////////////////////// creating functional closures namespace tuple { template struct Apply; template<> struct Apply<1> { template static RET invoke (FUN f, TUP & arg) { return f (arg.getAt<1>()); } template static RET bind (FUN f, TUP & arg) { return std::tr1::bind (f, arg.getAt<1>()); } }; template<> struct Apply<2> { template static RET invoke (FUN f, TUP & arg) { return f ( arg.getAt<1>() , arg.getAt<2>() ); } template static RET bind (FUN f, TUP & arg) { return std::tr1::bind (f, arg.getAt<1>() , arg.getAt<2>() ); } }; } // (END) sub-namespace template class TupleApplicator { typedef typename FunctionSignature< function >::Args Args; typedef typename FunctionSignature< function >::Ret Ret; enum { ARG_CNT = count::value }; using tuple::Apply; /** storing a ref to the parameter tuple */ Tuple& params_; public: TupleApplicator (Tuple& args) : params_(args) { } function bind (SIG& f) { return Apply::bind (f, params_); } function bind (function const& f) { return Apply::bind (f, params_); } Ret operator() (SIG& f) { return Apply::invoke (f, params_); } Ret operator() (function const& f) { return Apply::invoke (f, params_); } }; /** * Closing a function over its arguments. * This is a small usage example or spin-off, * having almost the same effect than invoking tr1::bind. * The notable difference is that the function arguments for * creating the closure are passed in as one compound tuple. */ template class FunctionClosure { typedef typename FunctionSignature< function >::Args Args; typedef typename FunctionSignature< function >::Ret Ret; function closure_; public: FunctionClosure (SIG& f, Tuple& arg) : closure_(TupleApplicator(arg).bind(f)) { } FunctionClosure (function const& f, Tuple& arg) : closure_(TupleApplicator(arg).bind(f)) { } Ret operator() () { return closure_(); } }; /* template struct BuildClosure : InstantiateWithIndex { }; */ ///////////////////////// additional typelist manipulators template struct SplitLast; template<> struct SplitLast { typedef NullType Type; typedef NullType Prefix; }; template struct SplitLast > { typedef TY Type; typedef NullType Prefix; }; template struct SplitLast > { typedef typename SplitLast::Type Type; typedef typename Append::Prefix>::List Prefix; }; }} // namespace lumiera::typelist namespace control { namespace test { using lib::test::showSizeof; // using session::test::TestClip; using lumiera::P; using lumiera::typelist::FunctionSignature; using lumiera::typelist::FunctionTypedef; using lumiera::typelist::Types; using lumiera::typelist::NullType; using lumiera::typelist::Tuple; using lumiera::typelist::Append; using lumiera::typelist::SplitLast; using lumiera::typelist::BuildTupleAccessor; /** * Type analysis helper template. * Used for dissecting a given type signature to derive * the related basic operation signature, the signature of a possible Undo-function * and the signature necessary for capturing undo information. The implementation * relies on re-binding an embedded type defining template, based on the actual * case, as identified by the structure of the given parameter signature. */ template struct UndoSignature { private: typedef typename FunctionSignature< function >::Args Args; typedef typename FunctionSignature< function >::Ret Ret; /** Case1: defining the Undo-Capture function */ template struct Case { typedef RET Memento; typedef typename Append::List ExtendedArglist; typedef typename Tuple::Type ExtendedArgs; typedef typename FunctionTypedef::Sig OperateSig; typedef typename FunctionTypedef::Sig CaptureSig; typedef typename FunctionTypedef::Sig UndoOp_Sig; }; /** Case2: defining the actual Undo function */ template struct Case { typedef typename ARG::List Args; typedef typename SplitLast::Type Memento; typedef typename SplitLast::Prefix OperationArglist; typedef typename Tuple::Type OperationArgs; typedef typename FunctionTypedef::Sig OperateSig; typedef typename FunctionTypedef::Sig CaptureSig; typedef typename FunctionTypedef::Sig UndoOp_Sig; }; public: typedef typename Case::CaptureSig CaptureSig; typedef typename Case::UndoOp_Sig UndoOp_Sig; typedef typename Case::OperateSig OperateSig; typedef typename Case::Memento Memento; }; /** Interface */ class CmdClosure { public: virtual ~CmdClosure() {} }; template struct ParamAccessor { }; template struct ParamAccessor { }; template class Closure : public CmdClosure { typedef typename FunctionSignature< function >::Args Args; // typedef typename FunctionSignature< function >::Ret Ret; typedef Tuple ArgTuple; typedef BuildTupleAccessor BuildAccessor; typedef typename BuildAccessor::Accessor ParamStorageTuple; ParamStorageTuple params_; Closure (ArgTuple& args) : params_(BuildAccessor(args)) { } }; /** * Helper class used solely for \em defining a Command-Object. * This technique is known as "fluent API", see http://en.wikipedia.org/wiki/Fluent_interface * The basic idea is for the user to create a disposable instance of this definition helper, * only for calling a chain of definition functions, which internally build the actual Command object. * Finally, the created Command object will be stored into a registry or handed over to the * ProcDispatcher. To give an example: * \code * CommandDefinition ("test.command1") * .operation (command1::operate) // provide the function to be executed as command * .captureUndo (command1::capture) // provide the function capturing Undo state * .undoOperation (command1::undoIt) // provide the function which might undo the command * .bind (obj, randVal) // bind to the actual command parameters * .executeSync(); // convenience call, forwarding the Command to dispatch. * \endcode * * @todo of course, this needs to be extracted into command-definition.hpp */ class CommDef { Symbol id_; template struct UndoDefinition { typedef typename FunctionSignature< function >::Args BasicArgs; typedef typename FunctionTypedef::Sig UndoCaptureSig; UndoDefinition (function& undoCapOperation) { cout << showSizeof(undoCapOperation) << endl; UNIMPLEMENTED ("re-fetch command definition and augment it with Functor for capturing Undo information"); } template UndoDefinition& undoOperation (SIG2& how_to_Undo) { typedef typename UndoSignature::UndoOp_Sig UndoSig; function opera3 (how_to_Undo); UNIMPLEMENTED ("store actual Undo-Functor into the command definition held by the enclosing UndoDefinition instance"); return *this; } }; /** type re-binding helper: create a suitable UndoDefinition type, * based on the UndoSignature template instance given as parameter */ template struct BuildUndoDefType { typedef UndoDefinition Type; }; template struct BasicDefinition { BasicDefinition(function& operation) { cout << showSizeof(operation) << endl; UNIMPLEMENTED ("create new command object an store the operation functor"); } template typename BuildUndoDefType >::Type captureUndo (SIG2& how_to_capture_UndoState) { typedef typename UndoSignature::CaptureSig UndoCapSig; typedef typename BuildUndoDefType >::Type SpecificUndoDefinition; function opera2 (how_to_capture_UndoState); return SpecificUndoDefinition (opera2); } }; public: CommDef (Symbol cmdID) : id_(cmdID) { } template BasicDefinition operation (SIG& operation_to_define) { function opera1 (operation_to_define); return BasicDefinition(opera1); } }; ///////////////////////////// ///////////////////////////// //////////////////////////// start of the actual Test.... /* bind: opFunc(a,b,c) -> op(void) curry(opFunc) (a) (b) (c) pAppl(func, x) -> func2 (b, c) return bind( recursion(), param) */ namespace command1 { void operate (P