diff --git a/src/proc/control/argument-erasure.hpp b/src/proc/control/argument-erasure.hpp new file mode 100644 index 000000000..003a38391 --- /dev/null +++ b/src/proc/control/argument-erasure.hpp @@ -0,0 +1,537 @@ +/* + ARGUMENT-TUPLE-ACCEPT.hpp - helper template providing a bind(...) member function + + 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 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_TUPLE_ACCEPT_H +#define CONTROL_ARGUMENT_TUPLE_ACCEPT_H + +#include "lib/meta/typelist.hpp" +#include "lib/meta/function.hpp" +#include "lib/meta/tuple.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 > ///< Accept dummy binding (0 Arguments) + : BA + { + RET + operator() () + { + return static_cast (this) -> bindArg (tuple::makeNullTuple() ); + } + }; + + + template< class TAR, class BA, class RET + , typename T1 + > //_______________________________ + struct AcceptArgs > ///< Accept binding for 1 Argument + : BA + { + RET + operator() (T1 a1) + { + return static_cast (this) -> bindArg (tuple::make (a1)); + } + }; + + + template< class TAR, class BA, class RET + , typename T1 + , typename T2 + > //________________________________ + struct AcceptArgs > ///< Accept binding for 2 Arguments + : BA + { + RET + operator() (T1 a1, T2 a2) + { + return static_cast (this) -> bindArg (tuple::make (a1,a2)); + } + }; + + + template< class TAR, class BA, class RET + , typename T1 + , typename T2 + , typename T3 + > //________________________________ + struct AcceptArgs > ///< Accept binding for 3 Arguments + : BA + { + RET + operator() (T1 a1, T2 a2, T3 a3) + { + return static_cast (this) -> bindArg (tuple::make (a1,a2,a3)); + } + }; + + + template< class TAR, class BA, class RET + , typename T1 + , typename T2 + , typename T3 + , typename T4 + > //________________________________ + struct AcceptArgs > ///< Accept binding for 4 Arguments + : BA + { + RET + operator() (T1 a1, T2 a2, T3 a3, T4 a4) + { + return static_cast (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 > ///< Accept binding for 5 Arguments + : BA + { + RET + operator() (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) + { + return static_cast (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 > ///< Accept binding for 6 Arguments + : BA + { + RET + operator() (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) + { + return static_cast (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 > ///< 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 (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 > ///< 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 (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 > ///< 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 (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 > ///< Accept dummy binding (0 Arguments) + : BA + { + RET + bind () + { + return static_cast (this) -> bindArg (tuple::makeNullTuple() ); + } + }; + + + template< class TAR, class BA, class RET + , typename T1 + > //_______________________________ + struct AcceptBind > ///< Accept binding for 1 Argument + : BA + { + RET + bind (T1 a1) + { + return static_cast (this) -> bindArg (tuple::make (a1)); + } + }; + + + template< class TAR, class BA, class RET + , typename T1 + , typename T2 + > //________________________________ + struct AcceptBind > ///< Accept binding for 2 Arguments + : BA + { + RET + bind (T1 a1, T2 a2) + { + return static_cast (this) -> bindArg (tuple::make (a1,a2)); + } + }; + + + template< class TAR, class BA, class RET + , typename T1 + , typename T2 + , typename T3 + > //________________________________ + struct AcceptBind > ///< Accept binding for 3 Arguments + : BA + { + RET + bind (T1 a1, T2 a2, T3 a3) + { + return static_cast (this) -> bindArg (tuple::make (a1,a2,a3)); + } + }; + + + template< class TAR, class BA, class RET + , typename T1 + , typename T2 + , typename T3 + , typename T4 + > //________________________________ + struct AcceptBind > ///< Accept binding for 4 Arguments + : BA + { + RET + bind (T1 a1, T2 a2, T3 a3, T4 a4) + { + return static_cast (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 > ///< Accept binding for 5 Arguments + : BA + { + RET + bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5) + { + return static_cast (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 > ///< Accept binding for 6 Arguments + : BA + { + RET + bind (T1 a1, T2 a2, T3 a3, T4 a4, T5 a5, T6 a6) + { + return static_cast (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 > ///< 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 (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 > ///< 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 (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 > ///< 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 (this) -> bindArg (tuple::make (a1,a2,a3,a4,a5,a6,a7,a8,a9)); + } + }; + + + + template + struct _Type + { + typedef typename FunctionSignature< function >::Args Args; + typedef typename FunctionSignature< function >::Ret Ret; + typedef Tuple ArgTuple; + typedef SIG Sig; + }; + + template + struct _Type > + { + typedef TYPES Args; + typedef void Ret; + typedef Tuple ArgTuple; + typedef typename FunctionTypedef::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) -- + * where \c TYPES... is the sequence of types found in the provided Signature SIG. + */ + template + class AcceptArgumentTuple + : public bind_arg::AcceptArgs::Ret + , typename bind_arg::_Type::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 >) + * @param BASE the base class for inheritance chaining + */ + template + class AcceptArgumentBinding + : public bind_arg::AcceptBind::Ret + , typename bind_arg::_Type::Args> + { + }; + + + /** Variation of AcceptArgumentBinding, allowing to control the return type + * of the generated \c bind(...) functions independently from SIG + */ + template + class AcceptArgumentBindingRet + : public bind_arg::AcceptBind::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" + */ + struct Arguments; + + template + struct TypedArguments; + + + struct Arguments + { + virtual ~Arguments() {} + + template + TUP const& + get () + { + TypedArguments* dest = dynamic_cast*> (this); + if (!dest) + throw lumiera::error::Invalid("Wrong type or number of arguments"); + + return dest->args_; + } + }; + + + template + struct TypedArguments + : Arguments + { + TUP const& args_; + + TypedArguments (TUP const& a) + : args_(a) + { } + }; + + + + + + +} // namespace control +#endif diff --git a/src/proc/control/command-registry.hpp b/src/proc/control/command-registry.hpp index 2aaea1e52..fba0ad032 100644 --- a/src/proc/control/command-registry.hpp +++ b/src/proc/control/command-registry.hpp @@ -89,6 +89,18 @@ namespace control { } + /** remove the given command registration. + * @return \c true if actually removed an entry + * @note existing command instances remain valid; + * storage will be freed at zero use-count */ + bool + remove (Symbol cmdID) + { + Lock sync(this); + UNIMPLEMENTED ("de-register a command definition."); + } + + /** query the command index by ID * @return the registered command, * or an "invalid" token */ diff --git a/src/proc/control/command.cpp b/src/proc/control/command.cpp index ce3b139d0..eca322e58 100644 --- a/src/proc/control/command.cpp +++ b/src/proc/control/command.cpp @@ -162,14 +162,7 @@ namespace control { bool Command::remove (Symbol cmdID) { - UNIMPLEMENTED ("de-register a single command instance"); - } - - - bool - Command::undef (Symbol cmdID) - { - UNIMPLEMENTED ("completely drop a command definition, together with all dependent instances"); + return CommandRegistry::instance().remove (cmdID); } diff --git a/src/proc/control/command.hpp b/src/proc/control/command.hpp index 525af5962..642e8cbbe 100644 --- a/src/proc/control/command.hpp +++ b/src/proc/control/command.hpp @@ -84,7 +84,6 @@ namespace control { static Command get (Symbol cmdID); static Command get (FuncPtr func); static bool remove (Symbol cmdID); - static bool undef (Symbol cmdID); Command storeDef (Symbol newCmdID); diff --git a/tests/components/proc/control/command-mutation-test.cpp b/tests/components/proc/control/command-mutation-test.cpp index b52a10a5f..39c88355c 100644 --- a/tests/components/proc/control/command-mutation-test.cpp +++ b/tests/components/proc/control/command-mutation-test.cpp @@ -22,6 +22,7 @@ #include "lib/test/run.hpp" +#include "lib/test/test-helper.hpp" #include "proc/control/command-mutation.hpp" #include "proc/control/memento-tie.hpp" #include "lib/meta/typelist.hpp" diff --git a/tests/components/proc/control/command-use1-test.cpp b/tests/components/proc/control/command-use1-test.cpp index f004f7006..c7bcf4326 100644 --- a/tests/components/proc/control/command-use1-test.cpp +++ b/tests/components/proc/control/command-use1-test.cpp @@ -238,14 +238,14 @@ namespace test { // use the current sate of c2 as Prototype for new command definition c2.storeDef ("test.command1.4"); - Command c3 = Command::get("test.command1.4"); - ASSERT (c3); - ASSERT (!c3.canUndo()); - c3(); + Command c4 = Command::get("test.command1.4"); + ASSERT (c4); + ASSERT (!c4.canUndo()); + c4(); ASSERT (randVal + 2*23 == command1::check_); - c3.bind(-command1::check_); - c3(); + c4.bind(-command1::check_); + c4(); ASSERT (0 == command1::check_); c2(); ASSERT (23 == command1::check_); @@ -297,34 +297,27 @@ namespace test { ASSERT (!miracle.canUndo()); ASSERT (!miracle); + Command c4 (Command::get("test.command1.4")); + ASSERT (Command::remove("test.command1.1")); ASSERT (Command::remove("test.command1.2")); ASSERT (Command::remove("test.command1.3")); + ASSERT (Command::remove("test.command1.4")); ASSERT (!Command::remove("miracle")); // there is no such thing... - - // note, we didn't remove the *definitions* - // thus we're free to create new instances... - Command xxx = Command::get("test.command1.1"); - VERIFY_ERROR (UNBOUND_ARGUMENTS, xxx() ); - - // but this one is still there (we didn't remove it) - ASSERT (Command::get("test.command1.4")); - - // now kill the definitions too... - ASSERT (Command::undef ("test.command1.1")); - ASSERT (Command::undef ("test.command1.2")); - ASSERT (Command::undef ("test.command1.3")); - ASSERT (Command::undef ("test.command1.4")); - ASSERT (Command::undef ("miracle")); VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.1")); VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.2")); VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.3")); + VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.4")); VERIFY_ERROR (INVALID_COMMAND, Command::get("miracle")); - // note: removing the definition automatically killed the remaining instance: - VERIFY_ERROR (INVALID_COMMAND, Command::get("test.command1.4")); + + // note, removed the registered definitions, + // but existing instances remain valid... + // thus we're free to create new instances... + ASSERT (c4.isValid()); + ASSERT (c4.canExec()); } }; diff --git a/tests/components/proc/control/command-use2-test.cpp b/tests/components/proc/control/command-use2-test.cpp index 5b6e18be6..e8d217fd2 100644 --- a/tests/components/proc/control/command-use2-test.cpp +++ b/tests/components/proc/control/command-use2-test.cpp @@ -141,8 +141,8 @@ namespace test { check_ThrowOnError(); - Command::undef ("test.command2"); - Command::undef ("test.command2.1"); + Command::remove ("test.command2"); + Command::remove ("test.command2.1"); ASSERT (cnt_defs == Command::definition_count()); ASSERT (cnt_inst == Command::instance_count()); } diff --git a/tests/components/proc/control/command-use3-test.cpp b/tests/components/proc/control/command-use3-test.cpp index f922c55d6..0ce985079 100644 --- a/tests/components/proc/control/command-use3-test.cpp +++ b/tests/components/proc/control/command-use3-test.cpp @@ -105,7 +105,7 @@ namespace test { ASSERT (cnt_inst == Command::instance_count()); - Command::undef ("test.command1.1"); + Command::remove ("test.command1.1"); ASSERT (cnt_defs == Command::definition_count()); }