refactoring(#988): switch command framework to std::tuple
this was rather easy, since the stadard tuple is a drop-in replacement, and we do nothing special here, beyond inheriting from a tuple type
This commit is contained in:
parent
fd2d56ca45
commit
0e10ef09ec
6 changed files with 172 additions and 102 deletions
|
|
@ -28,7 +28,7 @@
|
|||
** with the Tuples provided by the standard library.
|
||||
**
|
||||
** @see control::CommandDef usage example
|
||||
** @see tuple-test.cpp
|
||||
** @see TupleHelper_test
|
||||
** @see typelist.hpp
|
||||
** @see function.hpp
|
||||
** @see generator.hpp
|
||||
|
|
@ -50,7 +50,68 @@
|
|||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
namespace {
|
||||
/**
|
||||
* temporary workaround:
|
||||
* alternative definition of "type sequence",
|
||||
* already using variadic template parameters.
|
||||
* @remarks the problem with our existing type sequence type
|
||||
* is that it fills the end of each sequence with NullType,
|
||||
* which was the only way to get a flexible type sequence
|
||||
* prior to C++11. Unfortunately these trailing NullType
|
||||
* entries do not play well with other variadic defs.
|
||||
* @deprecated when we switch our primary type sequence type
|
||||
* to variadic parameters, this type will be superfluous.
|
||||
*/
|
||||
template<typename...TYPES>
|
||||
struct TySeq
|
||||
{
|
||||
using Seq = TySeq;
|
||||
using List = typename Types<TYPES...>::List;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* temporary workaround: additional specialisation for the template
|
||||
* `Prepend` to work also with the (alternative) variadic TySeq.
|
||||
* @see typeseq-util.hpp
|
||||
*/
|
||||
template<typename T, typename...TYPES>
|
||||
struct Prepend<T, TySeq<TYPES...>>
|
||||
{
|
||||
using Seq = TySeq<T, TYPES...>;
|
||||
using List = typename Types<T, TYPES...>::List;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* temporary workaround: strip trailing NullType entries from a
|
||||
* type sequence, to make it compatible with new-style variadic
|
||||
* template definitions.
|
||||
* @note the result type is a TySec, to keep it apart from our
|
||||
* legacy (non-variadic) lib::meta::Types
|
||||
* @deprecated necessary for the transition to variadic sequences
|
||||
*/
|
||||
template<typename SEQ>
|
||||
struct StripNullType;
|
||||
|
||||
template<typename T, typename...TYPES>
|
||||
struct StripNullType<Types<T,TYPES...>>
|
||||
{
|
||||
using TailSeq = typename StripNullType<Types<TYPES...>>::Seq;
|
||||
|
||||
using Seq = typename Prepend<T, TailSeq>::Seq;
|
||||
};
|
||||
|
||||
template<typename...TYPES>
|
||||
struct StripNullType<Types<NullType, TYPES...>>
|
||||
{
|
||||
using Seq = TySeq<>; // NOTE: this causes the result to be a TySeq
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
namespace { // rebinding helper to create std::tuple from a type sequence
|
||||
|
||||
template<typename SEQ>
|
||||
struct BuildTupleType
|
||||
|
|
@ -58,38 +119,74 @@ namespace meta {
|
|||
{ };
|
||||
|
||||
template<typename...TYPES>
|
||||
struct BuildTupleType<Types<TYPES...>>
|
||||
struct BuildTupleType<TySeq<TYPES...>>
|
||||
{
|
||||
using Type = std::tuple<TYPES...>;
|
||||
};
|
||||
|
||||
/**
|
||||
* temporary workaround: strip trailing NullType entries
|
||||
* prior to rebinding to the `std::tuple` type.
|
||||
*/
|
||||
template<typename...TYPES>
|
||||
struct BuildTupleType<Types<TYPES...>>
|
||||
{
|
||||
using VariadicSeq = typename StripNullType<Types<TYPES...>>::Seq;
|
||||
|
||||
using Type = typename BuildTupleType<VariadicSeq>::Type;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
template<typename...TYPES>
|
||||
/** Build a `std::tuple` from types given as type sequence
|
||||
* @remarks for Lumiera, we deliberately use a dedicated template `Types`
|
||||
* to mark a type sequence of types as such. This allows to pass such a
|
||||
* sequence as first-class citizen. The standard library often (ab)uses
|
||||
* the std::tuple for this purpose, which is an understandable, yet
|
||||
* inferior design choice. We should always favour dedicated types
|
||||
* over clever re-use of existing types.
|
||||
*/
|
||||
template<typename TYPES>
|
||||
using Tuple = typename BuildTupleType<TYPES>::Type;
|
||||
|
||||
|
||||
using std::tuple_size;
|
||||
using std::tuple_element;
|
||||
|
||||
|
||||
|
||||
/** match and rebind the type sequence from a tuple */
|
||||
template<typename...TYPES>
|
||||
struct Types<std::tuple<TYPES...>>
|
||||
{
|
||||
using Seq = typename Types<TYPES...>::Seq;
|
||||
using List = typename Seq::List;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/** Hold a sequence of index numbers as template parameters */
|
||||
template<size_t...idx>
|
||||
struct IndexSeq
|
||||
struct IndexSeq
|
||||
{
|
||||
template<size_t i>
|
||||
using AppendElm = IndexSeq<idx..., i>;
|
||||
};
|
||||
|
||||
|
||||
/** build an `IndexSeq<0, 1, 2, ..., n-1>` */
|
||||
template<size_t n>
|
||||
struct BuildIndexSeq
|
||||
struct BuildIndexSeq
|
||||
{
|
||||
using Ascending = typename BuildIndexSeq<n-1>::Ascending::AppendElm<n>;
|
||||
using Ascending = typename BuildIndexSeq<n-1>::Ascending::template AppendElm<n-1>;
|
||||
|
||||
template<size_t i>
|
||||
using FilledWith = typename BuildIndexSeq<n-1>::FilledWith<i>::AppendElm<i>;
|
||||
using FilledWith = typename BuildIndexSeq<n-1>::template FilledWith<i>::template AppendElm<i>;
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
struct BuildIndexSeq<0>
|
||||
struct BuildIndexSeq<0>
|
||||
{
|
||||
using Ascending = IndexSeq<>;
|
||||
|
||||
|
|
@ -709,60 +806,49 @@ namespace meta {
|
|||
public:
|
||||
static const bool value = (sizeof(Yes_t)== Check<TUP>::result);
|
||||
};
|
||||
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////OBSOLETE :: TICKET #988
|
||||
|
||||
|
||||
/**
|
||||
* Decorating a tuple type with auxiliary data access operations.
|
||||
* This helper template builds up a subclass of the given TUP (base) type
|
||||
* (which is assumed to be a Tuple or at least need to be copy constructible
|
||||
* from \c Tuple<TYPES> ). The purpose is to use the Tuple as storage, but
|
||||
* from `Tuple<TYPES>` ). The purpose is to use the Tuple as storage record, but
|
||||
* to add a layer of access functions, which in turn might rely on the exact
|
||||
* type of the individual elements within the Tuple. To achieve this, for each
|
||||
* type within the Tuple, the TUP type is decorated with an instance of the
|
||||
* template passed in as template template parameter _X_. Each of these
|
||||
* decorating instances is provided with a index allowing to access "his"
|
||||
* specific element within the underlying tuple.
|
||||
* decorating instances is provided with an index number, allowing to
|
||||
* access "his" specific element within the underlying tuple.
|
||||
*
|
||||
* The decorating template _X_ need to take its own base class as template
|
||||
* parameter. Typically, operations on _X_ will be defined in a recursive fashion,
|
||||
* calling down into this templated base class. To support this, an instantiation
|
||||
* of _X_ with the empty type sequence is generated for detecting recursion end
|
||||
* (built as innermost decorator, i.e. immediate subclass of TUP)
|
||||
* (built as innermost decorator, i.e. the immediate subclass of TUP)
|
||||
*/
|
||||
template
|
||||
< typename TYPES ///< Type sequence to use within the Accessor (usually the Tuple Types)
|
||||
, template<class,class,class, uint> class _X_ ///< user provided template<Type, Base, TupleType, arg-No>
|
||||
< template<class,class,class, uint> class _X_ ///< user provided template<Type, Base, TupleType, arg-idx>
|
||||
, typename TYPES ///< Sequence of types to use within the Accessor
|
||||
, class TUP =Tuple<TYPES> ///< the tuple type to build on
|
||||
, uint i = 0 ///< tuple element index counter
|
||||
>
|
||||
class BuildTupleAccessor
|
||||
{
|
||||
typedef Tuple<TYPES> ArgTuple;
|
||||
typedef typename ArgTuple::HeadType Head;
|
||||
typedef typename ArgTuple::TailType Tail;
|
||||
typedef BuildTupleAccessor<Tail,_X_,TUP, i+1> NextBuilder;
|
||||
typedef typename NextBuilder::Accessor NextAccessor;
|
||||
|
||||
ArgTuple const& argData_;
|
||||
|
||||
// prepare recursion...
|
||||
using Head = typename Split<TYPES>::Head;
|
||||
using Tail = typename Split<TYPES>::Tail;
|
||||
using NextBuilder = BuildTupleAccessor<_X_, Tail,TUP, i+1>;
|
||||
using NextAccessor = typename NextBuilder::Product;
|
||||
public:
|
||||
|
||||
/** type of the product created by this template.
|
||||
* Will be a subclass of TUP */
|
||||
typedef _X_< Head // the type to use for this accessor
|
||||
, NextAccessor // the base type to inherit from
|
||||
, TUP // the tuple type we build upon
|
||||
, i // current element index
|
||||
> Accessor;
|
||||
|
||||
|
||||
BuildTupleAccessor (ArgTuple const& tup)
|
||||
: argData_(tup)
|
||||
{ }
|
||||
|
||||
/** used to get the product of this builder template... */
|
||||
operator Accessor() { return Accessor(argData_); }
|
||||
|
||||
using Product = _X_< Head // the type to use for this accessor
|
||||
, NextAccessor // the base type to inherit from
|
||||
, TUP // the tuple type we build upon
|
||||
, i // current element index
|
||||
>;
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -771,24 +857,13 @@ namespace meta {
|
|||
, class TUP
|
||||
, uint i
|
||||
>
|
||||
class BuildTupleAccessor<Types<>, _X_, TUP, i>
|
||||
class BuildTupleAccessor< _X_, Types<>, TUP, i>
|
||||
{
|
||||
typedef Tuple<Types<> > ArgTuple;
|
||||
ArgTuple const& argData_;
|
||||
|
||||
public:
|
||||
typedef _X_<NullType, TUP, TUP, 0> Accessor;
|
||||
|
||||
BuildTupleAccessor (ArgTuple const& tup)
|
||||
: argData_(tup)
|
||||
{ }
|
||||
|
||||
/** used to get the product of this builder template... */
|
||||
operator Accessor() { return Accessor(argData_); }
|
||||
using Product = _X_<NullType, TUP, TUP, i>; // Note: i == tuple size
|
||||
|
||||
};
|
||||
|
||||
#endif /////////////////////////////////////////////////////////////////////////////////////////////////////////////OBSOLETE :: TICKET #988
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -59,7 +59,9 @@
|
|||
|
||||
#include "lib/meta/typelist.hpp"
|
||||
#include "lib/meta/function.hpp"
|
||||
#include "lib/meta/tuple.hpp"
|
||||
#include "lib/meta/tuple-helper.hpp"
|
||||
|
||||
#include <tuple>
|
||||
|
||||
|
||||
|
||||
|
|
@ -624,8 +626,7 @@ namespace control {
|
|||
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
|
||||
|
|
@ -637,8 +638,7 @@ namespace control {
|
|||
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
|
||||
|
|
@ -648,8 +648,7 @@ namespace control {
|
|||
class AcceptArgumentBindingRet
|
||||
: public bind_arg::AcceptBind<TAR,BASE, RET
|
||||
, typename bind_arg::_Type<SIG>::Args>
|
||||
{
|
||||
};
|
||||
{ };
|
||||
|
||||
|
||||
/** Helper Template for control::Command, mix-in complete set of \c bind(...) functions
|
||||
|
|
@ -663,8 +662,7 @@ namespace control {
|
|||
>
|
||||
class AcceptAnyBinding
|
||||
: public bind_arg::AcceptAnyBind<TAR,BASE,RET>
|
||||
{
|
||||
};
|
||||
{ };
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
#include "lib/meta/function.hpp"
|
||||
#include "lib/meta/function-closure.hpp"
|
||||
#include "lib/meta/function-erasure.hpp"
|
||||
#include "lib/meta/tuple.hpp"
|
||||
#include "lib/meta/tuple-helper.hpp"
|
||||
#include "lib/meta/maybe-compare.hpp"
|
||||
#include "lib/format-cout.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
|
@ -165,14 +165,11 @@ namespace control {
|
|||
class ParamAccessor
|
||||
: public BASE
|
||||
{
|
||||
TY & element() { return BASE::template getAt<idx>(); }
|
||||
TY const& element() const { return unConst(this)->template getAt<idx>(); }
|
||||
TY & element() { return std::get<idx> (*this); }
|
||||
TY const& element() const { return std::get<idx> (*this); }
|
||||
|
||||
public:
|
||||
|
||||
ParamAccessor(TUP const& tuple)
|
||||
: BASE(tuple)
|
||||
{ }
|
||||
using BASE::BASE;
|
||||
|
||||
|
||||
////////////////////TODO the real access operations (e.g. for serialising) go here
|
||||
|
|
@ -195,13 +192,13 @@ namespace control {
|
|||
}
|
||||
};
|
||||
|
||||
template<class TUP>
|
||||
class ParamAccessor<NullType, TUP, TUP, 0> ///< used for recursion end of implementation functions
|
||||
template<class TUP, uint n>
|
||||
class ParamAccessor<NullType, TUP, TUP, n> ///< used for recursion end of implementation functions
|
||||
: public TUP
|
||||
{
|
||||
public:
|
||||
ParamAccessor(TUP const& tuple)
|
||||
: TUP(tuple)
|
||||
ParamAccessor (TUP const& tup)
|
||||
: TUP(tup)
|
||||
{ }
|
||||
|
||||
////////////////////TODO the recursion-end of the access operations goes here
|
||||
|
|
@ -225,11 +222,10 @@ namespace control {
|
|||
class Closure
|
||||
: public AbstractClosure
|
||||
{
|
||||
typedef typename FunctionSignature< function<SIG> >::Args Args;
|
||||
using Args = typename FunctionSignature< function<SIG> >::Args;
|
||||
using Builder = BuildTupleAccessor<ParamAccessor, Args>;
|
||||
|
||||
|
||||
typedef BuildTupleAccessor<Args,ParamAccessor> Builder;
|
||||
typedef typename Builder::Accessor ParamStorageTuple;
|
||||
using ParamStorageTuple =typename Builder::Product;
|
||||
|
||||
ParamStorageTuple params_;
|
||||
|
||||
|
|
@ -237,7 +233,7 @@ namespace control {
|
|||
typedef Tuple<Args> ArgTuple;
|
||||
|
||||
Closure (ArgTuple const& args)
|
||||
: params_(Builder (args))
|
||||
: params_(args)
|
||||
{ }
|
||||
|
||||
/** create a clone copy of this, without disclosing the exact type */
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@
|
|||
#include "lib/meta/function.hpp"
|
||||
#include "lib/meta/typelist.hpp"
|
||||
#include "lib/meta/typelist-manip.hpp"
|
||||
#include "lib/meta/tuple.hpp"
|
||||
#include "lib/meta/tuple-helper.hpp"
|
||||
#include "lib/util.hpp"
|
||||
|
||||
#include <memory>
|
||||
|
|
@ -83,15 +83,16 @@ namespace control {
|
|||
using std::function;
|
||||
using std::bind;
|
||||
using std::placeholders::_1;
|
||||
using std::tuple_size;
|
||||
using lib::Symbol;
|
||||
using util::cStr;
|
||||
|
||||
using lib::meta::FunctionSignature;
|
||||
using lib::meta::FunctionTypedef;
|
||||
using lib::meta::Types;
|
||||
using lib::meta::NullType;
|
||||
using lib::meta::Types;
|
||||
using lib::meta::TySeq;
|
||||
using lib::meta::Tuple;
|
||||
using lib::meta::tuple::makeNullTuple;
|
||||
|
||||
|
||||
|
||||
|
|
@ -161,8 +162,8 @@ namespace control {
|
|||
void
|
||||
maybeArm_if_zero_parameters()
|
||||
{
|
||||
if (0 == Tuple<CmdArgs>::SIZE )
|
||||
prototype_.bindArg (makeNullTuple());
|
||||
if (0 == tuple_size<Tuple<CmdArgs>>::value )
|
||||
prototype_.bindArg<> (std::tuple<>());
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -58,8 +58,8 @@
|
|||
#include "proc/control/argument-erasure.hpp"
|
||||
#include "proc/control/argument-tuple-accept.hpp"
|
||||
#include "proc/control/handling-pattern.hpp"
|
||||
#include "lib/meta/tuple-helper.hpp"
|
||||
#include "lib/bool-checkable.hpp"
|
||||
#include "lib/meta/tuple.hpp"
|
||||
#include "lib/handle.hpp"
|
||||
|
||||
#include <string>
|
||||
|
|
@ -75,6 +75,7 @@ namespace control {
|
|||
using lib::Symbol;
|
||||
using std::shared_ptr;
|
||||
using lib::meta::Tuple;
|
||||
using lib::meta::Types;
|
||||
|
||||
|
||||
LUMIERA_ERROR_DECLARE (UNBOUND_ARGUMENTS); ///< Command functor not yet usable, because arguments aren't bound
|
||||
|
|
@ -130,8 +131,8 @@ namespace control {
|
|||
|
||||
/* === command lifecycle === */
|
||||
|
||||
template<typename TYPES>
|
||||
Command& bindArg (Tuple<TYPES> const&);
|
||||
template<typename...TYPES>
|
||||
Command& bindArg (std::tuple<TYPES...> const&);
|
||||
|
||||
/////////////////////////////////////////////////////////////TICKET #798 : we need a second overload to take the arguments as lib::diff::Record.
|
||||
///////////////////////////////////////////////////////////// : this needs to be built into the ParamAccessor within Closure (command-closure.hpp)
|
||||
|
|
@ -204,14 +205,14 @@ namespace control {
|
|||
}
|
||||
|
||||
|
||||
template<typename TYPES>
|
||||
template<typename...TYPES>
|
||||
inline Command&
|
||||
Command::bindArg (Tuple<TYPES> const& tuple)
|
||||
{
|
||||
TypedArguments<Tuple<TYPES> > args(tuple);
|
||||
this->setArguments (args);
|
||||
return *this;
|
||||
}
|
||||
Command::bindArg (std::tuple<TYPES...> const& tuple)
|
||||
{
|
||||
TypedArguments<std::tuple<TYPES...>> args(tuple);
|
||||
this->setArguments (args);
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
@ -219,9 +220,9 @@ namespace control {
|
|||
|
||||
inline bool
|
||||
Command::defined (Symbol cmdID)
|
||||
{
|
||||
return fetchDef(cmdID).isValid();
|
||||
}
|
||||
{
|
||||
return fetchDef(cmdID).isValid();
|
||||
}
|
||||
|
||||
|
||||
#define _FAILSAFE_COMMAND_QUERY(_ID_, _QUERY_) \
|
||||
|
|
@ -238,16 +239,16 @@ namespace control {
|
|||
|
||||
inline bool
|
||||
Command::canExec (Symbol cmdID)
|
||||
{
|
||||
_FAILSAFE_COMMAND_QUERY (cmdID, canExec() );
|
||||
}
|
||||
{
|
||||
_FAILSAFE_COMMAND_QUERY (cmdID, canExec() );
|
||||
}
|
||||
|
||||
|
||||
inline bool
|
||||
Command::canUndo (Symbol cmdID)
|
||||
{
|
||||
_FAILSAFE_COMMAND_QUERY (cmdID, canUndo() );
|
||||
}
|
||||
{
|
||||
_FAILSAFE_COMMAND_QUERY (cmdID, canUndo() );
|
||||
}
|
||||
|
||||
#undef _FAILSAFE_COMMAND_QUERY
|
||||
|
||||
|
|
|
|||
|
|
@ -67,7 +67,6 @@ namespace test {
|
|||
// using lumiera::P;
|
||||
|
||||
|
||||
//using lib::meta::BuildTupleAccessor;
|
||||
// using lumiera::error::LUMIERA_ERROR_EXTERNAL;
|
||||
|
||||
namespace { // test data and helpers...
|
||||
|
|
|
|||
Loading…
Reference in a new issue