LUMIERA.clone/src/proc/control/command-closure.hpp

332 lines
11 KiB
C++
Raw Normal View History

2009-06-08 04:46:07 +02:00
/*
COMMAND-CLOSURE.hpp - defining execution targets and parameters for commands
2010-12-17 23:28:49 +01:00
2009-06-08 04:46:07 +02:00
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
2010-12-17 23:28:49 +01:00
2009-06-08 04:46:07 +02: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.
2009-06-08 04:46:07 +02:00
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
2009-06-08 04:46:07 +02: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
2009-06-08 04:46:07 +02:00
*/
/** @file command-closure.hpp
** A closure enabling self-contained execution of commands within the ProcDispatcher.
** After defining a proc-layer command, at some point the function arguments
** of the contained operation are "closed" by storing concrete argument values.
** These values will be fed later on to the operation when the command is invoked.
**
** Most of the command machinery accesses this function closure through the generic
** interface CmdClosure, while, when defining a command, subclasses typed to the specific
** function arguments are created. Especially, there is an StorageHolder template,
** which is used to define the storage for the concrete arguments. This StorageHolder
** internally contains an OpClosure<SIG> instance (where SIG is the signature of the
** actual command operation function), which implements the invocation of the
** operation function with the stored argument tuple.
**
** \par Command Closure and Lifecycle
** When defining a command, Mutation objects are to be created based on a concrete function.
** These are stored embedded into a type erasure container, thus disposing the specific type
** information of the function and function arguments. Each command needs an Mutation object
** holding the command operation and an UndoMutation holding the undo functor.
**
** 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. Effectively, this means "closing" the Mutation (and UNDO) functor(s)) with the
** actual function arguments. These arguments are stored embedded within an StorageHolder,
** which thereby acts as closure. Besides, the StorageHolder also has to accommodate for
** storage holding the captured UNDO state (memento). Internally the StorageHolder
** has to keep track of the actual types, thus allowing to re-construct the concrete
** function signature when closing the Mutation.
**
** Finally, when invoking the command, it passes a \c CmdClosure& to the Mutation object,
** which allows the embedded function to be called with the concrete arguments. Besides
** just invoking it, a command can also be used like a prototype object. To support this
** use case it is possible to re-bind to a new set of command arguments, and to create
** a clone copy of the argument (holder) without disclosing the actual types involved.
**
2009-06-08 04:46:07 +02:00
** @see Command
** @see ProcDispatcher
** @see command-argument-holder.hpp
2009-06-08 04:46:07 +02:00
**
*/
#ifndef CONTROL_COMMAND_CLOSURE_H
#define CONTROL_COMMAND_CLOSURE_H
2009-07-12 18:55:33 +02:00
#include "lib/bool-checkable.hpp"
#include "lib/meta/typelist.hpp"
#include "lib/meta/function.hpp"
#include "lib/meta/function-closure.hpp"
2009-06-20 09:22:33 +02:00
#include "lib/meta/function-erasure.hpp"
#include "lib/meta/tuple-helper.hpp"
#include "lib/meta/tuple-record-init.hpp"
#include "lib/meta/maybe-compare.hpp"
#include "lib/format-cout.hpp"
2009-06-20 23:17:22 +02:00
#include "lib/util.hpp"
#include "proc/control/argument-erasure.hpp"
#include "lib/typed-allocation-manager.hpp"
2009-06-08 04:46:07 +02:00
#include <memory>
#include <functional>
#include <sstream>
#include <string>
2009-06-08 04:46:07 +02:00
2009-06-08 04:46:07 +02:00
namespace proc {
2009-06-08 04:46:07 +02:00
namespace control {
2011-12-03 02:56:50 +01:00
using lib::meta::FunctionSignature;
using lib::meta::Tuple;
using lib::meta::BuildTupleAccessor;
using lib::meta::func::TupleApplicator;
using lib::meta::FunErasure;
using lib::meta::StoreFunction;
using lib::meta::NullType;
using lib::meta::buildTuple;
2011-12-03 02:56:50 +01:00
using lib::meta::equals_safeInvoke;
using lib::TypedAllocationManager;
using util::unConst;
using std::function;
using std::ostream;
using std::string;
2009-07-12 18:55:33 +02:00
LUMIERA_ERROR_DECLARE (UNBOUND_ARGUMENTS); ///< Command functor not yet usable, because arguments aren't bound
2009-06-20 09:22:33 +02:00
/**
* A neutral container internally holding
* the functor used to implement the Command
*/
typedef FunErasure<StoreFunction> CmdFunctor;
class CommandImplCloneBuilder;
class CmdClosure;
typedef std::shared_ptr<CmdClosure> PClo;
/** Interface */
class CmdClosure
2009-07-12 18:55:33 +02:00
: public lib::BoolCheckable<CmdClosure>
{
public:
virtual ~CmdClosure() {}
virtual operator string() const =0;
virtual bool isValid () const =0; ///< does this closure hold a valid argument tuple?
virtual bool isCaptured () const =0; ///< does this closure hold captured UNDO state?
virtual bool equals (CmdClosure const&) const =0; ///< is equivalent to the given other closure?
virtual void bindArguments (Arguments&) =0; ///< store a set of parameter values within this closure
virtual void bindArguments (lib::diff::Rec const&) =0; ///< store a set of parameter values, passed as GenNode sequence
virtual void invoke (CmdFunctor const&) =0; ///< invoke functor using the stored parameter values
virtual void accept (CommandImplCloneBuilder&) const =0; ///< assist with creating clone closure without disclosing concrete type
};
inline ostream& operator<< (ostream& os, const CmdClosure& clo) { return os << string(clo); }
class AbstractClosure
: public CmdClosure
{
bool isValid() const override { return false; }
bool isCaptured() const override { return false; }
void accept (CommandImplCloneBuilder&) const override {}
};
/** Helper for accessing an individual function parameter */
template
< typename TY
, class BASE
, class TUP
, uint idx
>
class ParamAccessor
: public BASE
{
TY & element() { return std::get<idx> (*this); }
TY const& element() const { return std::get<idx> (*this); }
public:
using BASE::BASE;
////////////////////TODO the real access operations (e.g. for serialising) go here
/////////////////////////////////////////////////////////////TICKET #798 : we need to pick up arguments from a lib::diff::Record.
ostream&
dump (ostream& output) const
{
return BASE::dump (output << element() << ',');
}
friend bool
compare (ParamAccessor const& p1, ParamAccessor const& p2)
{
return equals_safeInvoke (p1.element(), p2.element())
&& compare ( static_cast<BASE>(p1)
, static_cast<BASE>(p2) );
}
};
template<class TUP, uint n>
class ParamAccessor<NullType, TUP, TUP, n> ///< used for recursion end of implementation functions
: public TUP
{
public:
ParamAccessor (TUP const& tup)
: TUP(tup)
{ }
////////////////////TODO the recursion-end of the access operations goes here
ostream&
dump (ostream& output) const
{
return output;
}
friend bool
compare (ParamAccessor const&, ParamAccessor const&)
{
return true;
}
};
2009-06-08 04:46:07 +02:00
/**
* closure to deal with the actual command operation.
* This includes holding the invocation parameter tuple
*/
template<typename SIG>
class OpClosure
: public AbstractClosure
2009-06-08 04:46:07 +02:00
{
using Args = typename FunctionSignature< function<SIG> >::Args;
using Builder = BuildTupleAccessor<ParamAccessor, Args>;
using ParamStorageTuple =typename Builder::Product;
ParamStorageTuple params_;
2009-06-08 04:46:07 +02:00
protected:
OpClosure()
: params_(Tuple<Args>())
{ }
2009-06-08 04:46:07 +02:00
public:
using ArgTuple = Tuple<Args>;
2009-07-12 18:55:33 +02:00
explicit
OpClosure (ArgTuple const& args)
: params_(args)
{ }
/** create a clone copy of this, without disclosing the exact type */
PClo
createClone (TypedAllocationManager& storageManager)
{
return storageManager.create<OpClosure> (*this);
}
/** assign a new parameter tuple to this */
void
bindArguments (Arguments& args) override
{
params_ = args.get<ArgTuple>();
}
/** assign a new set of parameter values to this.
* @note the values are passed packaged into a sequence
* of GenNode elements. This is the usual way
* arguments are passed from the UI-Bus
*/
void
bindArguments (lib::diff::Rec const& paramData) override
{
params_ = buildTuple<Args> (paramData);
}
/** Core operation: use the embedded argument tuple for invoking a functor
* @param unboundFunctor an function object, whose function arguments are
* required to match the types of the embedded ParamStorageTuple
2009-06-20 09:22:33 +02:00
* @note ASSERTION failure if the function signature
* doesn't match the argument types tuple.
* @note the functor might actually \em modify the param values.
* Thus this function can't be const.
2009-06-20 09:22:33 +02:00
*/
void
invoke (CmdFunctor const& unboundFunctor) override
2009-06-20 09:22:33 +02:00
{
TupleApplicator<SIG> apply_this_arguments(params_);
apply_this_arguments (unboundFunctor.getFun<SIG>());
2009-06-20 09:22:33 +02:00
}
2009-06-08 04:46:07 +02:00
operator string() const override
{
std::ostringstream buff;
params_.dump (buff << "OpClosure(" );
string dumped (buff.str());
if (10 < dumped.length())
// remove trailing comma...
return dumped.substr (0, dumped.length()-1) +")";
else
return dumped+")";
}
bool isValid () const override { return true; }
/// Supporting equality comparisons...
friend bool operator== (OpClosure const& c1, OpClosure const& c2) { return compare (c1.params_, c2.params_); }
friend bool operator!= (OpClosure const& c1, OpClosure const& c2) { return not (c1 == c2); }
bool
equals (CmdClosure const& other) const override
{
const OpClosure* toCompare = dynamic_cast<const OpClosure*> (&other);
return (toCompare)
&& (*this == *toCompare);
}
2009-06-08 04:46:07 +02:00
};
2009-06-08 04:46:07 +02:00
}} // namespace proc::control
2009-06-08 04:46:07 +02:00
#endif