From 9aa5ba560c1c780848db4f2294158f0ca50001a5 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Fri, 10 Jul 2009 19:04:01 +0200 Subject: [PATCH] finish and tidy up control::Mutation, unit test pass --- src/lib/bool-checkable.hpp | 4 +- src/lib/opaque-holder.hpp | 2 +- src/proc/control/command-closure.hpp | 33 ++++---- src/proc/control/command-mutation.hpp | 73 +++++++++++------ src/proc/control/memento-tie.hpp | 1 - tests/45controller.tests | 8 +- tests/components/Makefile.am | 2 +- .../proc/control/command-basic-test.cpp | 2 +- .../proc/control/command-mutation-test.cpp | 82 +++++++++---------- 9 files changed, 119 insertions(+), 88 deletions(-) diff --git a/src/lib/bool-checkable.hpp b/src/lib/bool-checkable.hpp index bbae1a35f..dd03610b8 100644 --- a/src/lib/bool-checkable.hpp +++ b/src/lib/bool-checkable.hpp @@ -88,8 +88,8 @@ namespace lib { * \c isValid() function, the conversion operator returns either a * bound or unbound member pointer. * - * @todo list some usage examples here - * @see bool-checkable-test.cpp + * @see bool-checkable-test.cpp + * @see control::Mutation usage example */ template< class T ///< the target type implementing \c isValid() , class PAR = imp::Dummy ///< optional parent for inheritance chain diff --git a/src/lib/opaque-holder.hpp b/src/lib/opaque-holder.hpp index d3a9b38fc..2fab78582 100644 --- a/src/lib/opaque-holder.hpp +++ b/src/lib/opaque-holder.hpp @@ -381,7 +381,7 @@ namespace lib { template InPlaceAnyHolder(SUB const& obj) - { + { place_inBuff (obj); } diff --git a/src/proc/control/command-closure.hpp b/src/proc/control/command-closure.hpp index ff2dc3ec6..c4ae309fc 100644 --- a/src/proc/control/command-closure.hpp +++ b/src/proc/control/command-closure.hpp @@ -45,7 +45,8 @@ #include #include -#include +#include +#include #include @@ -119,14 +120,12 @@ namespace control { ParamAccessor(TUP const& tuple) : BASE(tuple) - { - cout << showSizeof(element()) << endl; //////////TODO remove this test code - } + { } - string - dump (string const& prefix = "(") const + ostream& + dump (ostream& output) const { - return BASE::dump (prefix+element()+","); + return BASE::dump (output << element() << ','); } @@ -144,14 +143,10 @@ namespace control { ////////////////////TODO the recursion-end of the access operations goes here - string - dump (string const& prefix ="(") const + ostream& + dump (ostream& output) const { - if (1 < prefix.length()) - // remove trailing comma... - return prefix.substr (0, prefix.length()-1) +")"; - else - return prefix+")"; + return output; } }; @@ -212,7 +207,15 @@ namespace control { operator string() const { - UNIMPLEMENTED ("how to do a string conversion on the variable argument tuple??"); + std::ostringstream buff; + params_.dump (buff << "Closure(" ); + + string dumped (buff.str()); + if (1 < dumped.length()) + // remove trailing comma... + return dumped.substr (0, dumped.length()-1) +")"; + else + return dumped+")"; } }; diff --git a/src/proc/control/command-mutation.hpp b/src/proc/control/command-mutation.hpp index 223e36a6f..db3152785 100644 --- a/src/proc/control/command-mutation.hpp +++ b/src/proc/control/command-mutation.hpp @@ -22,11 +22,32 @@ /** @file command-mutation.hpp - ** The core of a Proc-Layer command: functor containing the actual operation to be executed. - ** //TODO - ** + ** Core of a Proc-Layer command: functor containing the actual operation to be executed. + ** Each command holds two of these functors: one representing the actual operation + ** and one to undo the effect of this operation. The latter involves the capturing + ** and storing of a "memento" value behind the scenes. But towards Command, the + ** Mutation acts as interface to conceal these details, as well as the actual + ** type and parameters of the functions to be invoked. Thus, Mutation's + ** public interface just consists of a function call operator \c void() . + ** + ** \par Lifecycle + ** Mutation objects are to be created based on a concrete function object, which then + ** gets embedded into a type erasure container, thus disposing the specific type information. + ** Moreover, building on this lib::OpaqueHolder yields a fixed size storage for Mutation objects, + ** allowing them to be embedded immediately within the Command instance. + ** + ** Later on, any command needs to be made ready for execution by binding it to a specific + ** execution environment, which especially includes the target objects to be mutated by the + ** command. This procedure includes "closing" the Mutation (and UNDO) functor(s) with the + ** actual function arguments. These arguments are stored embedded within an ArgumentHolder, + ** which thereby acts as closure. Besides, the ArgumentHolder also has to accommodate for + ** storage holding the captured UNDO state (memento). Thus, internally the ArgumentHolder + ** has to keep track of the actual types, thus allowing to re-construct the concrete + ** function signature when closing the Mutation. + ** ** @see Command ** @see ProcDispatcher + ** @see MementoTie binding memento state ** */ @@ -41,9 +62,6 @@ #include "proc/control/command-closure.hpp" #include "proc/control/memento-tie.hpp" -//#include -#include -#include #include #include @@ -51,10 +69,6 @@ namespace control { -// using lumiera::Symbol; -// using std::tr1::shared_ptr; - using boost::scoped_ptr; - using std::tr1::function; using std::ostream; using std::string; @@ -63,7 +77,13 @@ namespace control { /** - * @todo Type-comment + * Unspecific command functor for implementing Proc-Layer Command. + * To be created from an tr1::function object, which later on + * can be \link #close closed \endlink with a set of actual + * function arguments. The concrete type of the function + * and the arguments is concealed (erased) on the interface, + * while the unclosed/closed - state of the functor can be + * checked by bool() conversion. */ class Mutation : public lib::BoolCheckable @@ -105,7 +125,8 @@ namespace control { /** diagnostics */ operator string() const { - return isValid()? string (*clo_) : "Mutation(state missing)"; + return isValid()? "Mutation("+string (*clo_)+")" + : "Mutation(untied)"; } virtual bool @@ -114,7 +135,8 @@ namespace control { return func_ && clo_; } - protected: + + private: void invoke (CmdFunctor & closedFunction) { @@ -128,8 +150,21 @@ namespace control { + + + + /** - * @todo Type-comment + * Specialised version of the command Mutation functor, + * used to implement the UNDO functionality. The operation + * executed when invoking this functor is the UNDO operation + * of the respective command; additionally we need another + * functor to capture the state to be restored on UNDO. + * Both functors are wired up internally to cooperate + * and store the state (memento), which is implemented + * by the specifically typed MementoTie object passed + * in on construction. All these specific details + * are concealed on the interface */ class UndoMutation : public Mutation @@ -143,11 +178,6 @@ namespace control { , captureMemento_(mementoHolder.tieCaptureFunc()) { } -// UndoMutation (UndoMutation const& o) -// : Mutation(o) -// , captureMemento_(o.captureMemento_) -// { } - virtual Mutation& close (CmdClosure& cmdClosure) @@ -172,16 +202,13 @@ namespace control { private: virtual bool - isValid () const + isValid () const { return Mutation::isValid() && captureMemento_; } }; - ////////////////TODO currently just fleshing out the API.... - - } // namespace control diff --git a/src/proc/control/memento-tie.hpp b/src/proc/control/memento-tie.hpp index b5d42fd15..ed4a44380 100644 --- a/src/proc/control/memento-tie.hpp +++ b/src/proc/control/memento-tie.hpp @@ -50,7 +50,6 @@ namespace control { - using std::tr1::ref; using lumiera::typelist::func::bindLast; using lumiera::typelist::func::chained; diff --git a/tests/45controller.tests b/tests/45controller.tests index 46a33000c..5f4cc95f2 100644 --- a/tests/45controller.tests +++ b/tests/45controller.tests @@ -11,10 +11,14 @@ PLANNED "CommandArgument_test" CommandArgument_test < -//#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; @@ -60,25 +41,15 @@ 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 namespace lumiera::typelist; using control::CmdClosure; - - - - - namespace { - + namespace { /* ======= test functions to bind ========= */ + int testVal=0; ///< used to verify the effect of testFunc - + void testFunc (int val) { @@ -114,6 +85,7 @@ namespace test { { checkMutation(); checkUndoMutation(); + checkStateCapturingMechanism(); } @@ -125,11 +97,12 @@ namespace test { void checkMutation () { - function funky = bind (testFunc, _1); + function funky = testFunc; Mutation functor (funky); ASSERT (!functor); VERIFY_ERROR (UNBOUND_ARGUMENTS, functor() ); + cout << functor << endl; Tuple > param = tuple::make(23); Closure close_over (param); @@ -139,6 +112,7 @@ namespace test { ASSERT (functor); cout << "param values: " << clo << endl; + cout << functor << endl; testVal = 0; functor(); @@ -154,8 +128,8 @@ namespace test { * captured state value. Consequently this time the \em operation * which is to be undone would have the signature \c void(void) . * Obviously this is a rather silly "undo" function, but it is - * easy to check in a unit test. To carry out this test, we first - * have to trigger the state capturing mechanism; after that, + * easy to check for unit testing. To carry out this test, we + * first have to trigger the state capturing mechanism; after that, * invoking the UndoMutation will call the testFunc with the * previously captured state. * @note Mutation and UndoMutation are value objects, but they refer @@ -166,27 +140,29 @@ namespace test { void checkUndoMutation () { - function undo_func = bind (&testFunc,_1); - function cap_func = bind (&capture ); + function undo_func = testFunc; + function cap_func = capture; typedef MementoTie MemHolder; MemHolder mementoHolder (undo_func,cap_func); UndoMutation undoFunctor (mementoHolder); ASSERT (!undoFunctor); + ASSERT (!mementoHolder); VERIFY_ERROR (UNBOUND_ARGUMENTS, undoFunctor() ); Tuple > param; Closure clo (param); undoFunctor.close(clo); - ASSERT (!undoFunctor); + ASSERT ( undoFunctor); + ASSERT (!mementoHolder); VERIFY_ERROR (MISSING_MEMENTO, undoFunctor() ); VERIFY_ERROR (MISSING_MEMENTO, mementoHolder.getState() ); testVal = 11; undoFunctor.captureState(); - ASSERT (undoFunctor); + ASSERT (mementoHolder); ASSERT (testVal == 11); int mem = mementoHolder.getState(); @@ -217,11 +193,33 @@ namespace test { } + /** @test check the undo memento capturing mechanism in isolation + * @see memento-tie-test.cpp more in-depth coverage */ + void + checkStateCapturingMechanism () + { + typedef MementoTie MemHolder; + + MemHolder mementoHolder (testFunc, capture); + + function bound_undo_func = mementoHolder.tieUndoFunc(); + function bound_cap_func = mementoHolder.tieCaptureFunc(); + + + int rr (rand() % 100); + testVal = rr; + bound_cap_func(); // invoke state capturing + ASSERT (rr == mementoHolder.getState()); + + testVal = 10; // meanwhile "somehow" mutate the state + bound_undo_func(); // invoking the undo() feeds back the memento + ASSERT (testVal == 10+rr); + } }; /** Register this test class... */ LAUNCHER (CommandMutation_test, "unit controller"); - - + + }} // namespace control::test