LUMIERA.clone/src/proc/control/command-impl-clone-builder.hpp

184 lines
5.9 KiB
C++
Raw Normal View History

/*
COMMAND-IMPL-CLONE-BUILDER.hpp - Cloning command implementation without disclosing concrete type
2010-12-17 23:28:49 +01:00
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2010-12-17 23:28:49 +01:00
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
2010-12-17 23:28:49 +01:00
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.
2010-12-17 23:28:49 +01:00
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.
2010-12-17 23:28:49 +01:00
*/
/** @file command-impl-clone-builder.hpp
** Helper for creating an implementation clone, based on the visitor pattern.
** This file deals with the problem of creating a clone from top level without
** any specific type information. While generally this means passing down the
** allocation interface, the specific problem here is that multiple parts of the
** command implementation need to be cloned and re-wired with the cloned partners,
** which requires re-creating the specifically typed context used at initial setup.
**
** @todo Ticket #301 : it may well be that the need for such a facility is a symptom
** of misaligned design, but I rather doubt so -- because both the memento holder and
** the command closure need a specifically typed context, and there is no reason
** for combining them into a single facility.
**
** @see CommandRegistry#createCloneImpl
** @see CommandImpl
** @see StorageHolder#createClone
** @see command-clone-builder-test.cpp
**
*/
#ifndef CONTROL_COMMAND_IMPL_CLONE_BUILDER_H
#define CONTROL_COMMAND_IMPL_CLONE_BUILDER_H
#include "proc/control/command-mutation.hpp"
#include "lib/typed-allocation-manager.hpp"
#include "lib/opaque-holder.hpp"
#include <boost/noncopyable.hpp>
namespace proc {
namespace control {
using lib::TypedAllocationManager;
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<typename ARG>
ARG&
downcast()
{
REQUIRE (INSTANCEOF (ARG, newClosure_.get()));
return static_cast<ARG&> (*newClosure_);
}
public:
template<typename ARG>
ClonedContext ( ARG const& origArgHolder
, TypedAllocationManager& allocator
)
: newClosure_(allocator.create<ARG> (origArgHolder))
, newUndoFunctor_(downcast<ARG>().getMementoWiring())
{ }
};
}//(End) impl namespace
/**
* Visitor to support creating a CommandImpl clone.
* Created and managed by CommandRegistry, on clone creation
* an instance of this builder object is passed down to re-gain
* a fully typed context, necessary for re-wiring the undo functors
* and the memento storage within the cloned parts.
*/
class CommandImplCloneBuilder
: public boost::noncopyable
{
typedef InPlaceBuffer<impl::CloneContext, sizeof(impl::ClonedContext)> ContextHolder;
TypedAllocationManager& allocator_;
ContextHolder newContext_;
public:
CommandImplCloneBuilder (TypedAllocationManager& allo)
: allocator_(allo)
{ }
/** to be executed from within the specifically typed context
* of a concrete command StorageHolder; 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<typename ARG>
void
buildCloneContext (ARG const& origArgHolder)
{
REQUIRE (!newContext_->isValid(), "Lifecycle-Error");
newContext_.create<impl::ClonedContext> (origArgHolder, allocator_);
}
/** after visitation: use pre-built bits to provide a cloned UndoFunctor */
UndoMutation const&
clonedUndoMutation ()
{
REQUIRE (newContext_->isValid());
return newContext_->getUndoFunc();
}
/** after visitation: provide cloned StorageHolder,
* but already stripped down to the generic usage type */
PClo const&
clonedClosuere ()
{
REQUIRE (newContext_->isValid());
return newContext_->getClosure();
}
};
}} // namespace proc::control
#endif