Library: use as a foundation for the branch-combinator
After all the preparation, now this panes out quite well: * use a simple 3-way branch structure * the model type was already pre-selected by the `_Join` Model selector * can just pass the result-model elements to a constructor/builder * incremental extension can be directly mapped to the predecessor model
This commit is contained in:
parent
a8231150a5
commit
e3fe8fe380
5 changed files with 190 additions and 470 deletions
|
|
@ -167,33 +167,6 @@ namespace meta {
|
|||
|
||||
|
||||
|
||||
#if false ////////////////////////////////////////////////////////////////////////////////TODO reorder
|
||||
/* ==== Rebinding Variadic Arguments ==== **/
|
||||
|
||||
/**
|
||||
* Metaprogramming helper to transfer variadic arguments.
|
||||
* - builds a new type instantiation from the Template \a X
|
||||
* - possibly picks up the variadic argument pack from a given
|
||||
* source template `U<ARGS....>`
|
||||
* @tparam X a variadic template
|
||||
*/
|
||||
template<template<typename...> class X, typename...ARGS>
|
||||
struct RebindVariadic
|
||||
{
|
||||
using Type = X<ARGS...>;
|
||||
};
|
||||
|
||||
template<template<typename...> class X
|
||||
,template<typename...> class U
|
||||
,typename...ARGS>
|
||||
struct RebindVariadic<X, U<ARGS...>>
|
||||
{
|
||||
using Type = X<ARGS...>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif ////////////////////////////////////////////////////////////////////////////////TODO reorder
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -14,156 +14,48 @@
|
|||
|
||||
/** @file variadic-rebind.hpp
|
||||
** Metaprogramming support to rebuild and rebind variadic templates.
|
||||
** The type rebinding- and helper templates in this header allow to perform
|
||||
** simple sequence manipulations on sequences of template parameters extracted
|
||||
** from variadic parameter packs. The goal is to (pre)process flexible argument
|
||||
** lists _at compile time,_ driven by template instantiation, allowing to specialise
|
||||
** and react specifically on some concrete pattern of argument types.
|
||||
** The sequence of variadic arguments itself is often difficult to manipulate,
|
||||
** because a _parameter pack_ is not a type proper in C++, but rather some meta
|
||||
** mapping expanded immediately by the compiler. For more elaborate processing,
|
||||
** this sequence must thus be re-mapped into a format that allows to pass partial
|
||||
** results from recursive evaluations (since all of this »processing« is actually
|
||||
** a form of functional programming).
|
||||
**
|
||||
** @warning the metaprogramming part of Lumiera to deal with type sequences is in a
|
||||
** state of transition, since C++11 now offers direct language support for
|
||||
** processing of flexible template parameter sequences ("parameter packs").
|
||||
** It is planned to regroup and simplify our homemade type sequence framework
|
||||
** to rely on variadic templates and integrate better with std::tuple.
|
||||
** It is clear that we will _retain some parts_ of our own framework,
|
||||
** since programming with _Loki-style typelists_ is way more obvious
|
||||
** and straight forward than handling of template parameter packs,
|
||||
** since the latter can only be rebound through pattern matching.
|
||||
** @todo transition lib::meta::Types to variadic parameters /////////////////////////////////TICKET #987
|
||||
**
|
||||
** @see control::CommandDef usage example
|
||||
** @see TupleHelper_test
|
||||
** For many _simple cases_ though it is sufficient just to re-bind a template to
|
||||
** another template's variadic sequence, possibly with some basic manipulation.
|
||||
** Such a meta-processing can be coded very succinctly, by passing the target
|
||||
** template to receive the altered sequence as a template-template parameter.
|
||||
** @warning this kind of recursive remoulding typically imposes an O(n) effort
|
||||
** during compilation, sometimes even O(n²) (notably reversing a sequence).
|
||||
** Thus be sure to apply to short type sequences only
|
||||
** endcode
|
||||
** \par Usage example
|
||||
** \code{.cpp}
|
||||
** template<typename...CASES>
|
||||
** struct MyModel
|
||||
** {
|
||||
** using SubSeq = typename _Vari<MyModel, CASES...>::Prefix;
|
||||
**
|
||||
** // adapt a predecessor sequence
|
||||
** MyModel (SubSeq&& subModel);
|
||||
**
|
||||
**
|
||||
** using Tuple = typename RebindVariadic<std::tuple, CASES...>::Type;
|
||||
** }
|
||||
** \endcode
|
||||
** @see param-weaving-pattern.hpp "usage example"
|
||||
** @see util::parse::AltModel "usage example"
|
||||
** @see typelist.hpp
|
||||
** @see function.hpp
|
||||
** @see generator.hpp
|
||||
**
|
||||
*/
|
||||
|
||||
|
||||
#ifndef LIB_META_VARIADIC_REBIND_H
|
||||
#define LIB_META_VARIADIC_REBIND_H
|
||||
|
||||
//#include "lib/meta/typelist.hpp"
|
||||
//#include "lib/meta/typelist-util.hpp"
|
||||
//#include "lib/meta/typeseq-util.hpp"
|
||||
//#include "lib/meta/util.hpp"
|
||||
|
||||
namespace lib {
|
||||
namespace meta {
|
||||
|
||||
#if false ////////////////////////////////////////////////////////////////////////////////TODO reorder
|
||||
|
||||
|
||||
/* ==== Build Variadic Sequences ==== **/
|
||||
|
||||
|
||||
/** Hold a sequence of index numbers as template parameters */
|
||||
template<size_t...idx>
|
||||
struct IndexSeq
|
||||
{
|
||||
template<size_t i>
|
||||
using AppendElm = IndexSeq<idx..., i>;
|
||||
|
||||
template<size_t i>
|
||||
using PrependElm = IndexSeq<i, idx...>;
|
||||
};
|
||||
|
||||
/**
|
||||
* build regular sequences of index number
|
||||
* e.g. `IndexSeq<0, 1, 2, ..., n-1>`
|
||||
*/
|
||||
template<size_t n>
|
||||
struct BuildIndexSeq
|
||||
{
|
||||
using Ascending = typename BuildIndexSeq<n-1>::Ascending::template AppendElm<n-1>;
|
||||
using Descending = typename BuildIndexSeq<n-1>::Descending::template PrependElm<n-1>;
|
||||
|
||||
template<size_t d>
|
||||
using OffsetBy = typename BuildIndexSeq<n-1>::template OffsetBy<d>::template AppendElm<n-1+d>;
|
||||
|
||||
template<size_t x>
|
||||
using FilledWith = typename BuildIndexSeq<n-1>::template FilledWith<x>::template AppendElm<x>;
|
||||
|
||||
template<size_t c>
|
||||
using First = typename BuildIndexSeq<std::min(c,n)>::Ascending;
|
||||
|
||||
template<size_t c>
|
||||
using After = typename BuildIndexSeq< (n>c)? n-c : 0>::template OffsetBy<c>;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct BuildIndexSeq<0>
|
||||
{
|
||||
using Empty = IndexSeq<>;
|
||||
|
||||
using Ascending = Empty;
|
||||
using Descending = Empty;
|
||||
|
||||
template<size_t>
|
||||
using OffsetBy = Empty;
|
||||
|
||||
template<size_t>
|
||||
using FilledWith = Empty;
|
||||
|
||||
template<size_t>
|
||||
using First = Empty;
|
||||
|
||||
template<size_t>
|
||||
using After = Empty;
|
||||
};
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* build a sequence of index numbers based on a type sequence
|
||||
*/
|
||||
template<typename...TYPES>
|
||||
struct BuildIdxIter
|
||||
{
|
||||
enum {SIZ = sizeof...(TYPES) };
|
||||
using Builder = BuildIndexSeq<SIZ>;
|
||||
|
||||
using Ascending = typename Builder::Ascending;
|
||||
using Descending = typename Builder::Descending;
|
||||
|
||||
template<size_t d>
|
||||
using OffsetBy = typename Builder::template OffsetBy<d>;
|
||||
|
||||
template<size_t x>
|
||||
using FilledWith = typename Builder::template FilledWith<x>;
|
||||
|
||||
template<size_t c>
|
||||
using First = typename Builder::template First<c>;
|
||||
|
||||
template<size_t c>
|
||||
using After = typename Builder::template After<c>;
|
||||
};
|
||||
|
||||
/** build an index number sequence from a type sequence */
|
||||
template<typename...TYPES>
|
||||
struct BuildIdxIter<Types<TYPES...>>
|
||||
{
|
||||
///////////////////////TICKET #987 : since Types<T...> is not variadic, need to strip NullType here (instead of just using sizeof...(TYPES)
|
||||
enum {SIZ = lib::meta::count<typename Types<TYPES...>::List>::value };
|
||||
using Builder = BuildIndexSeq<SIZ>;
|
||||
|
||||
using Ascending = typename Builder::Ascending;
|
||||
using Descending = typename Builder::Descending;
|
||||
|
||||
template<size_t d>
|
||||
using OffsetBy = typename Builder::template OffsetBy<d>;
|
||||
|
||||
template<size_t x>
|
||||
using FilledWith = typename Builder::template FilledWith<x>;
|
||||
|
||||
template<size_t c>
|
||||
using First = typename Builder::template First<c>;
|
||||
|
||||
template<size_t c>
|
||||
using After = typename Builder::template After<c>;
|
||||
};
|
||||
|
||||
#endif ////////////////////////////////////////////////////////////////////////////////TODO reorder
|
||||
|
||||
|
||||
|
||||
|
|
@ -197,6 +89,22 @@ namespace meta {
|
|||
|
||||
/* ==== Rebuild with remoulded variadic sequence ==== **/
|
||||
|
||||
/**
|
||||
* Metaprogramming helper to remould the type sequence
|
||||
* in the template arguments of a variadic template.
|
||||
* The key idea is to construct a new instance of the
|
||||
* target template with an altered sequence; the target
|
||||
* template itself is passed as template-template param.
|
||||
* - `Penult` get the penultimate element of the sequence
|
||||
* - `Ultima` get the last element of the sequence
|
||||
* - `Prefix` rebind to the prefix sequence, leaving out the last
|
||||
* - `Remain` rebind to the sequence starting with the second
|
||||
* - `Revers` rebind to a sequence with reversed order
|
||||
* A secondary helper template variant is provided for rebinding
|
||||
* while prepending or appending a single type parameter.
|
||||
* @note does not work with empty sequences; also the penultimate
|
||||
* of a one-element sequence is mapped to NullType
|
||||
*/
|
||||
template<template<class...> class L, typename...XS>
|
||||
struct _Vari;
|
||||
|
||||
|
|
@ -221,7 +129,7 @@ namespace meta {
|
|||
struct _Vari<L, X>
|
||||
{
|
||||
using Ultima = X;
|
||||
using Penult = NullType;
|
||||
using Penult = NullType; ///< marker for undefined
|
||||
using Remain = L<X>;
|
||||
using Revers = L<X>;
|
||||
using Prefix = L<>;
|
||||
|
|
@ -241,248 +149,5 @@ namespace meta {
|
|||
using Revers = typename _Vari<L, Ultima, _Tail_Rev_>::Prepend;
|
||||
};
|
||||
|
||||
#if false ////////////////////////////////////////////////////////////////////////////////TODO reorder
|
||||
|
||||
/* ==== Build and Rebuild variadic type sequences ==== **/
|
||||
|
||||
/**
|
||||
* Variadic type sequence builder.
|
||||
* This metaprogramming helper template provides an unified view
|
||||
* to handle _»tuple-like« types and variadic _type sequences._
|
||||
* - the constant #SIZ gives the number of elements
|
||||
* - the nested type #Idx can be used as _index sequence_
|
||||
* - #Seq is a _variadic type sequence_ with the extracted types
|
||||
* - #Tup is a std::tuple over these types
|
||||
* - the nested template #Apply wraps each type into another template
|
||||
* - #Rebind likewise instantiates another template with the element types
|
||||
* - #AndAll applies a predicate and combines the result with _logical and_
|
||||
* - #OrAll similarly evaluates _logical or_ on the application results
|
||||
*/
|
||||
template<class X, typename =void>
|
||||
struct ElmTypes
|
||||
{
|
||||
static constexpr size_t SIZ = 1;
|
||||
using Idx = std::index_sequence<SIZ>;
|
||||
using Seq = TySeq<X>;
|
||||
using Tup = std::tuple<X>;
|
||||
|
||||
template<template<class> class META>
|
||||
using Apply = TySeq<META<X>>;
|
||||
template<template<typename...> class O>
|
||||
using Rebind = O<X>;
|
||||
template<template<class> class PRED>
|
||||
using AndAll = std::__and_<PRED<X>>;
|
||||
template<template<class> class PRED>
|
||||
using OrAll = std::__or_<PRED<X>>;
|
||||
};
|
||||
|
||||
/** Partial specialisation to handle type sequences */
|
||||
template<typename...TYPES>
|
||||
struct ElmTypes<TySeq<TYPES...>>
|
||||
{
|
||||
static constexpr size_t SIZ = sizeof...(TYPES);
|
||||
using Idx = std::make_index_sequence<SIZ>;
|
||||
using Seq = TySeq<TYPES...>;
|
||||
using Tup = std::tuple<TYPES...>;
|
||||
|
||||
template<template<class> class META>
|
||||
using Apply = TySeq<META<TYPES>...>;
|
||||
|
||||
template<template<typename...> class O>
|
||||
using Rebind = typename lib::meta::RebindVariadic<O, Seq>::Type;
|
||||
|
||||
template<template<class> class PRED>
|
||||
using AndAll = typename ElmTypes<Apply<PRED>>::template Rebind<std::__and_>;
|
||||
|
||||
template<template<class> class PRED>
|
||||
using OrAll = typename ElmTypes<Apply<PRED>>::template Rebind<std::__or_>;
|
||||
};
|
||||
|
||||
/** partial specialisation to handle types
|
||||
* supporting the C++ »tuple protocol«
|
||||
*/
|
||||
template<class TUP>
|
||||
struct ElmTypes<TUP, enable_if_TupleProtocol<TUP>>
|
||||
{
|
||||
template<typename>
|
||||
struct Extract;
|
||||
template<size_t...idx>
|
||||
struct Extract<std::index_sequence<idx...>>
|
||||
{
|
||||
using ElmTypes = TySeq<typename std::tuple_element<idx,TUP>::type ...>;
|
||||
};
|
||||
|
||||
static constexpr size_t SIZ = std::tuple_size<TUP>::value;
|
||||
|
||||
using Idx = std::make_index_sequence<SIZ>;
|
||||
using Seq = typename Extract<Idx>::ElmTypes;
|
||||
using Tup = typename RebindVariadic<std::tuple, Seq>::Type;
|
||||
|
||||
template<template<class> class META>
|
||||
using Apply = typename ElmTypes<Seq>::template Apply<META>;
|
||||
|
||||
template<template<typename...> class O>
|
||||
using Rebind = typename RebindVariadic<O, Seq>::Type;
|
||||
|
||||
template<template<class> class PRED>
|
||||
using AndAll = typename ElmTypes<Apply<PRED>>::template Rebind<std::__and_>;
|
||||
|
||||
template<template<class> class PRED>
|
||||
using OrAll = typename ElmTypes<Apply<PRED>>::template Rebind<std::__or_>;
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ==== Invoke with index from variadic ==== **/
|
||||
|
||||
/** helper to invoke a functor, passing instances of std::integral_constant
|
||||
* @tparam N size of the index-sequence to use for instantiation
|
||||
*/
|
||||
template<size_t N>
|
||||
class WithIdxSeq
|
||||
{
|
||||
template<class FUN, size_t...idx>
|
||||
static void
|
||||
invoke (FUN&& fun, std::index_sequence<idx...>)
|
||||
{
|
||||
(fun (std::integral_constant<size_t,idx>{}), ...);
|
||||
}
|
||||
|
||||
public:
|
||||
template<class FUN>
|
||||
static void
|
||||
invoke (FUN&& fun)
|
||||
{
|
||||
invoke (std::forward<FUN>(fun), std::make_index_sequence<N>{});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Invoke a function (or λ) with index numbers derived from some variadic count.
|
||||
* Notably this construct can be used for compile-time iteration over a structure.
|
||||
* Instances of `std::integral_constant` are passed in sequence to the functor.
|
||||
* The _size_ of the index sequence is derived from the following sources
|
||||
* - if the type \a TTX is _tuple-like,_ then std::tuple_size<TTX> is used
|
||||
* - otherwise, if the type is a loki-style type sequence or type list,
|
||||
* the number of type nodes is used
|
||||
* - otherwise, as fall-back the number of template parameters is used
|
||||
*/
|
||||
template<class TTX, class FUN>
|
||||
inline void
|
||||
forEachIDX (FUN&& fun)
|
||||
{
|
||||
auto N = []{
|
||||
if constexpr (is_Structured<TTX>())
|
||||
return size_t(std::tuple_size<TTX>::value);
|
||||
else
|
||||
if constexpr (lib::meta::is_Typelist<TTX>::value)
|
||||
return lib::meta::count<typename TTX::List>::value;
|
||||
else
|
||||
{ // Fallback: rebind template arguments into a type sequence
|
||||
using Seq = typename RebindVariadic<TySeq, TTX>::Type;
|
||||
return size_t(count<typename Seq::List>::value);
|
||||
}
|
||||
};
|
||||
|
||||
WithIdxSeq<N()>::invoke (std::forward<FUN> (fun));
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* ==== Manipulation of variadic arguments ==== **/
|
||||
|
||||
namespace { // Implementation delegate template...
|
||||
/**
|
||||
* @internal pick a single argument from a variadic parameter pack
|
||||
* @tparam i the index number (zero based) of the argument to select
|
||||
* @warning i must be smaller than the number of arguments available
|
||||
*/
|
||||
template<size_t i>
|
||||
struct SelectVararg
|
||||
{
|
||||
template<typename ARG, typename...ARGS>
|
||||
static auto
|
||||
get (ARG, ARGS&& ...args)
|
||||
{
|
||||
return SelectVararg<i-1>::get (std::forward<ARGS> (args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
struct SelectVararg<0>
|
||||
{
|
||||
template<typename ARG, typename...ARGS>
|
||||
static auto
|
||||
get (ARG&& a, ARGS...)
|
||||
{
|
||||
return std::forward<ARG>(a);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @internal helper to decide if SelectVararg shall be applied.
|
||||
* When the boolean condition does not hold, then, instead of selecting
|
||||
* from the argument list, an element of type DEFAULT is created as fallback.
|
||||
*/
|
||||
template<bool, typename, size_t idx>
|
||||
struct SelectOrInit
|
||||
: SelectVararg<idx>
|
||||
{ };
|
||||
|
||||
template<typename DEFAULT, size_t idx>
|
||||
struct SelectOrInit<false, DEFAULT, idx>
|
||||
{
|
||||
template<typename...ARGS>
|
||||
static DEFAULT
|
||||
get (ARGS&&...)
|
||||
{
|
||||
return DEFAULT{};
|
||||
}
|
||||
};
|
||||
}//(End)Implementation
|
||||
|
||||
|
||||
/**
|
||||
* Helper to single out one argument from a variadic argument pack.
|
||||
* @tparam idx the index number (zero based) of the argument to select
|
||||
* @remark typically this function is used "driven" by an likewise variadic index sequence,
|
||||
* where the index sequence itself is picked up by a pattern match; this usage pattern
|
||||
* allows arbitrarily to handle some of the arguments of a variable argument list,
|
||||
* as determined by the index sequence passed in.
|
||||
*/
|
||||
template<size_t idx, typename...ARGS>
|
||||
constexpr inline auto
|
||||
pickArg (ARGS&&... args)
|
||||
{
|
||||
static_assert (idx < sizeof...(args), "insufficient number of arguments");
|
||||
|
||||
return SelectVararg<idx>::get (std::forward<ARGS> (args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to pick one initialisation argument from a variadic argument pack,
|
||||
* falling back to a default constructed element of type `DEFAULT` in case of
|
||||
* insufficient number of variadic arguments.
|
||||
* @tparam idx the index number (zero based) of the argument to select
|
||||
* @tparam DEFALUT type of the default element to construct as fallback
|
||||
*/
|
||||
template<size_t idx, typename DEFAULT, typename...ARGS>
|
||||
constexpr inline auto
|
||||
pickInit (ARGS&&... args)
|
||||
{
|
||||
return SelectOrInit<(idx < sizeof...(args)), DEFAULT, idx>::get (std::forward<ARGS> (args)...);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#endif ////////////////////////////////////////////////////////////////////////////////TODO reorder
|
||||
}} // namespace lib::meta
|
||||
#endif /*LIB_META_VARIADIC_REBIND_H*/
|
||||
|
|
|
|||
|
|
@ -189,38 +189,46 @@ namespace util {
|
|||
{
|
||||
using Alt = lib::BranchCase<CASES...>;
|
||||
|
||||
template<typename INIT, typename =lib::meta::disable_if_self<AltModel,INIT>>
|
||||
AltModel (INIT&& init)
|
||||
: Alt{Alt::TOP, forward<INIT> (init)}
|
||||
{ }
|
||||
template<typename EXTRA>
|
||||
using Additionally = AltModel<CASES...,EXTRA>;
|
||||
|
||||
|
||||
|
||||
using SubSeq = typename _Vari<AltModel, CASES...>::Prefix;
|
||||
using Penult = typename _Vari<AltModel, CASES...>::Penult;
|
||||
using Ultima = typename _Vari<AltModel, CASES...>::Ultima;
|
||||
|
||||
template<typename EX>
|
||||
using Additionally = AltModel<CASES...,EX>;
|
||||
|
||||
template<typename EX>
|
||||
Additionally<EX>
|
||||
addBranch()
|
||||
template<typename EXTRA>
|
||||
Additionally<EXTRA>
|
||||
addBranch() ///< mark-up existing model to add a further branch-case
|
||||
{
|
||||
Additionally<EX>& upFaked = reinterpret_cast<Additionally<EX>&> (*this);
|
||||
Additionally<EXTRA>& upFaked = reinterpret_cast<Additionally<EXTRA>&> (*this);
|
||||
return {move (upFaked)};
|
||||
} // this trick works due to similar storage layout
|
||||
|
||||
|
||||
/* === Builder functions to mark which side of the combinator to pick === */
|
||||
|
||||
using SubSeq = typename _Vari<AltModel, CASES...>::Prefix; ///< a nested sub-model to extend
|
||||
using Penult = typename _Vari<AltModel, CASES...>::Penult; ///< plain value expected for left-branch
|
||||
using Ultima = typename _Vari<AltModel, CASES...>::Ultima; ///< plain value expected for right-branch
|
||||
|
||||
static AltModel
|
||||
mark_left (SubSeq&& leftCases)
|
||||
{
|
||||
return {leftCases.template addBranch<Ultima>()};
|
||||
}
|
||||
|
||||
AltModel (SubSeq&& leftCases)
|
||||
: AltModel{leftCases.template addBranch<Ultima>()}
|
||||
{ }
|
||||
static AltModel
|
||||
mark_left (Penult&& leftCase)
|
||||
{
|
||||
return {Alt::TOP-1, move(leftCase)};
|
||||
}
|
||||
|
||||
AltModel (Penult&& leftCase)
|
||||
: Alt{Alt::TOP-1, move(leftCase)}
|
||||
{ }
|
||||
static AltModel
|
||||
mark_right (Ultima&& rightCase)
|
||||
{
|
||||
return {Alt::TOP, move(rightCase)};
|
||||
}
|
||||
|
||||
AltModel (Ultima&& rightCase)
|
||||
: Alt{Alt::TOP, move(rightCase)}
|
||||
private:
|
||||
template<typename INIT>
|
||||
AltModel (size_t branchID, INIT&& init)
|
||||
: Alt{branchID, forward<INIT> (init)}
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
@ -246,7 +254,7 @@ namespace util {
|
|||
using Result = TAG<R1,R2>;
|
||||
};
|
||||
|
||||
/** Generic case : extend a structured model by further branch */
|
||||
/** Generic case : extend a structured model by further branch */
|
||||
template<template<class...> class TAG, class...RS, class R2>
|
||||
struct _Join<TAG,TAG<RS...>,R2>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ namespace test {
|
|||
auto e2 = parseSeq(s2);
|
||||
CHECK ( e2.result);
|
||||
|
||||
using SeqRes = std::decay_t<decltype(*e2.result)>; // Note: the result type depends on the actual syntax construction
|
||||
using SeqRes = decltype(e2)::Result; // Note: the result type depends on the actual syntax construction
|
||||
CHECK (is_Tuple<SeqRes>()); // Result model from sequence is the tuple of terminal results
|
||||
auto& [r1,r2] = *e2.result;
|
||||
CHECK (r1.str() == "hello"_expect);
|
||||
|
|
@ -219,56 +219,80 @@ namespace test {
|
|||
*/
|
||||
void
|
||||
acceptAlternatives()
|
||||
{
|
||||
{ //_______________________________
|
||||
// Demonstrate Alt-Model mechanics
|
||||
using R1 = char;
|
||||
using R2 = string;
|
||||
using R3 = double;
|
||||
|
||||
// build Model-Alternatives incrementally
|
||||
using A1 = AltModel<R1>;
|
||||
SHOW_EXPR(showType<A1>())
|
||||
CHECK (showType<A1>() == "parse::AltModel<char>"_expect);
|
||||
string s{"second"};
|
||||
|
||||
using A2 = A1::Additionally<R2>;
|
||||
SHOW_EXPR(showType<A2>())
|
||||
CHECK (showType<A2>() == "parse::AltModel<char, string>"_expect);
|
||||
|
||||
A2 model2{s};
|
||||
SHOW_EXPR(sizeof(A2));
|
||||
// create instance to represent this second branch...
|
||||
A2 model2 = A2::mark_right ("seduced");
|
||||
CHECK (sizeof(A2) >= sizeof(string)+sizeof(size_t));
|
||||
SHOW_EXPR(model2.SIZ);
|
||||
CHECK (model2.SIZ == sizeof(string));
|
||||
SHOW_EXPR(model2.TOP);
|
||||
CHECK (model2.TOP == 1);
|
||||
SHOW_EXPR(model2.selected())
|
||||
CHECK (model2.TOP == 1);
|
||||
CHECK (model2.selected() == 1);
|
||||
SHOW_EXPR(model2.get<1>())
|
||||
CHECK (model2.get<1>() == "second");
|
||||
CHECK (model2.get<1>() == "seduced");
|
||||
|
||||
using A3 = A2::Additionally<R3>;
|
||||
A3 model3{model2.addBranch<R3>()};
|
||||
SHOW_TYPE(A3)
|
||||
SHOW_EXPR(showType<A3>())
|
||||
A3 model3 = A3::mark_left (move (model2));
|
||||
CHECK (showType<A3>() == "parse::AltModel<char, string, double>"_expect);
|
||||
SHOW_EXPR(sizeof(A3));
|
||||
CHECK (sizeof(A3) == sizeof(A2));
|
||||
SHOW_EXPR(model3.SIZ);
|
||||
SHOW_EXPR(model3.TOP);
|
||||
CHECK (model3.TOP == 2);
|
||||
SHOW_EXPR(model3.selected())
|
||||
CHECK (model3.TOP == 2);
|
||||
CHECK (model3.selected() == 1);
|
||||
SHOW_EXPR(model3.get<1>())
|
||||
CHECK (model3.get<1>() == "second");
|
||||
CHECK (model3.get<1>() == "seduced");
|
||||
|
||||
auto res = move(model3);
|
||||
SHOW_TYPE(decltype(res))
|
||||
SHOW_EXPR(showType<decltype(res)>())
|
||||
CHECK (showType<decltype(res)>() == "parse::AltModel<char, string, double>"_expect);
|
||||
SHOW_EXPR(sizeof(res))
|
||||
CHECK (sizeof(res) == sizeof(A2));
|
||||
SHOW_EXPR(res.selected())
|
||||
CHECK (res.selected() == 1);
|
||||
SHOW_EXPR(res.get<1>())
|
||||
CHECK (res.get<1>() == "second");
|
||||
CHECK (res.selected() == 1);
|
||||
CHECK (res.get<1>() == "seduced");
|
||||
|
||||
|
||||
//_____________________________________________
|
||||
// Demonstration: how branch combinator works....
|
||||
auto term1 = buildConnex ("brazen");
|
||||
auto term2 = buildConnex ("bragging");
|
||||
auto parseAlt = [&](StrView toParse)
|
||||
{
|
||||
using R1 = decltype(term1)::Result;
|
||||
using R2 = decltype(term2)::Result;
|
||||
using SumResult = AltModel<R1,R2>;
|
||||
using SumEval = Eval<SumResult>;
|
||||
auto eval1 = term1.parse (toParse);
|
||||
if (eval1.result)
|
||||
{
|
||||
uint endBranch1 = eval1.consumed;
|
||||
return SumEval{SumResult::mark_left (move(*eval1.result))
|
||||
,endBranch1
|
||||
};
|
||||
}
|
||||
auto eval2 = term2.parse (toParse);
|
||||
if (eval2.result)
|
||||
{
|
||||
uint endBranch2 = eval2.consumed;
|
||||
return SumEval{SumResult::mark_right (move(*eval2.result))
|
||||
,endBranch2
|
||||
};
|
||||
}
|
||||
return SumEval{std::nullopt};
|
||||
};
|
||||
string s1{"decent contender"};
|
||||
string s2{"brazen dicktator"};
|
||||
|
||||
auto e1 = parseAlt(s1);
|
||||
CHECK (not e1.result); // does not compute....
|
||||
auto e2 = parseAlt(s2); // one hell of a match!
|
||||
CHECK ( e2.result);
|
||||
CHECK (e2.result->selected() == 0); // Selector-ID of the first matching branch (here #0)
|
||||
CHECK (e2.result->get<0>().str() == "brazen"); // We know that branch#0 holds a RegExp-Matcher (from term1)
|
||||
CHECK (e2.result->get<0>().suffix() == " dicktator");
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -56523,15 +56523,17 @@
|
|||
<node CREATED="1737483220362" ID="ID_480511006" MODIFIED="1737483229460" TEXT="die Fälle sind durch das _Join-Template bereits vorsortiert"/>
|
||||
<node CREATED="1737483230120" ID="ID_1640338591" MODIFIED="1737483245762" TEXT="dieses generiert auch bereits die korrekte AltModel-Instanz"/>
|
||||
</node>
|
||||
<node CREATED="1737483307902" ID="ID_1499952349" MODIFIED="1737483323544" TEXT="brauche passende Konstruktoren">
|
||||
<node COLOR="#338800" CREATED="1737483307902" ID="ID_1499952349" MODIFIED="1737507877713" TEXT="brauche passende Konstruktoren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1737483324699" ID="ID_1345828060" MODIFIED="1737483327919" TEXT="und zwar...">
|
||||
<node CREATED="1737483328843" ID="ID_1658557856" MODIFIED="1737483335394" TEXT="links-sub-Model"/>
|
||||
<node CREATED="1737483335987" ID="ID_986287971" MODIFIED="1737483342517" TEXT="links-Einzelwert"/>
|
||||
<node CREATED="1737483343129" ID="ID_1446250040" MODIFIED="1737483347092" TEXT="rechts-Einzelwert"/>
|
||||
</node>
|
||||
<node CREATED="1737483348177" ID="ID_1350491098" MODIFIED="1737483358069" TEXT="brauche dazu die konkreten Typen">
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1737483360495" ID="ID_1943823761" MODIFIED="1737483375712" TEXT="per Rebinding-Hilfstemplate aufbauen">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
<node COLOR="#435e98" CREATED="1737483348177" ID="ID_1350491098" MODIFIED="1737507857907" TEXT="brauche dazu die konkreten Typen">
|
||||
<icon BUILTIN="yes"/>
|
||||
<node COLOR="#338800" CREATED="1737483360495" FOLDED="true" ID="ID_1943823761" MODIFIED="1737507871184" TEXT="per Rebinding-Hilfstemplate aufbauen">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
<node CREATED="1737483378196" ID="ID_1296449236" LINK="https://stackoverflow.com/a/34941417/444796" MODIFIED="1737483733563" TEXT="Problem: C++ kann nur sehr limitiert gegen Argument-Packs matchen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
|
@ -56580,7 +56582,7 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1737496156742" ID="ID_1900356198" MODIFIED="1737496733785" TEXT="das sieht nach einem generischen Tool aus">
|
||||
<node BACKGROUND_COLOR="#e1e2ba" COLOR="#435e98" CREATED="1737496156742" ID="ID_1900356198" MODIFIED="1737507842748" TEXT="das sieht nach einem generischen Tool aus">
|
||||
<linktarget COLOR="#fdfcc6" DESTINATION="ID_1900356198" ENDARROW="Default" ENDINCLINATION="17;-73;" ID="Arrow_ID_987482225" SOURCE="ID_1009577491" STARTARROW="None" STARTINCLINATION="-279;12;"/>
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1737496171990" ID="ID_1854927200" MODIFIED="1737496227434" TEXT="�� neuer Header: rebind-variadic-rebind.hpp"/>
|
||||
|
|
@ -56612,6 +56614,54 @@
|
|||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node CREATED="1737503596247" ID="ID_371220796" MODIFIED="1737503608693" TEXT="Auswertung und Model-Erzeugung">
|
||||
<node COLOR="#338800" CREATED="1737503609673" ID="ID_984166098" MODIFIED="1737507882083" TEXT="wieder zunächst freistehend im Test ausformulieren">
|
||||
<icon BUILTIN="button_ok"/>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#c8c0b6" COLOR="#435e98" CREATED="1737504161230" ID="ID_757848579" MODIFIED="1737507887375" TEXT="gleiches Baumuster wie der seqConnex">
|
||||
<icon BUILTIN="idea"/>
|
||||
<node CREATED="1737504193738" ID="ID_1385503322" MODIFIED="1737504206428" TEXT="wird hier sogar noch einfacher"/>
|
||||
<node CREATED="1737504208567" ID="ID_1221738967" MODIFIED="1737507938424" TEXT="Design scheint sehr gut zu passen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
...Hinweis darauf ist der Umstand, daß ich gar nicht mehr viel auswerten / prüfen muß, sondern direkt der Match auf die Konstruktor-Argumente den Rest der Logik erledigt.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#e0ceaa" COLOR="#690f14" CREATED="1737504141641" ID="ID_457554053" MODIFIED="1737507459721" TEXT="Problem: Konstruktor-Signaturen können zusammenfallen">
|
||||
<icon BUILTIN="messagebox_warning"/>
|
||||
<node CREATED="1737504226576" ID="ID_1730264427" MODIFIED="1737504238455" TEXT="so ein Pech aber auch...">
|
||||
<icon BUILTIN="smily_bad"/>
|
||||
</node>
|
||||
<node CREATED="1737504240388" ID="ID_718576565" MODIFIED="1737504257555" TEXT="...wenn zufällig beide Zweige im Kombinator den gleichen Ergebnistyp haben"/>
|
||||
<node CREATED="1737504264413" ID="ID_198801973" MODIFIED="1737504277138" TEXT="muß anderweitig einen klaren Marker mitgeben"/>
|
||||
<node CREATED="1737504278222" ID="ID_7748352" MODIFIED="1737504291496" TEXT="⟹ Builder-Funktionen bieten">
|
||||
<node CREATED="1737507477423" ID="ID_712733860" MODIFIED="1737507490145" TEXT="ist maßgeschneidert für diesen einen Fall"/>
|
||||
<node CREATED="1737507491637" ID="ID_397795294" MODIFIED="1737507505855" TEXT="Clients sollen nur selected() und get<i>() verwenden"/>
|
||||
<node CREATED="1737507511586" ID="ID_1197062880" MODIFIED="1737507548997" TEXT="eigentlichen Konstruktor besser private machen">
|
||||
<richcontent TYPE="NOTE"><html>
|
||||
<head>
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
da geht nämlich eine Branch-ID ein, und die muß <= TOP sein
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
</richcontent>
|
||||
<icon BUILTIN="yes"/>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
</node>
|
||||
<node BACKGROUND_COLOR="#eee5c3" COLOR="#990000" CREATED="1737417144217" ID="ID_375516701" MODIFIED="1737417153090" TEXT="in einen Connex-Builder verpacken">
|
||||
<icon BUILTIN="flag-yellow"/>
|
||||
|
|
|
|||
Loading…
Reference in a new issue