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:
Fischlurch 2016-01-17 21:55:18 +01:00
parent fd2d56ca45
commit 0e10ef09ec
6 changed files with 172 additions and 102 deletions

View file

@ -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

View file

@ -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>
{
};
{ };

View file

@ -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 */

View file

@ -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<>());
}
};

View file

@ -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

View file

@ -67,7 +67,6 @@ namespace test {
// using lumiera::P;
//using lib::meta::BuildTupleAccessor;
// using lumiera::error::LUMIERA_ERROR_EXTERNAL;
namespace { // test data and helpers...