command frontend sort-of written now, pending integration test

This commit is contained in:
Fischlurch 2009-08-10 01:32:33 +02:00
parent 5988b1d697
commit b9763b6c16
11 changed files with 110 additions and 562 deletions

View file

@ -1,5 +1,5 @@
/*
ARGUMENT-TUPLE-ACCEPT.hpp - helper template providing a bind(...) member function
ARGUMENT-ERASURE.hpp - helper for passing on a dynamic typed argument tuple
Copyright (C) Lumiera.org
2009, Hermann Vosseler <Ichthyostega@web.de>
@ -21,478 +21,31 @@
*/
/** @file argument-tuple-accept.hpp
** The AcceptArgumentBinding template allows to mix in a \c bind(...) function.
** Thereby, the correct number and types of arguments is derived according to
** the function signature given as template parameter. This helper template is
** used for the ArgumentHolder and generally for binding the arguments when
** defining Proc-Layer commands.
**
** @see CommandDef
** @see ArgumentHolder
** @see argument-tuple-accept-test.cpp
**
*/
#ifndef CONTROL_ARGUMENT_ERASURE_H
#define CONTROL_ARGUMENT_ERASURE_H
#ifndef CONTROL_ARGUMENT_TUPLE_ACCEPT_H
#define CONTROL_ARGUMENT_TUPLE_ACCEPT_H
#include "lib/meta/typelist.hpp"
#include "lib/meta/function.hpp"
#include "lib/meta/tuple.hpp"
#include "lib/error.hpp"
namespace control {
namespace bind_arg { // internals....
using namespace lumiera::typelist;
/** @internal mix in a function operator */
template< class TAR, class BA, class RET
, typename TYPES
>
struct AcceptArgs ;
/* specialisations for 0...9 Arguments.... */
template< class TAR, class BA, class RET
> //____________________________________
struct AcceptArgs<TAR,BA,RET, Types<> > ///< Accept dummy binding (0 Arguments)
: BA
{
RET
operator() ()
{
return static_cast<TAR*> (this) -> bindArg (tuple::makeNullTuple() );
}
};
template< class TAR, class BA, class RET
, typename T1
> //_______________________________
struct AcceptArgs<TAR,BA,RET, Types<T1> > ///< Accept binding for 1 Argument
: BA
{
RET
operator() (T1 a1)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
> //________________________________
struct AcceptArgs<TAR,BA,RET, Types<T1,T2> > ///< Accept binding for 2 Arguments
: BA
{
RET
operator() (T1 a1, T2 a2)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
> //________________________________
struct AcceptArgs<TAR,BA,RET, Types<T1,T2,T3> > ///< Accept binding for 3 Arguments
: BA
{
RET
operator() (T1 a1, T2 a2, T3 a3)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
, typename T4
> //________________________________
struct AcceptArgs<TAR,BA,RET, Types<T1,T2,T3,T4> > ///< Accept binding for 4 Arguments
: BA
{
RET
operator() (T1 a1, T2 a2, T3 a3, T4 a4)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3,a4));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
, typename T4
, typename T5
> //________________________________
struct AcceptArgs<TAR,BA,RET, Types<T1,T2,T3,T4,T5> > ///< Accept binding for 5 Arguments
: BA
{
RET
operator() (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
, typename T4
, typename T5
, typename T6
> //________________________________
struct AcceptArgs<TAR,BA,RET, Types<T1,T2,T3,T4,T5,T6> > ///< Accept binding for 6 Arguments
: BA
{
RET
operator() (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
, typename T4
, typename T5
, typename T6
, typename T7
> //________________________________
struct AcceptArgs<TAR,BA,RET, Types<T1,T2,T3,T4,T5,T6,T7> > ///< Accept binding for 7 Arguments
: BA
{
RET
operator() (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
, typename T4
, typename T5
, typename T6
, typename T7
, typename T8
> //________________________________
struct AcceptArgs<TAR,BA,RET, Types<T1,T2,T3,T4,T5,T6,T7,T8> > ///< Accept binding for 8 Arguments
: BA
{
RET
operator() (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7,a8));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
, typename T4
, typename T5
, typename T6
, typename T7
, typename T8
, typename T9
> //________________________________
struct AcceptArgs<TAR,BA,RET, Types<T1,T2,T3,T4,T5,T6,T7,T8,T9> > ///< Accept binding for 9 Arguments
: BA
{
RET
operator() (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7,a8,a9));
}
};
/** @internal mix in a \c bind() function
*/
template< class TAR, class BA, class RET
, typename TYPES
>
struct AcceptBind ;
/* specialisations for 0...9 Arguments.... */
template< class TAR, class BA, class RET
> //____________________________________
struct AcceptBind<TAR,BA,RET, Types<> > ///< Accept dummy binding (0 Arguments)
: BA
{
RET
bind ()
{
return static_cast<TAR*> (this) -> bindArg (tuple::makeNullTuple() );
}
};
template< class TAR, class BA, class RET
, typename T1
> //_______________________________
struct AcceptBind<TAR,BA,RET, Types<T1> > ///< Accept binding for 1 Argument
: BA
{
RET
bind (T1 a1)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
> //________________________________
struct AcceptBind<TAR,BA,RET, Types<T1,T2> > ///< Accept binding for 2 Arguments
: BA
{
RET
bind (T1 a1, T2 a2)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
> //________________________________
struct AcceptBind<TAR,BA,RET, Types<T1,T2,T3> > ///< Accept binding for 3 Arguments
: BA
{
RET
bind (T1 a1, T2 a2, T3 a3)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
, typename T4
> //________________________________
struct AcceptBind<TAR,BA,RET, Types<T1,T2,T3,T4> > ///< Accept binding for 4 Arguments
: BA
{
RET
bind (T1 a1, T2 a2, T3 a3, T4 a4)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3,a4));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
, typename T4
, typename T5
> //________________________________
struct AcceptBind<TAR,BA,RET, Types<T1,T2,T3,T4,T5> > ///< Accept binding for 5 Arguments
: BA
{
RET
bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
, typename T4
, typename T5
, typename T6
> //________________________________
struct AcceptBind<TAR,BA,RET, Types<T1,T2,T3,T4,T5,T6> > ///< Accept binding for 6 Arguments
: BA
{
RET
bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
, typename T4
, typename T5
, typename T6
, typename T7
> //________________________________
struct AcceptBind<TAR,BA,RET, Types<T1,T2,T3,T4,T5,T6,T7> > ///< Accept binding for 7 Arguments
: BA
{
RET
bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
, typename T4
, typename T5
, typename T6
, typename T7
, typename T8
> //________________________________
struct AcceptBind<TAR,BA,RET, Types<T1,T2,T3,T4,T5,T6,T7,T8> > ///< Accept binding for 8 Arguments
: BA
{
RET
bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7,a8));
}
};
template< class TAR, class BA, class RET
, typename T1
, typename T2
, typename T3
, typename T4
, typename T5
, typename T6
, typename T7
, typename T8
, typename T9
> //________________________________
struct AcceptBind<TAR,BA,RET, Types<T1,T2,T3,T4,T5,T6,T7,T8,T9> > ///< Accept binding for 9 Arguments
: BA
{
RET
bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9)
{
return static_cast<TAR*> (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7,a8,a9));
}
};
template<typename SIG>
struct _Type
{
typedef typename FunctionSignature< function<SIG> >::Args Args;
typedef typename FunctionSignature< function<SIG> >::Ret Ret;
typedef Tuple<Args> ArgTuple;
typedef SIG Sig;
};
template<typename TYPES>
struct _Type<Tuple<TYPES> >
{
typedef TYPES Args;
typedef void Ret;
typedef Tuple<TYPES> ArgTuple;
typedef typename FunctionTypedef<void, TYPES>::Sig Sig;
};
struct Dummy {};
} // (END) impl details (bind_arg)
/** Helper Template for building a Functor or function-like class:
* Mix in a function call operator, which mimics the specified signature SIG .
* This template is to be used as a base class to inherit the target type TAR from;
* this target type is assumed to provide a function \bindArg(Tuple<TYPES..>) --
* where \c TYPES... is the sequence of types found in the provided Signature SIG.
*/
template<typename SIG, class TAR, class BASE =bind_arg::Dummy>
class AcceptArgumentTuple
: public bind_arg::AcceptArgs<TAR,BASE, typename bind_arg::_Type<SIG>::Ret
, typename bind_arg::_Type<SIG>::Args>
{
};
/** Helper Template for Proc-Layer control::Command : mix in a \c bind(...) function
* @param SIG function signature to mimic (regarding the arguments and return type)
* @param TAR the target class providing a function \c bindArg(Tuple<Types<T1...> >)
* @param BASE the base class for inheritance chaining
*/
template<typename SIG, class TAR, class BASE =bind_arg::Dummy>
class AcceptArgumentBinding
: public bind_arg::AcceptBind<TAR,BASE, typename bind_arg::_Type<SIG>::Ret
, typename bind_arg::_Type<SIG>::Args>
{
};
/** Variation of AcceptArgumentBinding, allowing to control the return type
* of the generated \c bind(...) functions independently from SIG
*/
template<typename RET, typename SIG, class TAR, class BASE =bind_arg::Dummy>
class AcceptArgumentBindingRet
: public bind_arg::AcceptBind<TAR,BASE, RET
, typename bind_arg::_Type<SIG>::Args>
{
};
/**
* Adapter interface for invoking an argument binding (e.g. as defined through
* AcceptArgumentBinding) \em without the need to disclose the concrete type
* actually accepting the bind call. This is an application of "type erasure"
* Adapter interface for invoking an argument binding for a command
* \em without the need to disclose the concrete types and number of arguments.
* At the receiver side, the concrete type can be restored by a dynamic cast.
* This requires the receiver somehow to know the desired argument types;
* usually this receiver will be an implementation object, whose exact
* type has been erased after definition, while the implementation
* internally of course knows the type and thus can perform an
* dynamic cast on the passed on argument tuple
*/
struct Arguments;
@ -528,10 +81,8 @@ namespace control {
{ }
};
} // namespace control
#endif

View file

@ -489,49 +489,8 @@ namespace control {
/**
* Adapter interface for invoking an argument binding (e.g. as defined through
* AcceptArgumentBinding) \em without the need to disclose the concrete type
* actually accepting the bind call. This is an application of "type erasure"
*/
struct Arguments;
template<typename TUP>
struct TypedArguments;
struct Arguments
{
virtual ~Arguments() {}
template<typename TUP>
TUP const&
get ()
{
TypedArguments<TUP>* dest = dynamic_cast<TypedArguments<TUP>*> (this);
if (!dest)
throw lumiera::error::Invalid("Wrong type or number of arguments");
return dest->args_;
}
};
template<typename TUP>
struct TypedArguments
: Arguments
{
TUP const& args_;
TypedArguments (TUP const& a)
: args_(a)
{ }
};
} // namespace control
#endif

View file

@ -22,7 +22,7 @@
/** @file command-argument-holder.hpp
** A passive container record holding the actual command arguments & UNDO state.
** A passive container record holding the actual command arguments & UNDO state.
** While all command objects themselves have a common type (type erasure),
** the actual argument tuple and the state memento for UNDO can't. Especially,
** the size of arguments and memento will depend on their respective types.

View file

@ -43,21 +43,15 @@
#ifndef CONTROL_COMMAND_BINDING_H
#define CONTROL_COMMAND_BINDING_H
//#include "pre.hpp"
//#include "include/symbol.hpp"
#include "lib/meta/typelist.hpp"
#include "lib/meta/tuple.hpp"
//#include <tr1/memory>
namespace control {
namespace com { ///< Proc-Layer command implementation details
// using lumiera::Symbol;
// using std::tr1::shared_ptr;
using namespace lumiera::typelist;
@ -65,7 +59,12 @@ namespace com { ///< Proc-Layer command implementation details
/**
* @todo Type-comment
* Building block for commands, allowing to mix in
* a set of \c bind(...) function for up to nine arbitrary arguments.
* All these functions will package the argument values into a Tuple
* (record) and forward the call to a \c bindArg(Tuple<TYPES...>) function
* on the target class. The latter function is asumed to perform a
* run-time check to detect calls with invalid signature.
*/
template<class TAR, class BA>
class ArgumentBinder
@ -203,10 +202,8 @@ namespace com { ///< Proc-Layer command implementation details
}
};
////////////////TODO currently just fleshing out the API....
}} // namespace control::com

View file

@ -23,6 +23,17 @@
/** @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 later on be fed to the operation when the command is invoked.
**
** Most of the command machinery accesses this function closure through the interface
** CmdClosure, while, when defining a command, subclasses typed to the specific
** function arguments are created. Especially, there is an ArgumentHolder template,
** which is used to define the storage for the concrete arguments. This ArgumentHolder
** internally contains an Closure<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.
** //TODO
**
** @see Command
@ -44,7 +55,7 @@
#include "lib/meta/tuple.hpp"
#include "lib/format.hpp"
#include "lib/util.hpp"
#include "proc/control/argument-tuple-accept.hpp" ////TODO better factor out struct TypedArguments
#include "proc/control/argument-erasure.hpp"
#include "proc/control/typed-allocation-manager.hpp"
#include <tr1/memory>
@ -54,17 +65,10 @@
#include <string>
#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 lumiera::typelist::FunctionSignature;
using lumiera::typelist::Tuple;
using lumiera::typelist::BuildTupleAccessor;
@ -72,9 +76,8 @@ namespace control {
using lumiera::typelist::FunErasure;
using lumiera::typelist::StoreFunction;
using lumiera::typelist::NullType;
using util::unConst;
using std::tr1::function;
using std::ostream;
using std::string;
@ -118,6 +121,7 @@ namespace control {
/** Helper for accessing an individual function parameter */
template
< typename TY
, class BASE
@ -260,9 +264,7 @@ namespace control {
friend bool operator== (Closure const& c1, Closure const& c2) { return compare (c1.params_, c2.params_); }
friend bool operator!= (Closure const& c1, Closure const& c2) { return ! (c1 == c2); }
};
////////////////TODO currently just fleshing out the API....

View file

@ -28,7 +28,7 @@
** \em defining the concrete operations to be encapsulated into a command. To
** create a command, you need to provide three functors (for the actual operation,
** the undo operation and for capturing undo state prior to invoking the operation).
** Besides, you provide a \em binding, thus creating a closue out of these three
** Besides, you provide a \em binding, thus creating a closure out of these three
** function objects and a set of actual parameters. This closure effectively is
** the command, which in a last step can be either dispatched, stored or
** invoked immediately.
@ -49,6 +49,7 @@
//#include "pre.hpp"
#include "lib/error.hpp"
#include "include/logging.h"
#include "include/symbol.hpp"
#include "proc/control/command.hpp"
#include "proc/control/command-impl.hpp" /////TODO: any chance to get rid of this import here??
@ -57,11 +58,12 @@
#include "proc/control/command-mutation.hpp"
#include "proc/control/command-closure.hpp"
#include "proc/control/argument-tuple-accept.hpp"
#include "lib/bool-checkable.hpp"
#include "lib/meta/function.hpp"
#include "lib/meta/typelist.hpp"
#include "lib/meta/typelist-util.hpp"
#include "lib/meta/tuple.hpp"
#include "lib/bool-checkable.hpp"
#include "lib/util.hpp"
#include <tr1/memory>
#include <tr1/functional>
@ -71,9 +73,10 @@
namespace control {
using lumiera::Symbol;
using std::tr1::shared_ptr;
using std::tr1::function;
using lumiera::Symbol;
using util::cStr;
using lumiera::typelist::FunctionSignature;
using lumiera::typelist::FunctionTypedef;
@ -82,7 +85,7 @@ namespace control {
using lumiera::typelist::Tuple;
namespace stage { ///< helpers for the building up a command definition
namespace stage { ///< helpers for building up a command definition
@ -99,7 +102,7 @@ namespace control {
CompletedDefinition (Command& definedCommand)
: prototype_(definedCommand)
{
TRACE (command_dbg, "Completed definition of %s.", cStr(prototype_));
}
typedef HandlingPattern::ID PattID;
@ -144,9 +147,7 @@ namespace control {
, operFunctor_(commandOperation)
, captFunctor_(undoCapOperation)
, undoFunctor_()
{
cout << showSizeof(undoCapOperation) << endl;
}
{ }
CompletedDefinition<SIG>
@ -182,8 +183,8 @@ namespace control {
template<typename SIG>
struct BasicDefinition
{
@ -238,7 +239,9 @@ namespace control {
CommandDef (Symbol cmdID)
: id_(cmdID)
, prototype_(Command::fetchDef(cmdID))
{ }
{
TRACE (command_dbg, "starting CommandDef('%s')...", cmdID);
}
template<typename SIG>
stage::BasicDefinition<SIG>
@ -252,7 +255,6 @@ namespace control {
bool isValid() const;
};
////////////////TODO currently just fleshing out the API....

View file

@ -22,7 +22,7 @@
/** @file command-mutation.hpp
** Core of a Proc-Layer command: functor containing the actual operation to be executed.
** Core of a Proc-Layer command: functor containing the 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
@ -34,7 +34,7 @@
** 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.
** allowing them to be embedded immediately within the CommandImpl frame.
**
** 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

View file

@ -80,7 +80,7 @@ namespace control {
/** register a command (Frontend) under the given ID
* @return either the new command, or an already existing
* command registered under the given ID*/
* command registered under the given ID */
Command
track (Symbol cmdID, Command const& commandHandle)
{

View file

@ -22,7 +22,16 @@
/** @file command.cpp
** //TODO
** Implementation of the command frontend.
** Within this file, the implementation level of the command frontend
** is linked to the implementation of the command registry. Client code
** is shielded from those implementation classes and need only include
** command.hpp
**
** More specifically, the actual number and type of arguments and the
** concrete functions implementing the command operation are known only
** at the time of the command definition; this detailed type information
** is erased afterwards, allowing client code to use a simple frontend.
**
** @see command.hpp
** @see command-registry.hpp
@ -38,9 +47,6 @@
#include "proc/control/command-impl.hpp"
#include "proc/control/command-registry.hpp"
#include "proc/control/handling-pattern.hpp"
//#include "proc/mobject/mobject-ref.hpp"
//#include "proc/mobject/mobject.hpp"
//#include "proc/mobject/placement.hpp"
#include <boost/format.hpp>
#include <sstream>
@ -68,11 +74,11 @@ namespace control {
lumiera::Singleton<CommandRegistry> CommandRegistry::instance;
Command::~Command() { }
/** */
Command
Command::get (Symbol cmdID)
@ -248,7 +254,7 @@ namespace control {
return repr.str();
}
@ -295,7 +301,7 @@ namespace control {
{
return impl().setHandlingPattern(pattID);
}

View file

@ -22,8 +22,26 @@
/** @file command.hpp
** //TODO
**
** Proc-Layer command frontend.
** A \b command is a functor, which can be invoked according to a pre-defined HandlingPattern.
** Most notably, command invocation can be scheduled and logged with the serialiser, and the effect
** of any command invocation can be \em undone later on by invoking the "undo operation" defined
** alongside with the command's operation. The command operation is defined through a C/C++ function
** and may receive an arbitrary number and type of arguments. After setting up such a CommandDef ,
** it can be referred for use through a symbolic ID. Before being able to invoke the command, concrete
** function arguments need to be provided (this is called "binding" or "closing the function arguments").
** These function arguments are stored within the command definition and remain opaque to the client code
** actually invoking the command. Behind the scenes, there is a CommandRegistry, holding an index of the
** registered commands and managing the storage for command definitions and arguments. The actual
** Command object used by client code is a small, copyable and ref-counting handle to this
** stored definition backend.
**
** //TODO maybe summarise how UNDO works?
**
** @see command-def.hpp
** @see command-use1-test.cpp
** @see command-use2-test.cpp
** @see command-use3-test.cpp
** @see ProcDispatcher
** @see Session
**
@ -35,15 +53,15 @@
#define CONTROL_COMMAND_H
#include "pre.hpp"
#include "lib/error.hpp"
#include "include/symbol.hpp"
#include "proc/control/command-binding.hpp"
#include "proc/control/command-mutation.hpp" /////TODO: do we need to expose this here?
#include "proc/control/command-closure.hpp"
#include "proc/control/argument-erasure.hpp"
#include "proc/control/handling-pattern.hpp"
#include "lib/bool-checkable.hpp"
#include "lib/meta/tuple.hpp"
#include "lib/handle.hpp"
//#include <tr1/memory>
#include <string>
///////////////////////////////////////////TODO: define an C-API representation here, make the header multilingual!
@ -55,14 +73,16 @@ namespace control {
using std::string;
using lumiera::Symbol;
using std::tr1::shared_ptr;
using lumiera::typelist::Tuple;
LUMIERA_ERROR_DECLARE (UNBOUND_ARGUMENTS); ///< Command functor not yet usable, because arguments aren't bound
LUMIERA_ERROR_DECLARE (INVALID_COMMAND); ///< Unknown or insufficiently defined command
LUMIERA_ERROR_DECLARE (DUPLICATE_COMMAND); ///< Attempt to redefine an already existing command definition
LUMIERA_ERROR_DECLARE (INVALID_ARGUMENTS); ///< Arguments provided for binding doesn't match stored command function parameters
typedef void* FuncPtr;
class CommandDef;
@ -70,12 +90,23 @@ namespace control {
/**
* @todo Type-comment
* Handle object representing a single Command instance to be used by client code.
* Commands are accessed \link #get through a symbolic ID \endlink; there need to be
* a CommandDef somewhere to specify the actual operation and to define, how the
* effect of the command can be undone. Moreover, the command's definition
* refers to a HandlingPattern, which describes how the command is actually
* to be executed (the default is to schedule it within the ProcDispatcher)
*
* Client code usually just
* - creates a command instance by referring to a command ID
* - maybe binds to concrete arguments (e.g. a target object)
* - triggers command execution through operator()
* - maybe checks the return value for errors
*/
class Command
: public com::ArgumentBinder<Command // accepts arbitrary bind(..) calls (with runtime check)
, lib::Handle<CommandImpl> // actually implemented as ref counting Handle
>
> //
{
typedef lib::Handle<CommandImpl> _Handle;
@ -177,7 +208,7 @@ namespace control {
return ! (c1 == c2);
}
} // namespace control

View file

@ -146,7 +146,7 @@ namespace control {
/** access the singleton instance for a given ID */
HandlingPattern const&
getPatternInstance (HandlingPattern::ID id)
getPatternInstance (size_t id)
{
REQUIRE (id < patternTable.size());
return patternTable[id] ();