diff --git a/src/proc/control/command-argument-holder.hpp b/src/proc/control/command-argument-holder.hpp index 244c72fdb..780ec0e56 100644 --- a/src/proc/control/command-argument-holder.hpp +++ b/src/proc/control/command-argument-holder.hpp @@ -45,6 +45,7 @@ #include "lib/typed-allocation-manager.hpp" #include "proc/control/command-closure.hpp" #include "proc/control/memento-tie.hpp" +#include "proc/control/command-impl-clone-builder.hpp" #include "lib/opaque-holder.hpp" #include @@ -194,11 +195,12 @@ namespace control { memento_.template create (*oAh.memento_); } - /** create a clone copy, without disclosing the exact type */ - PClo - createClone (TypedAllocationManager& storageManager) + /** assist with creating a clone copy; + * this results in invocation of the copy ctor */ + void + accept (CommandImplCloneBuilder& visitor) const { - return storageManager.create (*this); + visitor.buildCloneContext (*this); } @@ -230,6 +232,15 @@ namespace control { return memento_.template create (undoFunc,captureFunc); } + /** just re-access an existing memento storage wiring. + * Used when cloning the closure */ + MementoTie& + getMementoWiring () + { + REQUIRE (!empty()); + return *memento_; + } + /** direct "backdoor" access to stored memento value. diff --git a/src/proc/control/command-impl-clone-builder.hpp b/src/proc/control/command-impl-clone-builder.hpp index b00e59df4..21848f2a8 100644 --- a/src/proc/control/command-impl-clone-builder.hpp +++ b/src/proc/control/command-impl-clone-builder.hpp @@ -50,12 +50,13 @@ //#include "proc/control/command-closure.hpp" #include "proc/control/command-mutation.hpp" #include "lib/typed-allocation-manager.hpp" +#include "lib/opaque-holder.hpp" //#include "lib/bool-checkable.hpp" #include //#include -#include +//#include //#include @@ -63,7 +64,61 @@ namespace control { using lib::TypedAllocationManager; // using std::tr1::function; - using std::tr1::shared_ptr; +// using std::tr1::shared_ptr; + using lib::InPlaceBuffer; + + + namespace impl { // Helper: type erased context for creating command clones + + struct CloneContext ///< Interface and empty state + { + virtual ~CloneContext() {} + + virtual UndoMutation const& getUndoFunc() { NOTREACHED(); } + virtual PClo const& getClosure() { NOTREACHED(); } + virtual bool isValid() { return false; } + }; + + class ClonedContext + : public CloneContext + { + PClo newClosure_; + UndoMutation newUndoFunctor_; + + virtual UndoMutation const& getUndoFunc() { return newUndoFunctor_; } + virtual PClo const& getClosure() { return newClosure_; } + virtual bool isValid() { return true; } + + + /** helper for accessing the new cloned closure + * through the specific concrete type. As we need + * to access the closure later, after discarding the + * exact type, we can store only a baseclass pointer. + */ + template + ARG& + downcast() + { + REQUIRE (INSTANCEOF (ARG, newClosure_.get())); + + return static_cast (*newClosure_); + } + + + public: + + template + ClonedContext ( ARG const& origArgHolder + , TypedAllocationManager& allocator + ) + : newClosure_(allocator.create (origArgHolder)) + , newUndoFunctor_(downcast().getMementoWiring()) + { } + }; + + }//(End) impl namespace + + @@ -75,76 +130,55 @@ namespace control { * and the memento storage within the cloned parts. */ class CommandImplCloneBuilder -// : public lib::BoolCheckable : public boost::noncopyable { + typedef InPlaceBuffer ContextHolder; + TypedAllocationManager& allocator_; - shared_ptr newClo_; - - - - template - struct _Type - { - typedef typename ARG::SIG_op SIG_op; - typedef typename ARG::SIG_cap SIG_cap; - typedef typename ARG::SIG_undo SIG_undo; - - typedef function Func_op; - typedef function Func_cap; - typedef function Func_undo; - }; -#define _TY(_ID_) typename _Type::_ID_ + ContextHolder newContext_; public: - CommandImplCloneBuilder (TypedAllocationManager allo) + CommandImplCloneBuilder (TypedAllocationManager& allo) : allocator_(allo) - , newClo_() { } - /** visit the CommandImpl given as reference - * to re-gain the contained Closure type context - */ - void - visit (CommandImpl const& sourceImpl) - { - UNIMPLEMENTED ("get access to source context"); - } - - /** to be executed from within the specifically typed context - * of a concrete command ArgumentHolder; prepare the objects - * necessary to re-build a "clone" of the UNDO-Functor. + * of a concrete command ArgumentHolder; allocate a clone copy + * and then prepare a new UNDO-Functor, which is correctly wired + * with the memento holder within this new \em clone closure. + * After that point, these prepared parts can be retrieved + * through the public accessor functions; they will be + * used by the command registry to put together a complete + * clone copy of the original CommandImpl. */ template void - buildCloneContext (shared_ptr pArgHolder) + buildCloneContext (ARG const& origArgHolder) { - UNIMPLEMENTED ("how to reflect context back"); - newClo_ = pArgHolder; + REQUIRE (!newContext_->isValid(), "Lifecycle-Error"); + + newContext_.create (origArgHolder, allocator_); } -#undef _TY /** after visitation: use pre-built bits to provide a cloned UndoFunctor */ UndoMutation const& clonedUndoMutation () { - UNIMPLEMENTED (" getNewUndoMutation ()" ); + REQUIRE (newContext_->isValid()); + return newContext_->getUndoFunc(); } /** after visitation: provide cloned ArgumentHolder, * but already stripped down to the generic usage type */ - shared_ptr const& + PClo const& clonedClosuere () { - REQUIRE (newClo_); - return newClo_; + REQUIRE (newContext_->isValid()); + return newContext_->getClosure(); } }; diff --git a/src/proc/control/command-impl.hpp b/src/proc/control/command-impl.hpp index dd148037e..403c93317 100644 --- a/src/proc/control/command-impl.hpp +++ b/src/proc/control/command-impl.hpp @@ -124,7 +124,7 @@ namespace control { CommandImpl (CommandImpl const& orig, TypedAllocationManager& storageManager) : do_(orig.do_) , undo_(orig.undo_) - , pClo_(orig.pClo_->createClone(storageManager)) +// , pClo_(orig.pClo_->createClone(storageManager)) , defaultPatt_(orig.defaultPatt_) { } @@ -134,7 +134,9 @@ namespace control { * on a argument holder (without knowing the exact type), * we need to delegate the cloning of the arguments down * while providing a means of allocating storage for the clone */ - CommandImpl (CommandImpl const& orig, UndoMutation const& newUndo, shared_ptr& newClosure) + CommandImpl (CommandImpl const& orig + ,UndoMutation const& newUndo + ,shared_ptr const& newClosure) : do_(orig.do_) , undo_(newUndo) , pClo_(newClosure) @@ -142,6 +144,23 @@ namespace control { { } + /** assist with building a clone copy of this CommandImpl. + * By accepting the clone builder as a visitor and dispatching + * this visitation down into the concrete closure, the builder + * can re-gain the fully typed context available on creation + * of the ComandImpl. Within this context, for the clone + * to be created, the UndoMutation has to be re-wired, + * otherwise it would continue to cooperate with + * original closure. + */ + void + prepareClone (CommandImplCloneBuilder& visitor) const + { + ASSERT (pClo_); + pClo_->accept(visitor); + } + + void setArguments (Arguments& args) { diff --git a/tests/components/proc/control/command-clone-builder-test.cpp b/tests/components/proc/control/command-clone-builder-test.cpp index a2c9c2f6b..79ef9f069 100644 --- a/tests/components/proc/control/command-clone-builder-test.cpp +++ b/tests/components/proc/control/command-clone-builder-test.cpp @@ -88,7 +88,7 @@ namespace test { ////////////////////////////////////////////////////////////////////////////////////TODO // PCmdImpl clone = registry.createCloneImpl (*source); CommandImplCloneBuilder cloneBuilder(allo); - cloneBuilder.visit (*source); + source->prepareClone(cloneBuilder); PCmdImpl clone = allo.create (*source, cloneBuilder.clonedUndoMutation() , cloneBuilder.clonedClosuere()); ////////////////////////////////////////////////////////////////////////////////////TODO @@ -166,16 +166,16 @@ namespace test { ASSERT (!copy->canUndo()); testExec.invoke (*copy, "Execute clone"); // EXEC 2 ASSERT (command1::check_ != state_after_exec1); -// ASSERT (copy->canUndo()); + ASSERT (copy->canUndo()); ASSERT (copy != orig); // invoke UNDO on the clone -// testUndo.invoke (*copy, "Undo clone"); // UNDO 2 -// ASSERT (command1::check_ == state_after_exec1); + testUndo.invoke (*copy, "Undo clone"); // UNDO 2 + ASSERT (command1::check_ == state_after_exec1); // invoke UNDO on original testUndo.invoke (*orig, "Undo original"); // UNDO 1 -// ASSERT (command1::check_ ==0); + ASSERT (command1::check_ ==0); ASSERT (copy != orig); }