From 8f02514390dd3cbd3b49c0cc628bdb709a840db2 Mon Sep 17 00:00:00 2001 From: John Wellbelove Date: Sat, 21 Feb 2026 09:02:14 +0000 Subject: [PATCH] Added etl::index_sequence_cat, etl::index_sequence_pop_front, etl::index_sequence_pop_back, etl::index_sequence_at --- include/etl/utility.h | 155 ++++++++++++++++++++++++++++++++++-------- test/test_utility.cpp | 61 ++++++++++++++++- 2 files changed, 185 insertions(+), 31 deletions(-) diff --git a/include/etl/utility.h b/include/etl/utility.h index ecdfe3ac..6e997f16 100644 --- a/include/etl/utility.h +++ b/include/etl/utility.h @@ -623,36 +623,6 @@ namespace etl template using index_sequence_for = typename etl::make_index_sequence_for; - //************************************ - /// Pushes an index to the front of an index_sequence. - //************************************ - template - struct index_sequence_push_front; - - template - struct index_sequence_push_front, Index> - { - using type = etl::index_sequence; - }; - - template - using index_sequence_push_front_t = typename index_sequence_push_front::type; - - //************************************ - /// Pushes an index to the back of an index_sequence. - //************************************ - template - struct index_sequence_push_back; - - template - struct index_sequence_push_back, Index> - { - using type = etl::index_sequence; - }; - - template - using index_sequence_push_back_t = typename index_sequence_push_back::type; - //************************************ /// Concatenates two index_sequences. //************************************ @@ -667,6 +637,131 @@ namespace etl template using index_sequence_cat_t = typename index_sequence_cat::type; + + //************************************ + /// Pushes an index to the front of an index_sequence. + //************************************ + template + struct index_sequence_push_front; + + template + struct index_sequence_push_front, Index> + { + // Adds the new index to the front of the sequence. + using type = etl::index_sequence; + }; + + template + using index_sequence_push_front_t = typename index_sequence_push_front::type; + + //************************************ + /// Pop an index from the front of an index_sequence. + //************************************ + template + struct index_sequence_pop_front; + + template <> + struct index_sequence_pop_front> + { + using type = etl::index_sequence<>; + }; + + template + struct index_sequence_pop_front> + { + // Removes the front index by declaring the type to be the tail of the sequence. + using type = etl::index_sequence; + }; + + template + using index_sequence_pop_front_t = typename index_sequence_pop_front::type; + + //************************************ + /// Pushes an index to the back of an index_sequence. + //************************************ + template + struct index_sequence_push_back; + + template + struct index_sequence_push_back, Index> + { + // Adds the new index to the back of the sequence by concatenating the new index with the sequence. + using type = etl::index_sequence; + }; + + template + using index_sequence_push_back_t = typename index_sequence_push_back::type; + + //************************************ + /// Pop an index from the back of an index_sequence. + //************************************ + template + struct index_sequence_pop_back; + + // Pop back of and empty sequence is an empty sequence. + template <> + struct index_sequence_pop_back> + { + using type = etl::index_sequence<>; + }; + + // Pop back of a single element sequence is an empty sequence. + // The single element is never added to the result, so is effectively removed. + // This is the terminating specialisation for the general case. + template + struct index_sequence_pop_back> + { + using type = etl::index_sequence<>; + }; + + // Multi element sequence. Pop back is the front element concatenated with the pop back of the tail. + template + struct index_sequence_pop_back> + { + // Removes the last index by concatenating the front index with the pop back of the tail. + // The last index is never added to the result, so is effectively removed. + using type = etl::index_sequence_cat_t, + typename index_sequence_pop_back>::type>; + }; + + template + using index_sequence_pop_back_t = typename index_sequence_pop_back::type; + + //************************************ + /// Gets the index at the Nth position in an index_sequence. + //************************************ + template + struct index_sequence_at; + + template + struct index_sequence_at, Nth> + { + template + struct dependent_false : etl::false_type {}; + + static_assert(dependent_false::value, "Nth out of range for index_sequence_at"); + }; + + // When Nth is 0, the index at the Nth position is the front index of the sequence. + template + struct index_sequence_at, 0> + { + static constexpr size_t value = Index; + }; + + // When Nth is greater than 0, recurse with the tail of the sequence and Nth - 1. + template + struct index_sequence_at, Nth> + { + static_assert(Nth < sizeof...(Indices) + 1U, "Nth out of range for index_sequence_at"); + + static constexpr size_t value = index_sequence_at, Nth - 1U>::value; + }; + +#if ETL_USING_CPP17 + template + inline constexpr size_t index_sequence_at_v = index_sequence_at::value; +#endif #endif //*************************************************************************** diff --git a/test/test_utility.cpp b/test/test_utility.cpp index 322cd97d..f966f7f2 100644 --- a/test/test_utility.cpp +++ b/test/test_utility.cpp @@ -936,7 +936,21 @@ namespace using result0 = etl::index_sequence_push_front_t; using result1 = etl::index_sequence_push_front_t; using expect0 = etl::index_sequence<5U>; - using expect1 = etl::index_sequence<1U, 2U, 0U>; + using expect1 = etl::index_sequence<0U, 1U, 2U>; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + } + + //********************************* + TEST(test_index_sequence_pop_front_matches_expected) + { + using seq0 = etl::index_sequence<>; + using seq1 = etl::index_sequence<1U, 2U>; + using result0 = etl::index_sequence_pop_front_t; + using result1 = etl::index_sequence_pop_front_t; + using expect0 = etl::index_sequence<>; + using expect1 = etl::index_sequence<2U>; CHECK_TRUE((std::is_same::value)); CHECK_TRUE((std::is_same::value)); @@ -956,6 +970,20 @@ namespace CHECK_TRUE((std::is_same::value)); } + //********************************* + TEST(test_index_sequence_pop_back_matches_expected) + { + using seq0 = etl::index_sequence<>; + using seq1 = etl::index_sequence<1U, 2U>; + using result0 = etl::index_sequence_pop_back_t; + using result1 = etl::index_sequence_pop_back_t; + using expect0 = etl::index_sequence<>; + using expect1 = etl::index_sequence<1U>; + + CHECK_TRUE((std::is_same::value)); + CHECK_TRUE((std::is_same::value)); + } + //********************************* TEST(test_index_sequence_cat_matches_expected) { @@ -970,5 +998,36 @@ namespace CHECK_TRUE((std::is_same::value)); CHECK_TRUE((std::is_same::value)); } + + //********************************* + TEST(test_index_sequence_at_matches_expected) + { + using seq0 = etl::index_sequence<>; + using seq1 = etl::index_sequence<1U, 2U, 3U>; + //using result0 = etl::index_sequence_at; // This should fail to compile as seq0 is empty + //auto ignore0 = result0; // Uses result0 + size_t result1a = etl::index_sequence_at::value; + size_t result1b = etl::index_sequence_at::value; + size_t result1c = etl::index_sequence_at::value; + //size_t result1d = etl::index_sequence_at::value; // This should fail to compile as seq1 only has 3 elements + //auto ignore1d = result1d; // Uses result1d + size_t expect1a = 1U; + size_t expect1b = 2U; + size_t expect1c = 3U; + + CHECK_EQUAL(expect1a, result1a); + CHECK_EQUAL(expect1b, result1b); + CHECK_EQUAL(expect1c, result1c); + +#if ETL_USING_CPP17 + size_t result1e = etl::index_sequence_at_v; + size_t result1f = etl::index_sequence_at_v; + size_t result1g = etl::index_sequence_at_v; + + CHECK_EQUAL(expect1a, result1e); + CHECK_EQUAL(expect1b, result1f); + CHECK_EQUAL(expect1c, result1g); +#endif + } } }