From 39f50b548cd6f6b03fd75acaea39038fa794d2ff Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Sat, 3 Oct 2009 03:40:12 +0200 Subject: [PATCH] Ticket #266: simplify and combine the bind(...) mixin templates into a single header --- src/proc/control/argument-tuple-accept.hpp | 186 ++++++++++++++- src/proc/control/command-binding.hpp | 211 ------------------ src/proc/control/command-invocation.hpp | 31 +-- src/proc/control/command.hpp | 9 +- tests/45controller.tests | 2 +- .../control/argument-tuple-accept-test.cpp | 15 +- 6 files changed, 212 insertions(+), 242 deletions(-) delete mode 100644 src/proc/control/command-binding.hpp diff --git a/src/proc/control/argument-tuple-accept.hpp b/src/proc/control/argument-tuple-accept.hpp index 8a7d2d2f7..189934b9f 100644 --- a/src/proc/control/argument-tuple-accept.hpp +++ b/src/proc/control/argument-tuple-accept.hpp @@ -22,15 +22,33 @@ /** @file argument-tuple-accept.hpp + ** Mixin-templates providing arbitrary function call operators and argument + ** binding functions. By inheriting from one of these templates, a class can + ** accept a specifically typed binding or function call, as specified by the + ** template parameters, or alternatively it can inherit a complete set of + ** templated argument binding functions, assuming that the matching signature + ** can be detected at runtime. These templates are used for the Proc-Layer + ** command frontend, to bind to the actual command arguments. + ** ** 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. + ** the function signature given as template parameter. The class mixing in this + ** template needs to provide a suitable member function \c bindArg(Tuple<...>) , + ** which accepts all the command arguments packaged together into a tuple (record). + ** AcceptArgumentTuple works similar, but provides function call operators rather. ** + ** Contrary to this, the AcceptAnyBinding mixin template provides a complete + ** set of \c bind(...) functions, accepting up to 9 arbitrary call parameters and + ** again forwarding the call to a template member function \c bindArg(Tuple<...>) + ** This helper template is used on the control::Command frontend objects; in this + ** case, there is a runtime type-check built into CommandImpl which will throw + ** when the provided arguments don't fit the (hidden) function signature embedded + ** within the CommandMutation (functor). + ** + ** @see Command ** @see CommandDef - ** @see ArgumentHolder ** @see argument-tuple-accept-test.cpp + ** @see command-invocation.hpp ** */ @@ -53,6 +71,8 @@ namespace control { using namespace lumiera::typelist; + // + // _______________________________________________________________________________________________________________ /** @internal mix in a function operator */ template< class TAR, class BA, class RET , typename TYPES @@ -238,6 +258,11 @@ namespace control { + + + + // + // _______________________________________________________________________________________________________________ /** @internal mix in a \c bind() function */ template< class TAR, class BA, class RET @@ -424,6 +449,144 @@ namespace control { + + + + // + // _______________________________________________________________________________________________________________ + /** @internal mix in complete set of templated \c bind() functions + */ + template< class TAR, class BA, class RET> + struct AcceptAnyBind + : BA + { + + RET //________________________________ + bind () ///< Accept dummy binding (0 Arg) + { + return static_cast (this) -> bindArg (tuple::makeNullTuple()); + } + + + template + RET //________________________________ + bind (T1 a1) ///< Accept binding with 1 Argument + { + return static_cast (this) -> bindArg (tuple::make (a1)); + } + + + template< typename T1 + , typename T2 + > + RET //________________________________ + bind (T1 a1, T2 a2) ///< Accept binding for 2 Arguments + { + return static_cast (this) -> bindArg (tuple::make (a1,a2)); + } + + + template< typename T1 + , typename T2 + , typename T3 + > + RET //________________________________ + bind (T1 a1, T2 a2, T3 a3) ///< Accept binding for 3 Arguments + { + return static_cast (this) -> bindArg (tuple::make (a1,a2,a3)); + } + + + template< typename T1 + , typename T2 + , typename T3 + , typename T4 + > + RET //________________________________ + bind (T1 a1, T2 a2, T3 a3, T4 a4) ///< Accept binding for 4 Arguments + { + return static_cast (this) -> bindArg (tuple::make (a1,a2,a3,a4)); + } + + + template< typename T1 + , typename T2 + , typename T3 + , typename T4 + , typename T5 + > + RET //________________________________ + bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) ///< Accept binding for 5 Arguments + { + return static_cast (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5)); + } + + + template< typename T1 + , typename T2 + , typename T3 + , typename T4 + , typename T5 + , typename T6 + > + RET //________________________________ + bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) ///< Accept binding for 6 Arguments + { + return static_cast (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6)); + } + + + template< typename T1 + , typename T2 + , typename T3 + , typename T4 + , typename T5 + , typename T6 + , typename T7 + > + RET //________________________________ + bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7) ///< Accept binding for 7 Arguments + { + return static_cast (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7)); + } + + + template< typename T1 + , typename T2 + , typename T3 + , typename T4 + , typename T5 + , typename T6 + , typename T7 + , typename T8 + > + RET //________________________________ + bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8) ///< Accept binding for 8 Arguments + { + return static_cast (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7,a8)); + } + + + template< typename T1 + , typename T2 + , typename T3 + , typename T4 + , typename T5 + , typename T6 + , typename T7 + , typename T8 + , typename T9 + > + RET //________________________________ + bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9) ///< Accept binding for 9 Arguments + { + return static_cast (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7,a8,a9)); + } + + }; + + + template struct _Type { @@ -488,6 +651,21 @@ namespace control { }; + /** Helper Template for control::Command, mix-in complete set of \c bind(...) functions + * @param TAR the target class providing a function \c bindArg(Tuple >) + * @param RET common return type of \c bindArg() and all \c bind() functions + * @param BASE the base class for inheritance chaining + */ + template< class TAR + , class RET =TAR& + , class BASE =bind_arg::Dummy + > + class AcceptAnyBinding + : public bind_arg::AcceptAnyBind + { + }; + + diff --git a/src/proc/control/command-binding.hpp b/src/proc/control/command-binding.hpp deleted file mode 100644 index 2f278b33d..000000000 --- a/src/proc/control/command-binding.hpp +++ /dev/null @@ -1,211 +0,0 @@ -/* - COMMAND-BINDING.hpp - interface for various ways of binding command arguments - - Copyright (C) Lumiera.org - 2009, Hermann Vosseler - - This program is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - 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. - - 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. - -*/ - - -/** @file command-binding.hpp - ** Sub-include of command.hpp, providing an interface to various ways - ** of binding command arguments. While in some cases, a command will be - ** set up completely finished and closed over all it's arguments, usually - ** the CommandDef will just specify the command operation and undo function, - ** thus leaving the task of binding concrete arguments to the client code. - ** Thus, depending on the circumstances, there might be usage situations - ** where the exact number and type of arguments can be detected and checked - ** at compile time, while otherwise this check needs to be deferred to happen - ** at runtime, when the binding is actually invoked. - ** - ** @see Command - ** @see CommandDef - ** @see command-use1-test.cpp - ** - */ - - - -#ifndef CONTROL_COMMAND_BINDING_H -#define CONTROL_COMMAND_BINDING_H - -#include "lib/meta/typelist.hpp" -#include "lib/meta/tuple.hpp" - - - - -namespace control { -namespace com { ///< Proc-Layer command implementation details - - using namespace lumiera::typelist; - - - -////////////////////////TODO: Ticket #266 - can this be merged into argument-tuple-accept.hpp ?? - - - /** - * 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) function - * on the target class. The latter function is assumed to perform a - * run-time check to detect calls with invalid signature. - */ - template - class ArgumentBinder - : public BA - { - - public: - - - /** Arm up a command by binding it with concrete arguments. - * At this point, a run time type check is performed, to find out - * if the number and type of arguments of the stored operation function - * within the command matches the given argument pattern - */ - TAR& - bind () - { - return static_cast (this) -> bindArg (tuple::makeNullTuple()); - } - - - template - TAR& //________________________________ - bind (T1 a1) ///< Accept binding with 1 Argument - { - return static_cast (this) -> bindArg (tuple::make (a1)); - } - - - template< typename T1 - , typename T2 - > - TAR& //________________________________ - bind (T1 a1, T2 a2) ///< Accept binding for 2 Arguments - { - return static_cast (this) -> bindArg (tuple::make (a1,a2)); - } - - - template< typename T1 - , typename T2 - , typename T3 - > - TAR& //________________________________ - bind (T1 a1, T2 a2, T3 a3) ///< Accept binding for 3 Arguments - { - return static_cast (this) -> bindArg (tuple::make (a1,a2,a3)); - } - - - template< typename T1 - , typename T2 - , typename T3 - , typename T4 - > - TAR& //________________________________ - bind (T1 a1, T2 a2, T3 a3, T4 a4) ///< Accept binding for 4 Arguments - { - return static_cast (this) -> bindArg (tuple::make (a1,a2,a3,a4)); - } - - - template< typename T1 - , typename T2 - , typename T3 - , typename T4 - , typename T5 - > - TAR& //________________________________ - bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) ///< Accept binding for 5 Arguments - { - return static_cast (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5)); - } - - - template< typename T1 - , typename T2 - , typename T3 - , typename T4 - , typename T5 - , typename T6 - > - TAR& //________________________________ - bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) ///< Accept binding for 6 Arguments - { - return static_cast (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6)); - } - - - template< typename T1 - , typename T2 - , typename T3 - , typename T4 - , typename T5 - , typename T6 - , typename T7 - > - TAR& //________________________________ - bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7) ///< Accept binding for 7 Arguments - { - return static_cast (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7)); - } - - - template< typename T1 - , typename T2 - , typename T3 - , typename T4 - , typename T5 - , typename T6 - , typename T7 - , typename T8 - > - TAR& //________________________________ - bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8) ///< Accept binding for 8 Arguments - { - return static_cast (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7,a8)); - } - - - template< typename T1 - , typename T2 - , typename T3 - , typename T4 - , typename T5 - , typename T6 - , typename T7 - , typename T8 - , typename T9 - > - TAR& //________________________________ - bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6, T7 a7, T8 a8, T9 a9) ///< Accept binding for 9 Arguments - { - return static_cast (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7,a8,a9)); - } - - }; - - - - -}} // namespace control::com -#endif diff --git a/src/proc/control/command-invocation.hpp b/src/proc/control/command-invocation.hpp index bc1ff54b9..6f87f598f 100644 --- a/src/proc/control/command-invocation.hpp +++ b/src/proc/control/command-invocation.hpp @@ -26,7 +26,14 @@ ** Especially, this header defines a set of free \c invoke(...) functions, ** allowing to bind to specific arguments and then invoke through the default ** HandlingPatern in a single call. - ** + ** + ** While in some cases, a command will be set up completely finished and closed + ** over all it's arguments, usually the CommandDef will just specify the command operation + ** and undo function, thus leaving the task of binding concrete arguments to the client code. + ** Thus, depending on the circumstances, there might be usage situations where the exact number + ** and type of arguments can be detected and checked at compile time, while otherwise this check + ** needs to be deferred to happen at runtime, when the binding is actually invoked. + ** ** @see Command ** @see CommandDef ** @see command-binding.hpp @@ -40,34 +47,28 @@ #define CONTROL_COMMAND_INVOCACTION_H //#include "pre.hpp" -//#include "lib/symbol.hpp" -//#include "lib/meta/typelist.hpp" -//#include "lib/meta/tuple.hpp" #include "proc/control/command.hpp" #include "proc/control/handling-pattern.hpp" #include "proc/control/argument-tuple-accept.hpp" -//#include -#include - namespace control { -// using lib::Symbol; -// using std::tr1::shared_ptr; using namespace lumiera::typelist; - - namespace com { // define transient invoker objects, to allow for arbitrary bindings + + namespace com { ///< Proc-Layer command implementation details + // define transient invoker objects, to allow for arbitrary bindings + template struct _DefineBindFunc { typedef ExecResult SIG_Bind(int); }; - + /** @internal transient invoker object for invoking the command based * on a function provided at compile time. Because of the @@ -81,7 +82,7 @@ namespace control { > { Command com_; - + CommandInvoker (Command c) : com_(c) { } @@ -101,14 +102,14 @@ namespace control { /** @internal transient invoker object, usable when the exact signature * of the command's operation isn't known at compile time. - * In this case, we allow any invocation call to compile, + * In this case, we allow any invocation call to compile, * but the command will reject unsuitable signatures * at runtime, when fetching the operation functor. */ struct RuntimeCheckedCommandInvoker { Command com_; - + RuntimeCheckedCommandInvoker (Command c) : com_(c) { } diff --git a/src/proc/control/command.hpp b/src/proc/control/command.hpp index 0c105d2a5..58da5f815 100644 --- a/src/proc/control/command.hpp +++ b/src/proc/control/command.hpp @@ -55,8 +55,8 @@ #include "pre.hpp" #include "lib/error.hpp" #include "lib/symbol.hpp" -#include "proc/control/command-binding.hpp" #include "proc/control/argument-erasure.hpp" +#include "proc/control/argument-tuple-accept.hpp" #include "proc/control/handling-pattern.hpp" #include "lib/bool-checkable.hpp" #include "lib/meta/tuple.hpp" @@ -104,9 +104,10 @@ namespace control { * - maybe checks the return value for errors */ class Command - : public com::ArgumentBinder // actually implemented as ref counting Handle - > // + : public AcceptAnyBinding // actually implemented as ref counting Handle + > // { typedef lib::Handle _Handle; diff --git a/tests/45controller.tests b/tests/45controller.tests index 8ee423e4d..240530932 100644 --- a/tests/45controller.tests +++ b/tests/45controller.tests @@ -35,7 +35,7 @@ out: RESET...undoIt\(time=00:..:....00\)----memento-:START...doIt\( Time=00:..:. END -TEST "build argument accepting function" AcceptArgumentTuple_test < @@ -54,7 +54,7 @@ namespace test { namespace { // build a test dummy class.... template - struct Tup + struct _Tup { typedef typename FunctionSignature< function >::Args Args; typedef typename FunctionSignature< function >::Ret Ret; @@ -66,11 +66,11 @@ namespace test { class TestClass : public AcceptArgumentBinding< SIG // to derive the desired signature , TestClass // the target class providing the implementation - , typename Tup::Ty // base class to inherit from + , typename _Tup::Ty // base class to inherit from > { - typedef typename Tup::Ty ATuple; - typedef typename Tup::Ret RetType; + typedef typename _Tup::Ty ATuple; + typedef typename _Tup::Ret RetType; public: @@ -78,6 +78,7 @@ namespace test { bindArg (ATuple const& tuple) { static_cast (*this) = tuple; + return RetType(); } }; @@ -95,7 +96,7 @@ namespace test { * * @see control::CommandArgumentHolder */ - class AcceptArgumentTuple_test : public Test + class ArgumentTupleAccept_test : public Test { virtual void @@ -119,7 +120,7 @@ namespace test { /** Register this test class... */ - LAUNCHER (AcceptArgumentTuple_test, "unit controller"); + LAUNCHER (ArgumentTupleAccept_test, "unit controller"); }} // namespace control::test