diff --git a/src/proc/control/command-closure.hpp b/src/proc/control/command-closure.hpp index 91052aeae..f309d0aef 100644 --- a/src/proc/control/command-closure.hpp +++ b/src/proc/control/command-closure.hpp @@ -217,21 +217,6 @@ namespace control { }; - /** - * Special kind of Closure, which \em decorates an existing Closure - * and provides a captured state memento as additional parameter on invocation. - * - * @todo concept isn't clear yet. Multiple MementoClosurese are to decorate a single Closure; - * they have to match and extract the concrete type of the Closure and the provided Memento, - * but the latter needs to be erased immediately. Basically, MementoClosure must be able - * to stand-in for an simple parameter closure. - */ - class MementoClosure - : public CmdClosure - { - - }; - ////////////////TODO currently just fleshing out the API.... diff --git a/src/proc/control/command-mutation.hpp b/src/proc/control/command-mutation.hpp index 6afe61137..4bbede998 100644 --- a/src/proc/control/command-mutation.hpp +++ b/src/proc/control/command-mutation.hpp @@ -38,6 +38,7 @@ //#include "pre.hpp" #include "lib/error.hpp" #include "proc/control/command-closure.hpp" +#include "proc/control/memento-closure.hpp" //#include #include @@ -57,13 +58,17 @@ namespace control { using std::string; + 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 + + /** * @todo Type-comment */ class Mutation { CmdFunctor func_; - Closure* clo_; + CmdClosure* clo_; public: template @@ -76,11 +81,11 @@ namespace control { virtual Mutation& - close (Closure& cmdClosure) + close (CmdClosure& cmdClosure) { REQUIRE (!clo_, "Lifecycle error: already closed over the arguments"); REQUIRE (func_, "Param error: not bound to a valid function"); - func_ = cmdClosure->bindArguments(func_); + func_ = cmdClosure.bindArguments(func_); clo_ = &cmdClosure; return *this; } @@ -97,7 +102,7 @@ namespace control { /* == diagnostics == */ - typedef PClosure Mutation::*_unspecified_bool_type; + typedef CmdClosure* Mutation::*_unspecified_bool_type; /** implicit conversion to "bool" */ operator _unspecified_bool_type() const { return isValid()? &Mutation::clo_ : 0; } // never throws @@ -169,7 +174,7 @@ namespace control { virtual Mutation& - close (Closure& cmdClosure) + close (CmdClosure& cmdClosure) { REQUIRE (!memento_, "Lifecycle error: already closed over the arguments"); REQUIRE (captureFunc_, "Param error: not bound to a valid function"); @@ -215,9 +220,6 @@ 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 diff --git a/src/proc/control/memento-closure.hpp b/src/proc/control/memento-closure.hpp new file mode 100644 index 000000000..f97b1337e --- /dev/null +++ b/src/proc/control/memento-closure.hpp @@ -0,0 +1,114 @@ +/* + MEMENTO-CLOSURE.hpp - capturing and providing state for undoing commands + + 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. + +*/ + + +/** @file memento-closure.hpp + ** Extension to the CmdClosure for storing and retrieving a state memento. + ** //TODO + ** + ** @see CmdClosure + ** @see UndoMutation + ** @see memento-closure-test.cpp + ** + */ + + + +#ifndef CONTROL_MEMENTO_CLOSURE_H +#define CONTROL_MEMENTO_CLOSURE_H + +//#include "pre.hpp" +//#include "lib/meta/typelist.hpp" ////////////////TODO include these?? +//#include "lib/meta/function.hpp" +//#include "lib/meta/function-closure.hpp" +//#include "lib/meta/function-erasure.hpp" +//#include "lib/meta/tuple.hpp" +#include "proc/control/command-closure.hpp" +#include "lib/util.hpp" + +//#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 util::unConst; + 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::TupleApplicator; +// using lumiera::typelist::FunErasure; +// using lumiera::typelist::StoreFunction; + +// using lumiera::typelist::NullType; + + + + /** + * Special kind of Closure, which \em decorates an existing Closure + * and provides a captured state memento as additional parameter on invocation. + * + * @todo concept isn't clear yet. Multiple MementoClosurese are to decorate a single Closure; + * they have to match and extract the concrete type of the Closure and the provided Memento, + * but the latter needs to be erased immediately. Basically, MementoClosure must be able + * to stand-in for an simple parameter closure. + */ + class MementoClosure + : public CmdClosure ///////////TODO hierarachy? + { + public: + + virtual PClosure clone() const =0; + + virtual operator string() const =0; + + virtual CmdFunctor bindArguments (CmdFunctor&) =0; + + + ////////////TODO how to give access to the following dedicated API? + CmdClosure& decorate (CmdClosure& core) + { + return *this; // TODO would be nice, but probably won't be thus simple ;-) + } + }; + + ////////////////TODO currently just fleshing out the API.... + + + + +} // namespace control +#endif diff --git a/tests/45controller.tests b/tests/45controller.tests index b49080ee9..761354de1 100644 --- a/tests/45controller.tests +++ b/tests/45controller.tests @@ -9,3 +9,7 @@ END PLANNED "CommandMutation_test" CommandMutation_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 "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/memento-closure.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::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::rand; +using std::cout; +using std::endl; + + +namespace control { +namespace test { + + using lib::test::showSizeof; + +// using session::test::TestClip; +// using lumiera::P; + using namespace lumiera::typelist; + using lumiera::typelist::Tuple; + + using control::CmdClosure; + + + + + + + namespace { /////////////////TODO: use a more interesting function here..... + + int testVal=0; ///< used to verify the effect of testFunc + + void + testFunc (int val) + { + testVal += val; + } + + int + capture () + { + return testVal; + } + + } + + + + /*************************************************************************** + * Verify the state capturing mechanism (memento), which is used + * to implement the Undo() functionality for Proc-Layer commands + * + * @see control::Command + * @see control::CmdClosure + * @see control::UndoMutation + * @see command-mutation-test.hpp + */ + class MementoClosure_test : public Test + { + + virtual void + run (Arg) + { + checkStateCapturingClosure(); + } + + + /** @test check the functionality used to implement UndoMutation: + * bind an undo function and a state capturing function + * and use the latter to define the special CmdClosure + * with the ability hold the memento and bind it into + * the relevant parameter of the undo function. + * Verify that, after closing the functions, actually + * state is captured by each invocation. + */ + void + checkStateCapturingClosure () + { + function undo_func = bind (&testFunc,_1); + function cap_func = bind (&capture ); + + MementoClosure memClo (cap_func); + CmdFunctor closed_cap_func = memClo.bindArguments (cap_func); + Tuple > param; + Closure clo (param); + cout << "plain param values: " << clo << endl; + + Closure extendedClo = memClo.decorate (clo); + cout << "params including memento storage: " << extendedClo << endl; + + CmdFunctor closed_undo_func = extendedClo.bindArguments (undo_func); + + VERIFY_ERROR (MISSING_MEMENTO, closed_undo_func() ); // invalid, because no state was captured + + int rr (rand() %100); + + testVal = rr; + closed_cap_func(); // invoke state capturing + + cout << "params including memento: " << memClo << endl; + cout << "captured memento state : " << extendedClo << endl; + + testVal = -10; // meanwhile "somehow" mutate the state + + closed_undo_func(); // invoking the undo() feeds back the memento + ASSERT (rr == testVal); // which is then restored into the state + + // this cycle can be repeated with different state values + rr = (rand() %100); + testVal = rr; + closed_cap_func(); // capture new state + cout << "params including memento: " << memClo << endl; + // ....note the changed memento! + testVal = -20; + closed_undo_func(); + ASSERT (rr == testVal); + } + }; + + + /** Register this test class... */ + LAUNCHER (MementoClosure_test, "unit controller"); + + +}} // namespace control::test