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
This commit is contained in:
Fischlurch 2025-06-23 19:23:20 +02:00
parent 49e7b31511
commit bb0b73e2a7
2 changed files with 62 additions and 110 deletions

View file

@ -244,23 +244,56 @@ namespace meta {
/** helper to invoke a functor, passing instances of std::integral_constant /** helper to invoke a functor, passing instances of std::integral_constant
* @tparam N size of the index-sequence to use for instantiation * @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<size_t N> template<size_t N>
class WithIdxSeq class WithIdxSeq
{ {
template<class FUN, size_t...idx> template<class FUN, size_t...idx>
static void static constexpr void
invoke (FUN&& fun, std::index_sequence<idx...>) invoke_forEach (FUN&& fun, std::index_sequence<idx...>)
{ {
(fun (std::integral_constant<size_t,idx>{}), ...); (fun (std::integral_constant<size_t,idx>{}), ...);
} }
template<class FUN, size_t...idx>
static constexpr bool
and_forEach (FUN&& fun, std::index_sequence<idx...>)
{
return (fun (std::integral_constant<size_t,idx>{}) and ...);
}
template<class FUN, size_t...idx>
static constexpr bool
or_forEach (FUN&& fun, std::index_sequence<idx...>)
{
return (fun (std::integral_constant<size_t,idx>{}) or ...);
}
using IdxSeq = std::make_index_sequence<N>;
public: public:
template<class FUN> template<class FUN>
static void static constexpr void
invoke (FUN&& fun) invoke (FUN&& fun)
{ {
invoke (std::forward<FUN>(fun), std::make_index_sequence<N>{}); invoke_forEach (std::forward<FUN>(fun), IdxSeq{});
}
template<class FUN>
static constexpr bool
andAll (FUN&& fun)
{
return and_forEach (std::forward<FUN>(fun), IdxSeq{});
}
template<class FUN>
static constexpr bool
orAny (FUN&& fun)
{
return or_forEach (std::forward<FUN>(fun), IdxSeq{});
} }
}; };
@ -268,30 +301,31 @@ namespace meta {
* Invoke a function (or λ) with index numbers derived from some variadic count. * 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. * 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. * 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<TTX> is used * - 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, * - otherwise, if the type is a _type sequence_ (`Types<T...>`), then
* the number of type nodes is used * the size of this meta sequence is used
* - otherwise, as fall-back the number of template parameters is used * - otherwise, sequence-size 1 is used as fall-back
*/ */
template<class TTX, class FUN> template<class TTX, class FUN>
inline void inline void
forEachIDX (FUN&& fun) forEachIDX (FUN&& fun)
{ {
auto N = []{ WithIdxSeq<ElmTypes<TTX>::SIZ>::invoke (std::forward<FUN> (fun));
if constexpr (is_Structured<TTX>()) }
return size_t(std::tuple_size<TTX>::value);
else template<class TTX, class FUN>
if constexpr (lib::meta::is_Typelist<TTX>::value) inline bool
return lib::meta::count<typename TTX::List>(); andAllIDX (FUN&& fun)
else {
{ // Fallback: rebind template arguments into a type sequence return WithIdxSeq<ElmTypes<TTX>::SIZ>::andAll (std::forward<FUN> (fun));
using Seq = typename RebindVariadic<Types, TTX>::Type; }
return size_t(count<Seq>());
} template<class TTX, class FUN>
}; inline bool
orAnyIDX (FUN&& fun)
WithIdxSeq<N()>::invoke (std::forward<FUN> (fun)); {
return WithIdxSeq<ElmTypes<TTX>::SIZ>::orAny (std::forward<FUN> (fun));
} }

View file

@ -62,88 +62,6 @@ namespace test {
} // (End) test data } // (End) test data
////////////////////////////////////////OOO
template<class TTX>
class WithIdxSeq2
{
template<class FUN, size_t...idx>
static void
invoke_forEach (FUN&& fun, std::index_sequence<idx...>)
{
(fun (std::integral_constant<size_t,idx>{}), ...);
}
template<class FUN, size_t...idx>
static bool
and_forEach (FUN&& fun, std::index_sequence<idx...>)
{
return (fun (std::integral_constant<size_t,idx>{}) and ...);
}
template<class FUN, size_t...idx>
static bool
or_forEach (FUN&& fun, std::index_sequence<idx...>)
{
return (fun (std::integral_constant<size_t,idx>{}) or ...);
}
using IdxSeq = typename ElmTypes<TTX>::Idx;
public:
template<class FUN>
static void
invoke (FUN&& fun)
{
invoke_forEach (std::forward<FUN>(fun), IdxSeq{});
}
template<class FUN>
static bool
andAll (FUN&& fun)
{
return and_forEach (std::forward<FUN>(fun), IdxSeq{});
}
template<class FUN>
static bool
orAny (FUN&& fun)
{
return or_forEach (std::forward<FUN>(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<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
forEachIDX2 (FUN&& fun)
{
WithIdxSeq2<TTX>::invoke (std::forward<FUN> (fun));
}
template<class TTX, class FUN>
inline bool
andAllIDX2 (FUN&& fun)
{
return WithIdxSeq2<TTX>::andAll (std::forward<FUN> (fun));
}
template<class TTX, class FUN>
inline bool
orAnyIDX2 (FUN&& fun)
{
return WithIdxSeq2<TTX>::orAny (std::forward<FUN> (fun));
}
////////////////////////////////////////OOO
/*********************************************************************//** /*********************************************************************//**
@ -280,7 +198,7 @@ namespace test {
_Fmt showElm{"|%d|▷%s◁"}; _Fmt showElm{"|%d|▷%s◁"};
dump = ""; dump = "";
// apply λ-generic with (constexpr) index // apply λ-generic with (constexpr) index
forEachIDX2<Tup> ([&](auto idx) forEachIDX<Tup> ([&](auto idx)
{ {
using Idx = decltype(idx); using Idx = decltype(idx);
using Iii = std::integral_constant<size_t, idx.value>; using Iii = std::integral_constant<size_t, idx.value>;
@ -293,16 +211,16 @@ namespace test {
// apply λ-generic and combine results // apply λ-generic and combine results
auto boolFun = [&](auto idx){ return bool(get<idx>(tup)); }; auto boolFun = [&](auto idx){ return bool(get<idx>(tup)); };
CHECK ( andAllIDX2<Tup> (boolFun)); CHECK ( andAllIDX<Tup> (boolFun));
get<0>(tup) = 0; // ◁————————————————————— demonstrate that a run-time evaluation happens get<0>(tup) = 0; // ◁————————————————————— demonstrate that a run-time evaluation happens
CHECK (not andAllIDX2<Tup> (boolFun)); CHECK (not andAllIDX<Tup> (boolFun));
CHECK ( orAnyIDX2<Tup> (boolFun)); CHECK ( orAnyIDX<Tup> (boolFun));
// can use this mechanism also for sole compile-time computation // can use this mechanism also for sole compile-time computation
auto integralCheckFun = [](auto idx){ return std::is_integral_v<std::tuple_element_t<idx,Tup>>;}; auto integralCheckFun = [](auto idx){ return std::is_integral_v<std::tuple_element_t<idx,Tup>>;};
CHECK (not andAllIDX2<Tup> (integralCheckFun)); CHECK (not andAllIDX<Tup> (integralCheckFun));
CHECK ( orAnyIDX2<Tup> (integralCheckFun)); CHECK ( orAnyIDX<Tup> (integralCheckFun));
// Note however, the same can also be achieved simpler, // Note however, the same can also be achieved simpler,
// using any meta-function which takes a single type argument... // using any meta-function which takes a single type argument...