diff --git a/src/lib/meta/variadic-helper.hpp b/src/lib/meta/variadic-helper.hpp index 88dcece3d..b36f8bfa4 100644 --- a/src/lib/meta/variadic-helper.hpp +++ b/src/lib/meta/variadic-helper.hpp @@ -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` - * @tparam X a variadic template - */ - template class X, typename...ARGS> - struct RebindVariadic - { - using Type = X; - }; - - template class X - ,template class U - ,typename...ARGS> - struct RebindVariadic> - { - using Type = X; - }; - - - -#endif ////////////////////////////////////////////////////////////////////////////////TODO reorder diff --git a/src/lib/meta/variadic-rebind.hpp b/src/lib/meta/variadic-rebind.hpp index b6eefc0e1..1042fa128 100644 --- a/src/lib/meta/variadic-rebind.hpp +++ b/src/lib/meta/variadic-rebind.hpp @@ -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 + ** struct MyModel + ** { + ** using SubSeq = typename _Vari::Prefix; + ** + ** // adapt a predecessor sequence + ** MyModel (SubSeq&& subModel); + ** + ** + ** using Tuple = typename RebindVariadic::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 - struct IndexSeq - { - template - using AppendElm = IndexSeq; - - template - using PrependElm = IndexSeq; - }; - - /** - * build regular sequences of index number - * e.g. `IndexSeq<0, 1, 2, ..., n-1>` - */ - template - struct BuildIndexSeq - { - using Ascending = typename BuildIndexSeq::Ascending::template AppendElm; - using Descending = typename BuildIndexSeq::Descending::template PrependElm; - - template - using OffsetBy = typename BuildIndexSeq::template OffsetBy::template AppendElm; - - template - using FilledWith = typename BuildIndexSeq::template FilledWith::template AppendElm; - - template - using First = typename BuildIndexSeq::Ascending; - - template - using After = typename BuildIndexSeq< (n>c)? n-c : 0>::template OffsetBy; - }; - - template<> - struct BuildIndexSeq<0> - { - using Empty = IndexSeq<>; - - using Ascending = Empty; - using Descending = Empty; - - template - using OffsetBy = Empty; - - template - using FilledWith = Empty; - - template - using First = Empty; - - template - using After = Empty; - }; - - - - /** - * build a sequence of index numbers based on a type sequence - */ - template - struct BuildIdxIter - { - enum {SIZ = sizeof...(TYPES) }; - using Builder = BuildIndexSeq; - - using Ascending = typename Builder::Ascending; - using Descending = typename Builder::Descending; - - template - using OffsetBy = typename Builder::template OffsetBy; - - template - using FilledWith = typename Builder::template FilledWith; - - template - using First = typename Builder::template First; - - template - using After = typename Builder::template After; - }; - - /** build an index number sequence from a type sequence */ - template - struct BuildIdxIter> - { - ///////////////////////TICKET #987 : since Types is not variadic, need to strip NullType here (instead of just using sizeof...(TYPES) - enum {SIZ = lib::meta::count::List>::value }; - using Builder = BuildIndexSeq; - - using Ascending = typename Builder::Ascending; - using Descending = typename Builder::Descending; - - template - using OffsetBy = typename Builder::template OffsetBy; - - template - using FilledWith = typename Builder::template FilledWith; - - template - using First = typename Builder::template First; - - template - using After = typename Builder::template After; - }; - -#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 class L, typename...XS> struct _Vari; @@ -221,7 +129,7 @@ namespace meta { struct _Vari { using Ultima = X; - using Penult = NullType; + using Penult = NullType; ///< marker for undefined using Remain = L; using Revers = L; using Prefix = L<>; @@ -241,248 +149,5 @@ namespace meta { using Revers = typename _Vari::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 - struct ElmTypes - { - static constexpr size_t SIZ = 1; - using Idx = std::index_sequence; - using Seq = TySeq; - using Tup = std::tuple; - - template class META> - using Apply = TySeq>; - template class O> - using Rebind = O; - template class PRED> - using AndAll = std::__and_>; - template class PRED> - using OrAll = std::__or_>; - }; - - /** Partial specialisation to handle type sequences */ - template - struct ElmTypes> - { - static constexpr size_t SIZ = sizeof...(TYPES); - using Idx = std::make_index_sequence; - using Seq = TySeq; - using Tup = std::tuple; - - template class META> - using Apply = TySeq...>; - - template class O> - using Rebind = typename lib::meta::RebindVariadic::Type; - - template class PRED> - using AndAll = typename ElmTypes>::template Rebind; - - template class PRED> - using OrAll = typename ElmTypes>::template Rebind; - }; - - /** partial specialisation to handle types - * supporting the C++ »tuple protocol« - */ - template - struct ElmTypes> - { - template - struct Extract; - template - struct Extract> - { - using ElmTypes = TySeq::type ...>; - }; - - static constexpr size_t SIZ = std::tuple_size::value; - - using Idx = std::make_index_sequence; - using Seq = typename Extract::ElmTypes; - using Tup = typename RebindVariadic::Type; - - template class META> - using Apply = typename ElmTypes::template Apply; - - template class O> - using Rebind = typename RebindVariadic::Type; - - template class PRED> - using AndAll = typename ElmTypes>::template Rebind; - - template class PRED> - using OrAll = typename ElmTypes>::template Rebind; - }; - - - - - - - /* ==== 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 - class WithIdxSeq - { - template - static void - invoke (FUN&& fun, std::index_sequence) - { - (fun (std::integral_constant{}), ...); - } - - public: - template - static void - invoke (FUN&& fun) - { - invoke (std::forward(fun), std::make_index_sequence{}); - } - }; - - /** - * 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 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 - inline void - forEachIDX (FUN&& fun) - { - auto N = []{ - if constexpr (is_Structured()) - return size_t(std::tuple_size::value); - else - if constexpr (lib::meta::is_Typelist::value) - return lib::meta::count::value; - else - { // Fallback: rebind template arguments into a type sequence - using Seq = typename RebindVariadic::Type; - return size_t(count::value); - } - }; - - WithIdxSeq::invoke (std::forward (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 - struct SelectVararg - { - template - static auto - get (ARG, ARGS&& ...args) - { - return SelectVararg::get (std::forward (args)...); - } - }; - - template<> - struct SelectVararg<0> - { - template - static auto - get (ARG&& a, ARGS...) - { - return std::forward(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 - struct SelectOrInit - : SelectVararg - { }; - - template - struct SelectOrInit - { - template - 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 - constexpr inline auto - pickArg (ARGS&&... args) - { - static_assert (idx < sizeof...(args), "insufficient number of arguments"); - - return SelectVararg::get (std::forward (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 - constexpr inline auto - pickInit (ARGS&&... args) - { - return SelectOrInit<(idx < sizeof...(args)), DEFAULT, idx>::get (std::forward (args)...); - } - - - -#endif ////////////////////////////////////////////////////////////////////////////////TODO reorder }} // namespace lib::meta #endif /*LIB_META_VARIADIC_REBIND_H*/ diff --git a/src/lib/parse.hpp b/src/lib/parse.hpp index cdd0ba508..294a71a25 100644 --- a/src/lib/parse.hpp +++ b/src/lib/parse.hpp @@ -189,38 +189,46 @@ namespace util { { using Alt = lib::BranchCase; - template> - AltModel (INIT&& init) - : Alt{Alt::TOP, forward (init)} - { } + template + using Additionally = AltModel; - - - using SubSeq = typename _Vari::Prefix; - using Penult = typename _Vari::Penult; - using Ultima = typename _Vari::Ultima; - - template - using Additionally = AltModel; - - template - Additionally - addBranch() + template + Additionally + addBranch() ///< mark-up existing model to add a further branch-case { - Additionally& upFaked = reinterpret_cast&> (*this); + Additionally& upFaked = reinterpret_cast&> (*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::Prefix; ///< a nested sub-model to extend + using Penult = typename _Vari::Penult; ///< plain value expected for left-branch + using Ultima = typename _Vari::Ultima; ///< plain value expected for right-branch + + static AltModel + mark_left (SubSeq&& leftCases) + { + return {leftCases.template addBranch()}; } - AltModel (SubSeq&& leftCases) - : AltModel{leftCases.template addBranch()} - { } + 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 + AltModel (size_t branchID, INIT&& init) + : Alt{branchID, forward (init)} { } }; @@ -246,7 +254,7 @@ namespace util { using Result = TAG; }; - /** Generic case : extend a structured model by further branch */ + /** Generic case : extend a structured model by further branch */ template class TAG, class...RS, class R2> struct _Join,R2> { diff --git a/tests/library/parse-test.cpp b/tests/library/parse-test.cpp index 861678049..856c0c4f2 100644 --- a/tests/library/parse-test.cpp +++ b/tests/library/parse-test.cpp @@ -174,7 +174,7 @@ namespace test { auto e2 = parseSeq(s2); CHECK ( e2.result); - using SeqRes = std::decay_t; // 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()); // 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; -SHOW_EXPR(showType()) CHECK (showType() == "parse::AltModel"_expect); - string s{"second"}; + using A2 = A1::Additionally; -SHOW_EXPR(showType()) CHECK (showType() == "parse::AltModel"_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; - A3 model3{model2.addBranch()}; -SHOW_TYPE(A3) -SHOW_EXPR(showType()) + A3 model3 = A3::mark_left (move (model2)); CHECK (showType() == "parse::AltModel"_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()) CHECK (showType() == "parse::AltModel"_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; + using SumEval = Eval; + 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"); } }; diff --git a/wiki/thinkPad.ichthyo.mm b/wiki/thinkPad.ichthyo.mm index 79ab70f3b..09883ed1d 100644 --- a/wiki/thinkPad.ichthyo.mm +++ b/wiki/thinkPad.ichthyo.mm @@ -56523,15 +56523,17 @@ - + + - - - + + + + @@ -56580,7 +56582,7 @@ - + @@ -56612,6 +56614,54 @@ + + + + + + + + + + + + + +

+ ...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. +

+ + +
+
+
+ + + + + + + + + + + + + + + + +

+ da geht nämlich eine Branch-ID ein, und die muß <= TOP sein +

+ + +
+ +
+
+
+