From 0286d02fbe28fc7b215f98e08385295abd91bb2f Mon Sep 17 00:00:00 2001 From: reneSchm <49305466+reneSchm@users.noreply.github.com> Date: Mon, 12 Jan 2026 17:05:06 +0100 Subject: [PATCH 1/5] refactor index_of_type implementation --- cpp/memilio/utils/metaprogramming.h | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/cpp/memilio/utils/metaprogramming.h b/cpp/memilio/utils/metaprogramming.h index fd2e110a84..873e4701bf 100644 --- a/cpp/memilio/utils/metaprogramming.h +++ b/cpp/memilio/utils/metaprogramming.h @@ -194,6 +194,12 @@ using type_at_index_t = typename type_at_index::type; namespace details { + +template +consteval std::size_t index_of_impl() +{ + return Size; +} /** * @brief Recursively searches Types for Type. * @tparam Index Iteration index for Types. Must be set to 0. @@ -201,21 +207,17 @@ namespace details * @tparam Types list to search in. * @return The index of Type in Types, or sizeof...(Types) if Type is not in the list. */ -template -constexpr std::size_t index_of_impl() +template +consteval std::size_t index_of_impl() { - if constexpr (Index < sizeof...(Types)) { - if constexpr (std::is_same_v>) { - return Index; - } - else { - return index_of_impl(); - } + if constexpr (std::is_same_v) { + return Size - sizeof...(Types) - 1; } else { - return Index; + return index_of_impl(); } } + } // namespace details /** @@ -224,8 +226,9 @@ constexpr std::size_t index_of_impl() * @tparam Types A list of types. */ template -struct is_type_in_list : std::conditional_t<(details::index_of_impl<0, Type, Types...>() < sizeof...(Types)), - std::true_type, std::false_type> { +struct is_type_in_list + : std::conditional_t<(details::index_of_impl() < sizeof...(Types)), + std::true_type, std::false_type> { }; /** @@ -244,8 +247,8 @@ constexpr bool is_type_in_list_v = is_type_in_list::value; */ template struct index_of_type { + static constexpr std::size_t value = details::index_of_impl(); static_assert(is_type_in_list_v, "Type is not contained in given list."); - static constexpr std::size_t value = details::index_of_impl<0, Type, Types...>(); }; /** From 42858500963b2ad665369363bcb68912a0129b26 Mon Sep 17 00:00:00 2001 From: reneSchm <49305466+reneSchm@users.noreply.github.com> Date: Mon, 12 Jan 2026 18:28:24 +0100 Subject: [PATCH 2/5] update docstring --- cpp/memilio/utils/metaprogramming.h | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/cpp/memilio/utils/metaprogramming.h b/cpp/memilio/utils/metaprogramming.h index 873e4701bf..72a0d71c63 100644 --- a/cpp/memilio/utils/metaprogramming.h +++ b/cpp/memilio/utils/metaprogramming.h @@ -195,21 +195,26 @@ using type_at_index_t = typename type_at_index::type; namespace details { -template -consteval std::size_t index_of_impl() -{ - return Size; -} /** - * @brief Recursively searches Types for Type. - * @tparam Index Iteration index for Types. Must be set to 0. + * @brief Recursively searches (TypeHead, Types...) for Type. + * @tparam Size Total size of the list to search. * @tparam Type to search. - * @tparam Types list to search in. - * @return The index of Type in Types, or sizeof...(Types) if Type is not in the list. + * @tparam TypesHead, Types The list to search in. May be empty. + * @return The index of Type in the list (TypeHead, Types...), or the size of the list if Type is not in it. + * @{ */ +template +constexpr std::size_t index_of_impl() +{ + // this works both as an overload for empty lists as well as a "not found" + return Size; +} template -consteval std::size_t index_of_impl() +constexpr std::size_t index_of_impl() { + // check if the type matches, otherwise call itself, omitting TypesHead + // this is significantly cheaper to compile compared to using an index and carrying the entire list, + // as that needs additional work for looking up "Types[Index]", e.g. through type_at_index if constexpr (std::is_same_v) { return Size - sizeof...(Types) - 1; } @@ -217,6 +222,7 @@ consteval std::size_t index_of_impl() return index_of_impl(); } } +/** @} */ } // namespace details From 727d82aa5ef48fdad7578a586fa7b9081d98aec9 Mon Sep 17 00:00:00 2001 From: reneSchm <49305466+reneSchm@users.noreply.github.com> Date: Tue, 13 Jan 2026 09:38:32 +0100 Subject: [PATCH 3/5] use slightly faster type_at_index implementation --- cpp/memilio/utils/metaprogramming.h | 41 ++++++++++++++++++++++------- 1 file changed, 31 insertions(+), 10 deletions(-) diff --git a/cpp/memilio/utils/metaprogramming.h b/cpp/memilio/utils/metaprogramming.h index 72a0d71c63..942d375ee7 100644 --- a/cpp/memilio/utils/metaprogramming.h +++ b/cpp/memilio/utils/metaprogramming.h @@ -173,15 +173,36 @@ using not_copyable_if = std::conditional; template using not_copyable_if_t = typename not_copyable_if::type; +namespace details +{ + +/** + * @brief Get the type at position Index of list (Head, Tail...). + * @tparam Index The index of the type to get. + * @tparam Head, Tail The list to search in. May be empty. + * @{ + */ +template +struct type_at_index_impl { + using type = typename type_at_index_impl::type; +}; +template +struct type_at_index_impl<0, Head, Tail...> { + using type = Head; +}; +/** @} */ + +} // namespace details + /** - * Finds the type at the Index-th position in the list Types. + * @brief Finds the type at the Index-th position in the list Types. * @tparam Index An index in `[0, sizeof...(Types))`. * @tparam Types A list of types. */ template struct type_at_index { static_assert(Index < sizeof...(Types), "Index is too large for the list Types."); - using type = typename std::tuple_element>::type; + using type = typename details::type_at_index_impl::type; }; /** @@ -196,10 +217,10 @@ namespace details { /** - * @brief Recursively searches (TypeHead, Types...) for Type. + * @brief Recursively searches the list (Head, Tail...) for Type. * @tparam Size Total size of the list to search. * @tparam Type to search. - * @tparam TypesHead, Types The list to search in. May be empty. + * @tparam Head, Tail The list to search in. May be empty. * @return The index of Type in the list (TypeHead, Types...), or the size of the list if Type is not in it. * @{ */ @@ -209,17 +230,17 @@ constexpr std::size_t index_of_impl() // this works both as an overload for empty lists as well as a "not found" return Size; } -template +template constexpr std::size_t index_of_impl() { // check if the type matches, otherwise call itself, omitting TypesHead // this is significantly cheaper to compile compared to using an index and carrying the entire list, // as that needs additional work for looking up "Types[Index]", e.g. through type_at_index - if constexpr (std::is_same_v) { - return Size - sizeof...(Types) - 1; + if constexpr (std::is_same_v) { + return Size - sizeof...(Tail) - 1; } else { - return index_of_impl(); + return index_of_impl(); } } /** @} */ @@ -246,7 +267,7 @@ template constexpr bool is_type_in_list_v = is_type_in_list::value; /** - * Finds the index of a Type in the list Types. + * @brief Finds the index of a Type in the list Types. * If Type does not have a unique index in Types, only the smallest is given as value. * @tparam Type A type contained in Types. * @tparam Types A list of types. @@ -254,7 +275,7 @@ constexpr bool is_type_in_list_v = is_type_in_list::value; template struct index_of_type { static constexpr std::size_t value = details::index_of_impl(); - static_assert(is_type_in_list_v, "Type is not contained in given list."); + static_assert(value < sizeof...(Types), "Type is not contained in given list."); }; /** From 87552ec2c4caaa9cff0e1aa370725bf8d53a9e90 Mon Sep 17 00:00:00 2001 From: reneSchm <49305466+reneSchm@users.noreply.github.com> Date: Wed, 14 Jan 2026 09:39:21 +0100 Subject: [PATCH 4/5] [ci skip] Update cpp/memilio/utils/metaprogramming.h Co-authored-by: Henrik Zunker <69154294+HenrZu@users.noreply.github.com> --- cpp/memilio/utils/metaprogramming.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/memilio/utils/metaprogramming.h b/cpp/memilio/utils/metaprogramming.h index 942d375ee7..eac03d75a9 100644 --- a/cpp/memilio/utils/metaprogramming.h +++ b/cpp/memilio/utils/metaprogramming.h @@ -221,7 +221,7 @@ namespace details * @tparam Size Total size of the list to search. * @tparam Type to search. * @tparam Head, Tail The list to search in. May be empty. - * @return The index of Type in the list (TypeHead, Types...), or the size of the list if Type is not in it. + * @return The index of Type in the list (Head, Tail...), or the size of the list if Type is not in it. * @{ */ template From 32da3e7dfc12d745cc54224b8be3ddbb7ca5233b Mon Sep 17 00:00:00 2001 From: reneSchm <49305466+reneSchm@users.noreply.github.com> Date: Wed, 14 Jan 2026 09:39:39 +0100 Subject: [PATCH 5/5] [ci skip] Update cpp/memilio/utils/metaprogramming.h Co-authored-by: Henrik Zunker <69154294+HenrZu@users.noreply.github.com> --- cpp/memilio/utils/metaprogramming.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cpp/memilio/utils/metaprogramming.h b/cpp/memilio/utils/metaprogramming.h index eac03d75a9..33068d5f2c 100644 --- a/cpp/memilio/utils/metaprogramming.h +++ b/cpp/memilio/utils/metaprogramming.h @@ -233,7 +233,7 @@ constexpr std::size_t index_of_impl() template constexpr std::size_t index_of_impl() { - // check if the type matches, otherwise call itself, omitting TypesHead + // check if the type matches, otherwise call itself, omitting Head // this is significantly cheaper to compile compared to using an index and carrying the entire list, // as that needs additional work for looking up "Types[Index]", e.g. through type_at_index if constexpr (std::is_same_v) {