From bb0b73e2a73fe817c19975a067cc1804f8fd5cf3 Mon Sep 17 00:00:00 2001 From: Ichthyostega Date: Mon, 23 Jun 2025 19:23:20 +0200 Subject: [PATCH] Upgrade: switch existing usages of `forEachIDX` ...to rely on the new formulation and the extended template `WithIdxSeq` This is in preparation to use this new iteration scheme also from the tuple_like concept --- src/lib/meta/variadic-helper.hpp | 78 ++++++++++++++------ tests/library/meta/tuple-helper-test.cpp | 94 ++---------------------- 2 files changed, 62 insertions(+), 110 deletions(-) diff --git a/src/lib/meta/variadic-helper.hpp b/src/lib/meta/variadic-helper.hpp index b23f6e079..d3f81b445 100644 --- a/src/lib/meta/variadic-helper.hpp +++ b/src/lib/meta/variadic-helper.hpp @@ -244,23 +244,56 @@ namespace meta { /** helper to invoke a functor, passing instances of std::integral_constant * @tparam N size of the index-sequence to use for instantiation + * @remark the functor is given for... + * - to be invoked either (as void) for each index + * - or as a predicate, combining the results with AND / OR */ template class WithIdxSeq { template - static void - invoke (FUN&& fun, std::index_sequence) + static constexpr void + invoke_forEach (FUN&& fun, std::index_sequence) { (fun (std::integral_constant{}), ...); } + template + static constexpr bool + and_forEach (FUN&& fun, std::index_sequence) + { + return (fun (std::integral_constant{}) and ...); + } + + template + static constexpr bool + or_forEach (FUN&& fun, std::index_sequence) + { + return (fun (std::integral_constant{}) or ...); + } + + using IdxSeq = std::make_index_sequence; + public: template - static void + static constexpr void invoke (FUN&& fun) { - invoke (std::forward(fun), std::make_index_sequence{}); + invoke_forEach (std::forward(fun), IdxSeq{}); + } + + template + static constexpr bool + andAll (FUN&& fun) + { + return and_forEach (std::forward(fun), IdxSeq{}); + } + + template + static constexpr bool + orAny (FUN&& fun) + { + return or_forEach (std::forward(fun), IdxSeq{}); } }; @@ -268,30 +301,31 @@ namespace meta { * 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 + * The _size_ of the index sequence is derived using a \ref ElmTypes specialisation * - 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 + * - otherwise, if the type is a _type sequence_ (`Types`), then + * the size of this meta sequence is used + * - otherwise, sequence-size ≡ 1 is used as fall-back */ 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(); - else - { // Fallback: rebind template arguments into a type sequence - using Seq = typename RebindVariadic::Type; - return size_t(count()); - } - }; - - WithIdxSeq::invoke (std::forward (fun)); + WithIdxSeq::SIZ>::invoke (std::forward (fun)); + } + + template + inline bool + andAllIDX (FUN&& fun) + { + return WithIdxSeq::SIZ>::andAll (std::forward (fun)); + } + + template + inline bool + orAnyIDX (FUN&& fun) + { + return WithIdxSeq::SIZ>::orAny (std::forward (fun)); } diff --git a/tests/library/meta/tuple-helper-test.cpp b/tests/library/meta/tuple-helper-test.cpp index 1018d5261..e77fb3a54 100644 --- a/tests/library/meta/tuple-helper-test.cpp +++ b/tests/library/meta/tuple-helper-test.cpp @@ -62,88 +62,6 @@ namespace test { } // (End) test data -////////////////////////////////////////OOO - template - class WithIdxSeq2 - { - template - static void - invoke_forEach (FUN&& fun, std::index_sequence) - { - (fun (std::integral_constant{}), ...); - } - - template - static bool - and_forEach (FUN&& fun, std::index_sequence) - { - return (fun (std::integral_constant{}) and ...); - } - - template - static bool - or_forEach (FUN&& fun, std::index_sequence) - { - return (fun (std::integral_constant{}) or ...); - } - - using IdxSeq = typename ElmTypes::Idx; - - public: - template - static void - invoke (FUN&& fun) - { - invoke_forEach (std::forward(fun), IdxSeq{}); - } - - template - static bool - andAll (FUN&& fun) - { - return and_forEach (std::forward(fun), IdxSeq{}); - } - - template - static bool - orAny (FUN&& fun) - { - return or_forEach (std::forward(fun), IdxSeq{}); - } - }; - - /** - * 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 - forEachIDX2 (FUN&& fun) - { - WithIdxSeq2::invoke (std::forward (fun)); - } - - template - inline bool - andAllIDX2 (FUN&& fun) - { - return WithIdxSeq2::andAll (std::forward (fun)); - } - - template - inline bool - orAnyIDX2 (FUN&& fun) - { - return WithIdxSeq2::orAny (std::forward (fun)); - } - -////////////////////////////////////////OOO /*********************************************************************//** @@ -280,7 +198,7 @@ namespace test { _Fmt showElm{"|%d|▷%s◁"}; dump = ""; // apply λ-generic with (constexpr) index - forEachIDX2 ([&](auto idx) + forEachIDX ([&](auto idx) { using Idx = decltype(idx); using Iii = std::integral_constant; @@ -293,16 +211,16 @@ namespace test { // apply λ-generic and combine results auto boolFun = [&](auto idx){ return bool(get(tup)); }; - CHECK ( andAllIDX2 (boolFun)); + CHECK ( andAllIDX (boolFun)); get<0>(tup) = 0; // ◁————————————————————— demonstrate that a run-time evaluation happens - CHECK (not andAllIDX2 (boolFun)); - CHECK ( orAnyIDX2 (boolFun)); + CHECK (not andAllIDX (boolFun)); + CHECK ( orAnyIDX (boolFun)); // can use this mechanism also for sole compile-time computation auto integralCheckFun = [](auto idx){ return std::is_integral_v>;}; - CHECK (not andAllIDX2 (integralCheckFun)); - CHECK ( orAnyIDX2 (integralCheckFun)); + CHECK (not andAllIDX (integralCheckFun)); + CHECK ( orAnyIDX (integralCheckFun)); // Note however, the same can also be achieved simpler, // using any meta-function which takes a single type argument...