From f358f548d1eea47973e33af2778d238bc92cedbe Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 19 Jun 2009 19:11:33 +0200 Subject: [PATCH] draft version of CmdClosure and Mutation interface now passing compiler --- src/lib/meta/tuple.hpp | 37 ++- src/proc/control/command-closure.hpp | 127 ++++++++- src/proc/control/command-def.hpp | 173 +++++++++++- src/proc/control/command-mutation.hpp | 46 +++- src/proc/control/command.cpp | 12 +- src/proc/control/command.hpp | 6 + src/proc/control/proc-dispatcher.hpp | 2 +- .../proc/control/command-basic-test.cpp | 246 +----------------- .../proc/control/command-mutation-test.cpp | 44 ++-- 9 files changed, 403 insertions(+), 290 deletions(-) diff --git a/src/lib/meta/tuple.hpp b/src/lib/meta/tuple.hpp index 19eb272fd..f95816824 100644 --- a/src/lib/meta/tuple.hpp +++ b/src/lib/meta/tuple.hpp @@ -305,16 +305,17 @@ namespace typelist{ - Tuple > + inline + Tuple< Types<> > makeNullTuple () { return Tuple > (); } - template< typename T1 - > - Tuple > + template + inline + Tuple< Types > make ( T1 a1 =T1() ) { @@ -325,7 +326,8 @@ namespace typelist{ template< typename T1 , typename T2 > - Tuple > + inline + Tuple< Types > make ( T1 a1 =T1() , T2 a2 =T2() ) @@ -338,7 +340,8 @@ namespace typelist{ , typename T2 , typename T3 > - Tuple > + inline + Tuple< Types > make ( T1 a1 =T1() , T2 a2 =T2() , T3 a3 =T3() @@ -353,7 +356,8 @@ namespace typelist{ , typename T3 , typename T4 > - Tuple > + inline + Tuple< Types > make ( T1 a1 =T1() , T2 a2 =T2() , T3 a3 =T3() @@ -370,7 +374,8 @@ namespace typelist{ , typename T4 , typename T5 > - Tuple > + inline + Tuple< Types > make ( T1 a1 =T1() , T2 a2 =T2() , T3 a3 =T3() @@ -392,7 +397,8 @@ namespace typelist{ , typename T8 , typename T9 > - Tuple > + inline + Tuple< Types > make ( T1 a1 =T1() , T2 a2 =T2() , T3 a3 =T3() @@ -443,7 +449,7 @@ namespace typelist{ typedef BuildTupleAccessor NextBuilder; typedef typename NextBuilder::Accessor NextAccessor; - ArgTuple& argData_; + ArgTuple const& argData_; public: @@ -456,7 +462,7 @@ namespace typelist{ > Accessor; - BuildTupleAccessor (ArgTuple& tup) + BuildTupleAccessor (ArgTuple const& tup) : argData_(tup) { } @@ -474,9 +480,18 @@ namespace typelist{ class BuildTupleAccessor, _X_, TUP, i> { typedef Tuple > ArgTuple; + ArgTuple const& argData_; public: typedef _X_ Accessor; + + BuildTupleAccessor (ArgTuple const& tup) + : argData_(tup) + { } + + /** used to get the product of this builder template... */ + operator Accessor() { return Accessor(argData_); } + }; diff --git a/src/proc/control/command-closure.hpp b/src/proc/control/command-closure.hpp index 8b38eacab..5c5923f09 100644 --- a/src/proc/control/command-closure.hpp +++ b/src/proc/control/command-closure.hpp @@ -36,25 +36,142 @@ #define CONTROL_COMMAND_CLOSURE_H //#include "pre.hpp" +#include "lib/meta/typelist.hpp" +#include "lib/meta/function.hpp" +#include "lib/meta/function-closure.hpp" +#include "lib/meta/tuple.hpp" -//#include +#include +#include +#include +#include +#include "lib/test/test-helper.hpp" /////////////////TODO remove this +using lib::test::showSizeof; + +using std::cout; //////////////////////////////////TODO remove this +using std::endl; + namespace control { // using lumiera::Symbol; // using std::tr1::shared_ptr; + using std::string; + using std::ostream; + using std::tr1::function; + using lumiera::typelist::FunctionSignature; + using lumiera::typelist::Tuple; + using lumiera::typelist::BuildTupleAccessor; + + using lumiera::typelist::NullType; + + class CmdClosure; + typedef std::tr1::shared_ptr PClo; ///< smart-ptr type used for handling concrete closures - /** - * @todo Type-comment - */ - class CommandClosure + /** Interface */ + class CmdClosure { + public: + virtual ~CmdClosure() {} + + virtual PClo clone() const =0; + + virtual operator string() const =0; + + }; + + + + inline ostream& operator<< (ostream& os, const CmdClosure& clo) { return os << string(clo); } + + + template + < typename TY + , class BASE + , class TUP + , uint idx + > + class ParamAccessor + : public BASE + { + TY& element() { return BASE::template getAt(); } public: + + ParamAccessor(TUP const& tuple) + : BASE(tuple) + { + cout << showSizeof(element()) << endl; //////////TODO remove this test code + } + string + dump (string const& prefix = "(") const + { + return BASE::dump (prefix+element()); + } + + + ////////////////////TODO the real access operations (e.g. for serialising) go here + }; + + template + class ParamAccessor + : public TUP + { + public: + ParamAccessor(TUP const& tuple) + : TUP(tuple) + { } + + ////////////////////TODO the recursion-end of the access operations goes here + + protected: + string + dump (string const& prefix) const + { + return prefix+")"; + } + + }; + + + + template + class Closure + : public CmdClosure + { + typedef typename FunctionSignature< function >::Args Args; + + typedef Tuple ArgTuple; + + typedef BuildTupleAccessor BuildAccessor; + typedef typename BuildAccessor::Accessor ParamStorageTuple; + + ParamStorageTuple params_; + + public: + Closure (ArgTuple const& args) + : params_(BuildAccessor(args)) + { } + + + /** create a clone copy of this concrete closure, + * hidden behind the generic CmdClosure interface + * and owned by a shared_ptr PClo. + */ + PClo + clone() const + { + return PClo (new Closure (this->params_)); + } + + operator string() const + { + UNIMPLEMENTED ("how to do a string conversion on the variable argument tuple??"); + } }; ////////////////TODO currently just fleshing out the API.... diff --git a/src/proc/control/command-def.hpp b/src/proc/control/command-def.hpp index acbf8bb5b..5002e9452 100644 --- a/src/proc/control/command-def.hpp +++ b/src/proc/control/command-def.hpp @@ -52,8 +52,13 @@ #include "proc/control/command.hpp" #include "proc/control/command-mutation.hpp" #include "proc/control/command-closure.hpp" +#include "lib/meta/function.hpp" +#include "lib/meta/typelist.hpp" +#include "lib/meta/typelistutil.hpp" +#include "lib/meta/tuple.hpp" //#include +#include @@ -62,21 +67,187 @@ namespace control { using lumiera::Symbol; // using std::tr1::shared_ptr; + using std::tr1::function; + + 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; + + + + + /** + * 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::List 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; + }; + + + + + + + /** - * @todo Type-comment + * 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 CommandDef { 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; + } + + template + < typename T1 + , typename T2 + > + UndoDefinition& ///////TODO return here the completed Command + bind ( T1& p1 + , T2& p2 + ) + { + typedef Types ArgTypes; + Tuple params(p1,p2); + Closure clo (params); + + cout << showSizeof(clo) << endl; + UNIMPLEMENTED ("complete Command definition by closing all functions"); + 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: CommandDef (Symbol cmdID) : id_(cmdID) { } + template + BasicDefinition + operation (SIG& operation_to_define) + { + function opera1 (operation_to_define); + return BasicDefinition(opera1); + } }; + ////////////////TODO currently just fleshing out the API.... diff --git a/src/proc/control/command-mutation.hpp b/src/proc/control/command-mutation.hpp index eeb26c51d..02a68794f 100644 --- a/src/proc/control/command-mutation.hpp +++ b/src/proc/control/command-mutation.hpp @@ -32,13 +32,18 @@ -#ifndef CONTROL_MUTATION_H -#define CONTROL_MUTATION_H +#ifndef CONTROL_COMMAND_MUTATION_H +#define CONTROL_COMMAND_MUTATION_H //#include "pre.hpp" #include "lib/error.hpp" +#include "proc/control/command-closure.hpp" //#include +#include +#include +#include +#include @@ -46,6 +51,10 @@ namespace control { // using lumiera::Symbol; // using std::tr1::shared_ptr; + using boost::scoped_ptr; + using std::tr1::function; + using std::ostream; + using std::string; /** @@ -53,6 +62,7 @@ namespace control { */ class Mutation { + PClo clo_; public: template @@ -63,12 +73,15 @@ namespace control { virtual ~Mutation() {} + virtual Mutation& close (CmdClosure const& closure) { UNIMPLEMENTED ("accept and store a parameter closure"); + return *this; } + void operator() () { @@ -77,7 +90,7 @@ namespace control { /* == diagnostics == */ - typedef pClo Mutation::*_unspecified_bool_type; + typedef PClo Mutation::*_unspecified_bool_type; /** implicit conversion to "bool" */ operator _unspecified_bool_type() const { return isValid()? &Mutation::clo_ : 0; } // never throws @@ -85,12 +98,12 @@ namespace control { operator string() const { - return isValid()? string (*clo) : "Mutation(state missing)"; + return isValid()? string (*clo_) : "Mutation(state missing)"; } protected: virtual bool - isValid () + isValid () const { UNIMPLEMENTED ("mutation lifecycle"); } @@ -108,14 +121,30 @@ namespace control { class UndoMutation : public Mutation { + scoped_ptr memento_; public: - template - UndoMutation (function const& func) + template + UndoMutation (function const& undoFunc, function const& captureFunc) + : Mutation(undoFunc) { UNIMPLEMENTED ("build a undo Mutation functor object"); } + UndoMutation (UndoMutation const& o) + : Mutation(*this), + memento_(o.memento_->clone().get()) + { } + + UndoMutation& + operator= (UndoMutation const& o) + { + Mutation::operator= (o); + memento_.reset(o.memento_->clone().get()); + return *this; + } + + Mutation& captureState () { @@ -132,6 +161,9 @@ namespace control { ////////////////TODO currently just fleshing out the API.... + LUMIERA_ERROR_DECLARE (UNBOUND_ARGUMENTS); ///< Mutation functor not yet usable, because arguments aren't bound + LUMIERA_ERROR_DECLARE (MISSING_MEMENTO); ///< Undo functor not yet usable, because no undo state has been captured + } // namespace control diff --git a/src/proc/control/command.cpp b/src/proc/control/command.cpp index e0d82fdf7..54e4b0888 100644 --- a/src/proc/control/command.cpp +++ b/src/proc/control/command.cpp @@ -39,8 +39,18 @@ namespace control { - /** */ + LUMIERA_ERROR_DEFINE (UNBOUND_ARGUMENTS, "Mutation functor not yet usable, because arguments aren't bound"); + LUMIERA_ERROR_DEFINE (MISSING_MEMENTO, "Undo functor not yet usable, because no undo state has been captured"); + + + /** */ + Command& + Command::get (Symbol cmdID) + { + UNIMPLEMENTED ("fetch an existing command from the internal cmd registry"); + } + diff --git a/src/proc/control/command.hpp b/src/proc/control/command.hpp index 4d24e961e..d48dba207 100644 --- a/src/proc/control/command.hpp +++ b/src/proc/control/command.hpp @@ -58,6 +58,12 @@ namespace control { { public: + static Command& get (Symbol cmdID); + + virtual ~Command() {}; + + virtual void operator() () =0; + virtual void undo () =0; }; ////////////////TODO currently just fleshing out the API.... diff --git a/src/proc/control/proc-dispatcher.hpp b/src/proc/control/proc-dispatcher.hpp index d6e221838..b0783a940 100644 --- a/src/proc/control/proc-dispatcher.hpp +++ b/src/proc/control/proc-dispatcher.hpp @@ -45,7 +45,7 @@ namespace control { - using lumiera::Symbol; +// using lumiera::Symbol; // using std::tr1::shared_ptr; diff --git a/tests/components/proc/control/command-basic-test.cpp b/tests/components/proc/control/command-basic-test.cpp index a15e9d97f..a47209ad7 100644 --- a/tests/components/proc/control/command-basic-test.cpp +++ b/tests/components/proc/control/command-basic-test.cpp @@ -39,9 +39,6 @@ #include "lib/meta/typelist.hpp" #include "lib/meta/typelistutil.hpp" #include "lib/meta/generator.hpp" -#include "lib/meta/function.hpp" -#include "lib/meta/function-closure.hpp" -#include "lib/meta/tuple.hpp" #include @@ -69,245 +66,10 @@ namespace test { // 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; - ////////////////////////////////////////////TODO braindump - - - /** - * 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::List 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 - < typename TY - , class BASE - , class TUP - , uint idx - > - struct ParamAccessor - : BASE - { - ParamAccessor(TUP& tuple) - : BASE(tuple) - { - cout << showSizeof(tuple.template getAt()) << endl; - } - - ////////////////////TODO the real access operations (e.g. for serialising) go here - }; - - template - struct ParamAccessor - : TUP - { - ParamAccessor(TUP& tuple) - : TUP(tuple) - { } - - ////////////////////TODO the recursion-end of the access operations goes here - }; - - - - template - class Closure - : public CmdClosure - { - typedef typename FunctionSignature< function >::Args Args; - - typedef Tuple ArgTuple; - - typedef BuildTupleAccessor BuildAccessor; - typedef typename BuildAccessor::Accessor ParamStorageTuple; - - ParamStorageTuple params_; - - public: - 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; - } - - template - < typename T1 - , typename T2 - > - UndoDefinition& ///////TODO return here the completed Command - bind ( T1& p1 - , T2& p2 - ) - { - typedef Types ArgTypes; - Tuple params(p1,p2); - Closure clo (params); - - cout << showSizeof(clo) << endl; - UNIMPLEMENTED ("complete Command definition by closing all functions"); - 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); - } - }; @@ -372,16 +134,16 @@ namespace test { ; - Command ourCmd = Command::get("test.command1"); + Command& ourCmd = Command::get("test.command1"); // invoke the command - ASSERT (obj == Time(5)); + ASSERT (*obj == Time(5)); ourCmd(); - ASSERT (obj == Time(5) + Time(randVal)); + ASSERT (*obj == Time(5) + Time(randVal)); // undo the effect of the command ourCmd.undo(); - ASSERT (obj == Time(5)); + ASSERT (*obj == Time(5)); } }; diff --git a/tests/components/proc/control/command-mutation-test.cpp b/tests/components/proc/control/command-mutation-test.cpp index 38a124e2b..5d9547a32 100644 --- a/tests/components/proc/control/command-mutation-test.cpp +++ b/tests/components/proc/control/command-mutation-test.cpp @@ -33,19 +33,20 @@ //#include "proc/mobject/placement-index.hpp" //#include "proc/mobject/explicitplacement.hpp" #include "proc/control/command-mutation.hpp" +#include "lib/meta/typelist.hpp" #include "lib/meta/tuple.hpp" //#include "lib/lumitime.hpp" //#include "lib/util.hpp" -//#include +#include //#include #include #include -//using std::tr1::bind; +using std::tr1::bind; //using std::tr1::placeholders::_1; //using std::tr1::placeholders::_2; -//using std::tr1::function; +using std::tr1::function; //using boost::format; //using lumiera::Time; //using util::contains; @@ -61,8 +62,10 @@ namespace test { // using session::test::TestClip; // using lumiera::P; + using namespace lumiera::typelist; using lumiera::typelist::Tuple; - using control::CommandClosure; + + using control::CmdClosure; @@ -70,22 +73,19 @@ namespace test { namespace { + + int testVal; ///< used to verify the effect of testFunc + void - operate (P