/****************************************************************************** The MIT License(MIT) Embedded Template Library. https://github.com/ETLCPP/etl https://www.etlcpp.com Copyright(c) 2026 BMW AG Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files(the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and / or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions : The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ******************************************************************************/ #include "unit_test_framework.h" #include "etl/algorithm.h" #include "etl/array.h" #include "etl/ranges.h" #include "etl/vector.h" #include #include #include #include #include // Issue #1391: include when available to verify etl::operator| // does not conflict with std::ranges::operator|. #if ETL_USING_STL && ETL_USING_CPP20 && defined(__has_include) #if __has_include() #include #endif #endif #if ETL_USING_CPP17 // C++03 does not support move semantics as used in the ranges library #if !defined(ETL_FORCE_TEST_CPP03_IMPLEMENTATION) namespace { class MoveInt { public: MoveInt(int v) : _v{v} { } MoveInt(const MoveInt& other) : _v{other._v} { } MoveInt& operator=(const MoveInt& other) { _v = other._v; return *this; } MoveInt(MoveInt&& other) : _v{other._v} { other._v = 0; } MoveInt& operator=(MoveInt&& other) { _v = other._v; other._v = 0; return *this; } int get() const { return _v; } bool operator==(const MoveInt& other) const { return _v == other._v; } bool operator!=(const MoveInt& other) const { return !(*this == other); } private: int _v; }; } // namespace namespace std { template < typename Container, etl::enable_if_t< etl::is_base_of_v, Container> || etl::is_base_of_v, Container> || etl::is_base_of_v, Container>, int> = 0> std::basic_ostream& operator<<(std::basic_ostream& s, const Container& v) { auto it = v.cbegin(); auto e = v.cend(); bool first = true; for (; it != e; ++it) { if (!first) { s << " "; } s << *it; first = false; } return s; } std::ostringstream& operator<<(std::ostringstream& s, const etl::ivector& v) { auto it = v.cbegin(); auto e = v.cend(); bool first = true; for (; it != e; ++it) { if (!first) { s << " "; } s << it->get(); first = false; } return s; } template std::ostringstream& operator<<(std::ostringstream& s, const etl::ranges::range_iterator& v) { auto value{v.get()}; s << value; return s; } } // namespace std namespace { #include "etl/private/diagnostic_null_dereference_push.h" SUITE(test_ranges) { //************************************************************************* // Iterators. //************************************************************************* TEST(test_ranges_begin) { etl::vector v_in{3, 2, 1}; auto it = etl::ranges::begin(v_in); CHECK_EQUAL(*it, 3); } TEST(test_ranges_end) { etl::vector v_in{3, 2, 1}; auto it = etl::ranges::end(v_in); CHECK_EQUAL(it, ETL_OR_STD::end(v_in)); } TEST(test_ranges_cbegin) { etl::vector v_in{3, 2, 1}; auto it = etl::ranges::cbegin(v_in); CHECK_EQUAL(*it, 3); } TEST(test_ranges_cend) { etl::vector v_in{3, 2, 1}; auto it = etl::ranges::cend(v_in); CHECK_EQUAL(it, ETL_OR_STD::cend(v_in)); } TEST(test_ranges_rbegin) { etl::vector v_in{3, 2, 1}; auto it = etl::ranges::rbegin(v_in); CHECK_EQUAL(*it, 1); } TEST(test_ranges_rend) { etl::vector v_in{3, 2, 1}; auto it = etl::ranges::rend(v_in); CHECK_EQUAL(&(*it), &(*ETL_OR_STD::rend(v_in))); } TEST(test_ranges_crbegin) { etl::vector v_in{3, 2, 1}; auto it = etl::ranges::crbegin(v_in); CHECK_EQUAL(*it, 1); } TEST(test_ranges_crend) { etl::vector v_in{3, 2, 1}; auto it = etl::ranges::crend(v_in); CHECK(it == ETL_OR_STD::crend(v_in)); } TEST(test_ranges_size) { etl::vector v_in{11, 3, 2, 1}; CHECK_EQUAL(etl::ranges::size(v_in), 4); using size_type = decltype(etl::ranges::size(v_in)); static_assert(etl::is_signed::value == false, "Result of size must be unsigned"); } TEST(test_ranges_ssize) { etl::vector v_in{11, 3, 2, 1}; CHECK_EQUAL(etl::ranges::ssize(v_in), 4); using signed_type = decltype(etl::ranges::ssize(v_in)); using unsigned_type = decltype(etl::ranges::size(v_in)); static_assert(etl::is_signed::value, "Result of ssize must be signed"); static_assert(sizeof(signed_type) >= sizeof(unsigned_type), "Signed size type needs to be as wide as unsigned size type"); } TEST(test_ranges_empty) { etl::vector v_in0{11, 3, 2, 1}; etl::vector v_in1{}; CHECK_EQUAL(etl::ranges::empty(v_in0), false); CHECK_EQUAL(etl::ranges::empty(v_in1), true); } TEST(test_ranges_data) { etl::vector v_in{11, 3, 2, 1}; CHECK_EQUAL(*etl::ranges::data(v_in), 11); } TEST(test_ranges_cdata) { etl::vector v_in{11, 3, 2, 1}; CHECK_EQUAL(*etl::ranges::cdata(v_in), 11); } //************************************************************************* // Range primitives. //************************************************************************* TEST(test_ranges_iterator_t) { using range_type = etl::vector; static_assert(etl::is_same, int*>::value, "Bad iterator type from etl::ranges::iterator_t"); } TEST(test_ranges_const_iterator_t) { using range_type = etl::vector; static_assert(etl::is_same, const int*>::value, "Bad iterator type from etl::ranges::const_iterator_t"); } TEST(test_ranges_sentinel_t) { using range_type = etl::vector; static_assert(etl::is_same, int*>::value, "Bad sentinel type from etl::ranges::sentinel_t"); } TEST(test_ranges_const_sentinel_t) { using range_type = etl::vector; static_assert(etl::is_same, const int*>::value, "Bad sentinel type from etl::ranges::const_sentinel_t"); } TEST(test_ranges_range_size_t) { using range_type0 = int[10]; using range_type1 = etl::vector; using range_type2 = etl::ranges::empty_view; static_assert(etl::is_same, size_t>::value, "Bad size type from etl::ranges::range_size_t"); static_assert(etl::is_same, size_t>::value, "Bad size type from etl::ranges::range_size_t"); static_assert(etl::is_same, size_t>::value, "Bad size type from etl::ranges::range_size_t"); } TEST(test_ranges_range_difference_t) { using range_type0 = int[10]; using range_type1 = etl::vector; using range_type2 = etl::ranges::empty_view; static_assert(etl::is_same, ptrdiff_t>::value, "Bad size type from etl::ranges::range_difference_t"); static_assert(etl::is_same, ptrdiff_t>::value, "Bad size type from etl::ranges::range_difference_t"); static_assert(etl::is_same, ptrdiff_t>::value, "Bad size type from etl::ranges::range_difference_t"); } TEST(test_ranges_range_value_t) { using range_type0 = int[10]; using range_type1 = etl::vector; using range_type2 = etl::ranges::empty_view; static_assert(etl::is_same, int>::value, "Bad size type from etl::ranges::range_value_t"); static_assert(etl::is_same, int>::value, "Bad size type from etl::ranges::range_value_t"); static_assert(etl::is_same, int>::value, "Bad size type from etl::ranges::range_value_t"); } TEST(test_ranges_subrange) { etl::vector v{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto sr = etl::ranges::subrange{v.begin(), v.end()}; CHECK_EQUAL(sr.begin(), v.begin()); CHECK_EQUAL(sr.end(), v.end()); CHECK_EQUAL(sr.empty(), false); CHECK_EQUAL(sr.size(), 10); sr.advance(1); CHECK_EQUAL(sr.size(), 9); CHECK_EQUAL(sr[0], 1); sr.advance(2); CHECK_EQUAL(sr.size(), 7); CHECK_EQUAL(sr[0], 3); CHECK_EQUAL(sr.next().size(), 6); CHECK_EQUAL(sr.next()[0], 4); CHECK_EQUAL(sr.next(1).size(), 6); CHECK_EQUAL(sr.next(1)[0], 4); CHECK_EQUAL(sr.next(2).size(), 5); CHECK_EQUAL(sr.next(2)[0], 5); CHECK_EQUAL(sr.prev().size(), 8); CHECK_EQUAL(sr.prev()[0], 2); CHECK_EQUAL(sr.prev(1).size(), 8); CHECK_EQUAL(sr.prev(1)[0], 2); CHECK_EQUAL(sr.prev(2).size(), 9); CHECK_EQUAL(sr.prev(2)[0], 1); } //************************************************************************* // Range factories. //************************************************************************* TEST(test_ranges_empty_view) { auto ev = etl::ranges::empty_view{}; CHECK_EQUAL(ev.begin(), nullptr); CHECK_EQUAL(ev.end(), nullptr); CHECK_EQUAL(ev.data(), nullptr); CHECK_EQUAL(ev.size(), 0); CHECK_EQUAL(ev.empty(), true); } TEST(test_ranges_views_empty) { auto e = etl::ranges::views::empty; CHECK_EQUAL(e.begin(), nullptr); CHECK_EQUAL(e.end(), nullptr); CHECK_EQUAL(e.data(), nullptr); CHECK_EQUAL(e.size(), 0); CHECK_EQUAL(e.empty(), true); } TEST(test_ranges_single_view) { auto s0 = etl::ranges::single_view(12); CHECK_EQUAL(s0.size(), 1); auto s = etl::ranges::single_view(23); CHECK_EQUAL(*s.begin(), 23); CHECK_EQUAL(s.end(), s.begin() + 1); CHECK_EQUAL(*s.data(), 23); CHECK_EQUAL(s.size(), 1); CHECK_EQUAL(s.empty(), false); *s.begin() = 45; CHECK_EQUAL(*s.data(), 45); CHECK_EQUAL(*s.begin(), 45); } TEST(test_ranges_views_single) { auto s = etl::ranges::views::single(23); CHECK_EQUAL(*s.begin(), 23); CHECK_EQUAL(s.end(), s.begin() + 1); CHECK_EQUAL(*s.data(), 23); CHECK_EQUAL(s.size(), 1); CHECK_EQUAL(s.empty(), false); *s.begin() = 45; CHECK_EQUAL(*s.data(), 45); CHECK_EQUAL(*s.begin(), 45); } TEST(test_ranges_iota_view) { auto iv = etl::ranges::iota_view(1, 7); int compare = 1; for (auto i : iv) { CHECK_EQUAL(i, compare); ++compare; } CHECK_EQUAL(*iv.begin(), 1); CHECK_EQUAL(iv.end(), iv.begin() + 6); CHECK_EQUAL(iv.size(), 6); CHECK_EQUAL(iv.empty(), false); CHECK_EQUAL(iv[4], 5); auto iv2 = etl::ranges::iota_view(3); CHECK_EQUAL(iv2[0], 3); CHECK_EQUAL(iv2[1], 4); CHECK_EQUAL(iv2[2], 5); CHECK_EQUAL(iv2[3], 6); CHECK_EQUAL(iv2[4], 7); auto iv3 = etl::ranges::iota_view(); CHECK_EQUAL(iv3.size(), 0); CHECK_EQUAL(iv3.end(), iv3.begin()); CHECK_EQUAL(iv3.empty(), true); } TEST(test_ranges_views_iota) { auto iv = etl::ranges::views::iota(1, 7); CHECK_EQUAL(*iv.begin(), 1); CHECK_EQUAL(iv.end(), iv.begin() + 6); CHECK_EQUAL(iv.size(), 6); CHECK_EQUAL(iv.empty(), false); CHECK_EQUAL(iv[4], 5); } TEST(test_ranges_iota_view_pipe_take) { auto iv = etl::ranges::iota_view(3) | etl::views::take(5); auto i = iv.begin(); auto j = i; CHECK_EQUAL(*i, 3); i++; CHECK_EQUAL(*i, 4); ++i; CHECK_EQUAL(*i, 5); CHECK_EQUAL(i - j, 2); CHECK_EQUAL(iv.size(), 5); CHECK_EQUAL(iv.front(), 3); CHECK_EQUAL(iv.back(), 7); CHECK_EQUAL(iv[0], 3); CHECK_EQUAL(iv[1], 4); CHECK_EQUAL(iv[2], 5); CHECK_EQUAL(iv[3], 6); CHECK_EQUAL(iv[4], 7); } TEST(test_ranges_repeat_view) { // bounded auto iv = etl::ranges::repeat_view(1, 7); for (auto i : iv) { CHECK_EQUAL(i, 1); } CHECK_EQUAL(*iv.begin(), 1); CHECK_EQUAL(iv.end(), iv.begin() + 7); CHECK_EQUAL(iv.size(), 7); CHECK_EQUAL(iv.empty(), false); CHECK_EQUAL(iv[4], 1); // unbounded auto iv2 = etl::ranges::repeat_view(3); CHECK_EQUAL(iv2[0], 3); CHECK_EQUAL(iv2[1], 3); CHECK_EQUAL(iv2[2], 3); CHECK_EQUAL(iv2[3], 3); CHECK_EQUAL(iv2[4], 3); auto iv3 = etl::ranges::repeat_view(); CHECK_EQUAL(iv3.size(), 0); CHECK_EQUAL(iv3.end(), iv3.begin()); CHECK_EQUAL(iv3.empty(), true); } TEST(test_ranges_views_repeat) { auto iv = etl::ranges::views::repeat(1, 7); CHECK_EQUAL(*iv.begin(), 1); CHECK_EQUAL(iv.end(), iv.begin() + 7); CHECK_EQUAL(iv.size(), 7); CHECK_EQUAL(iv.empty(), false); CHECK_EQUAL(iv[4], 1); } TEST(test_ranges_repeat_view_pipe_take) { auto iv = etl::ranges::repeat_view(3) | etl::views::take(5); auto i = iv.begin(); CHECK_EQUAL(*i, 3); i++; CHECK_EQUAL(*i, 3); ++i; CHECK_EQUAL(*i, 3); CHECK_EQUAL(iv.size(), 5); CHECK_EQUAL(iv.front(), 3); CHECK_EQUAL(iv.back(), 3); CHECK_EQUAL(iv[0], 3); CHECK_EQUAL(iv[1], 3); CHECK_EQUAL(iv[2], 3); CHECK_EQUAL(iv[3], 3); CHECK_EQUAL(iv[4], 3); } TEST(test_ranges_repeat_view_pipe_take_bounded) { auto iv = etl::ranges::repeat_view(3, 30) | etl::views::take(5); auto i = iv.begin(); CHECK_EQUAL(*i, 3); i++; CHECK_EQUAL(*i, 3); ++i; CHECK_EQUAL(*i, 3); CHECK_EQUAL(iv.size(), 5); CHECK_EQUAL(iv.front(), 3); CHECK_EQUAL(iv.back(), 3); CHECK_EQUAL(iv[0], 3); CHECK_EQUAL(iv[1], 3); CHECK_EQUAL(iv[2], 3); CHECK_EQUAL(iv[3], 3); CHECK_EQUAL(iv[4], 3); } TEST(test_ranges_repeat_view_pipe_take_bounded_limited) { auto iv = etl::ranges::repeat_view(3, 4) | etl::views::take(5); auto i = iv.begin(); CHECK_EQUAL(*i, 3); i++; CHECK_EQUAL(*i, 3); ++i; CHECK_EQUAL(*i, 3); CHECK_EQUAL(iv.size(), 4); CHECK_EQUAL(iv.front(), 3); CHECK_EQUAL(iv.back(), 3); CHECK_EQUAL(iv[0], 3); CHECK_EQUAL(iv[1], 3); CHECK_EQUAL(iv[2], 3); CHECK_EQUAL(iv[3], 3); } //************************************************************************* // Range adaptors //************************************************************************* TEST(test_ranges_iterate_c_array) { auto even = [](int i) -> bool { return 0 == i % 2; }; int v_in[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 2, 4, 6, 8}; for (int i : etl::views::filter(v_in, even)) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_iterate_plain) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 2, 4, 6, 8}; for (int i : etl::views::filter(v_in, even)) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_iterate_pipe) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 2, 4, 6, 8}; for (int i : v_in | etl::views::filter(even)) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_drop_functional) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{2, 3, 4, 5, 6, 7, 8, 9}; auto rv = etl::views::drop(v_in, 2); CHECK_EQUAL(etl::views::all(v_out_expected), rv); CHECK_EQUAL(rv.base().base(), v_in); CHECK_EQUAL(*rv.begin(), 2); CHECK_EQUAL(rv.size(), 8); CHECK_EQUAL(*rv.cbegin(), 2); CHECK_EQUAL(rv.empty(), false); CHECK_EQUAL(rv, true); CHECK_EQUAL(rv.front(), 2); CHECK_EQUAL(rv.back(), 9); CHECK_EQUAL(rv[7], 9); rv[1] = 33; CHECK_EQUAL(rv[1], 33); CHECK_EQUAL(v_in[3], 33); v_in[2] = 44; CHECK_EQUAL(rv[0], 44); CHECK_EQUAL(v_in[2], 44); } TEST(test_ranges_iterate_pipe_drop) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{2, 3, 4, 5, 6, 7, 8, 9}; auto rv = v_in | etl::views::drop(2); for (int i : rv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(rv.base().base(), v_in); CHECK_EQUAL(*rv.begin(), 2); CHECK_EQUAL(rv.size(), 8); CHECK_EQUAL(*rv.cbegin(), 2); CHECK_EQUAL(rv.empty(), false); CHECK_EQUAL(rv, true); CHECK_EQUAL(rv.front(), 2); CHECK_EQUAL(rv.back(), 9); CHECK_EQUAL(rv[7], 9); rv[1] = 33; CHECK_EQUAL(rv[1], 33); CHECK_EQUAL(v_in[3], 33); v_in[2] = 44; CHECK_EQUAL(rv[0], 44); CHECK_EQUAL(v_in[2], 44); } TEST(test_ranges_iterate_pipe_drop_out_of_bounds) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{}; auto rv = v_in | etl::views::drop(12); for (int i : rv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(rv.size(), 0); } TEST(test_ranges_iterate_pipe_twice) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{2, 4, 6, 8}; for (int i : v_in | etl::views::filter(even) | etl::views::drop(1)) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_iterate_pipe_drop_while) { auto below_three = [](int i) -> bool { return i < 3; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{3, 4, 5, 6, 7, 8, 9}; auto rv = v_in | etl::views::drop_while(below_three); for (int i : rv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(rv.base().base(), v_in); CHECK_EQUAL(*rv.begin(), 3); CHECK_EQUAL(rv.size(), 7); CHECK_EQUAL(*rv.cbegin(), 3); CHECK_EQUAL(rv.empty(), false); CHECK_EQUAL(rv, true); CHECK_EQUAL(rv.front(), 3); CHECK_EQUAL(rv.back(), 9); CHECK_EQUAL(rv[6], 9); } TEST(test_ranges_take_functional) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out_expected{0, 1, 2, 3}; auto rv = etl::views::take(v_in, 4); CHECK_EQUAL(etl::views::all(v_out_expected), rv); CHECK_EQUAL(rv.base().base(), v_in); CHECK_EQUAL(*rv.begin(), 0); CHECK_EQUAL(rv.size(), 4); CHECK_EQUAL(*rv.cbegin(), 0); CHECK_EQUAL(rv.empty(), false); CHECK_EQUAL(rv, true); CHECK_EQUAL(rv.front(), 0); CHECK_EQUAL(rv.back(), 3); CHECK_EQUAL(rv[2], 2); rv[2] = 33; CHECK_EQUAL(rv[2], 33); CHECK_EQUAL(v_in[2], 33); v_in[3] = 44; CHECK_EQUAL(rv[3], 44); CHECK_EQUAL(v_in[3], 44); } TEST(test_ranges_iterate_pipe_take) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3}; auto rv = v_in | etl::views::take(4); for (int i : rv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(rv.base().base(), v_in); CHECK_EQUAL(*rv.begin(), 0); CHECK_EQUAL(rv.size(), 4); CHECK_EQUAL(*rv.cbegin(), 0); CHECK_EQUAL(rv.empty(), false); CHECK_EQUAL(rv, true); CHECK_EQUAL(rv.front(), 0); CHECK_EQUAL(rv.back(), 3); CHECK_EQUAL(rv[2], 2); rv[2] = 33; CHECK_EQUAL(rv[2], 33); CHECK_EQUAL(v_in[2], 33); v_in[3] = 44; CHECK_EQUAL(rv[3], 44); CHECK_EQUAL(v_in[3], 44); } TEST(test_ranges_iterate_pipe_take_while) { auto below_three = [](int i) -> bool { return i < 3; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2}; auto rv = v_in | etl::views::take_while(below_three); for (int i : rv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(rv.base().base(), v_in); CHECK_EQUAL(*rv.begin(), 0); CHECK_EQUAL(rv.size(), 3); CHECK_EQUAL(*rv.cbegin(), 0); CHECK_EQUAL(rv.empty(), false); CHECK_EQUAL(rv, true); CHECK_EQUAL(rv.front(), 0); CHECK_EQUAL(rv.back(), 2); CHECK_EQUAL(rv[2], 2); } TEST(test_ranges_reverse_view_functional) { etl::vector v_in{0, 1, 2, 3, 4}; etl::vector v_out; etl::vector v_out_expected{4, 3, 2, 1, 0}; auto rv = etl::ranges::reverse_view(v_in); for (int i : rv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(rv.base().base(), v_in); CHECK_EQUAL(*rv.begin(), 4); CHECK_EQUAL(rv.size(), 5); CHECK_EQUAL(*rv.cbegin(), 4); CHECK_EQUAL(rv.empty(), false); CHECK_EQUAL(rv, true); CHECK_EQUAL(rv.front(), 4); CHECK_EQUAL(rv.back(), 0); CHECK_EQUAL(rv[2], 2); rv[0] = 22; CHECK_EQUAL(rv[0], 22); CHECK_EQUAL(v_in[4], 22); v_in[0] = 11; CHECK_EQUAL(rv.back(), 11); CHECK_EQUAL(rv[4], 11); } TEST(test_ranges_iterate_pipe_reverse) { etl::vector v_in{0, 1, 2, 3, 4}; etl::vector v_out; etl::vector v_out_expected{4, 3, 2, 1, 0}; auto rv = v_in | etl::views::reverse; for (int i : rv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(rv.base().base(), v_in); CHECK_EQUAL(*rv.begin(), 4); CHECK_EQUAL(rv.size(), 5); CHECK_EQUAL(rv.front(), 4); CHECK_EQUAL(rv.back(), 0); } TEST(test_ranges_iterate_pipe_reverse_reverse) { etl::vector v_in{0, 1, 2, 3, 4}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4}; auto rv = v_in | etl::views::reverse | etl::views::reverse; for (int i : rv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(rv.base(), v_in); CHECK_EQUAL(*rv.begin(), 0); CHECK_EQUAL(rv.size(), 5); CHECK_EQUAL(rv.front(), 0); CHECK_EQUAL(rv.back(), 4); } TEST(test_ranges_iterate_pipe_all) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; for (int i : v_in | etl::views::all) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_iterate_pipe_ref) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto r = v_in | etl::views::ref(); for (int i : r) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); v_in[9] = 99; CHECK_EQUAL(r[9], 99); CHECK_EQUAL(r.base(), v_in); CHECK_EQUAL(*r.begin(), 0); CHECK_EQUAL(r.end(), r.begin() + 10); CHECK_EQUAL(r.empty(), false); CHECK_EQUAL(r.size(), 10); CHECK_EQUAL(r.data(), v_in.data()); } TEST(test_ranges_iterate_pipe_owning) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto r = v_in | etl::views::owning(); for (int i : r) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(0, v_in.size()); etl::ranges::owning_view> ov2; CHECK_NOT_EQUAL(r.base(), v_in); CHECK_EQUAL(*r.begin(), 0); CHECK_EQUAL(r.end(), r.begin() + 10); CHECK_EQUAL(r.empty(), false); CHECK_EQUAL(r.size(), 10); CHECK_NOT_EQUAL(r.data(), v_in.data()); // ov2 = r; // expected: compile error! ov2 = etl::move(r); } TEST(test_ranges_iterate_pipe_to) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out_expected{2, 4, 6, 8}; auto v_out = v_in | etl::views::filter(even) | etl::views::drop(1) | etl::ranges::to>(); CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_iterate_pipe_as_rvalue) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected_0{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; etl::vector v_out_expected_1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; for (auto&& i : v_in | etl::views::as_rvalue) { v_out.emplace_back(etl::move(i)); } CHECK_EQUAL(v_out_expected_0, v_in); CHECK_EQUAL(v_out_expected_1, v_out); } TEST(test_ranges_iterate_pipe_as_rvalue_functional) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected_0{0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; etl::vector v_out_expected_1{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; v_out = etl::views::as_rvalue(v_in) | etl::ranges::to>(); CHECK_EQUAL(v_out_expected_0, v_in); CHECK_EQUAL(v_out_expected_1, v_out); } TEST(test_ranges_as_const_view_functional) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto cv = etl::ranges::as_const_view(v_in); // Iterator type should be const_iterator using cv_reference = decltype(*cv.begin()); static_assert(etl::is_const_v>, "as_const_view iterator should dereference to const"); for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(cv.size(), 10u); CHECK_EQUAL(cv.empty(), false); CHECK_EQUAL(cv.front(), 0); CHECK_EQUAL(cv.back(), 9); } TEST(test_ranges_as_const_view_reflects_base_changes) { etl::vector v_in{0, 1, 2, 3, 4}; auto cv = etl::ranges::as_const_view(v_in); CHECK_EQUAL(cv.front(), 0); CHECK_EQUAL(cv.back(), 4); CHECK_EQUAL(cv.size(), 5u); v_in[0] = 99; v_in[4] = 77; CHECK_EQUAL(cv.front(), 99); CHECK_EQUAL(cv.back(), 77); } TEST(test_ranges_as_const_view_pipe) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto cv = v_in | etl::views::as_const(); using cv_reference = decltype(*cv.begin()); static_assert(etl::is_const_v>, "piped as_const view iterator should dereference to const"); for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(cv.size(), 10u); } TEST(test_ranges_views_as_const_functional) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto cv = etl::views::as_const(v_in); using cv_reference = decltype(*cv.begin()); static_assert(etl::is_const_v>, "views::as_const iterator should dereference to const"); for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_as_const_view_pipe_chained_with_take) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2}; auto cv = v_in | etl::views::as_const() | etl::views::take(3); for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_as_const_view_pipe_chained_with_drop) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{7, 8, 9}; auto cv = v_in | etl::views::as_const() | etl::views::drop(7); for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_as_const_view_pipe_chained_with_reverse) { etl::vector v_in{0, 1, 2, 3, 4}; etl::vector v_out; etl::vector v_out_expected{4, 3, 2, 1, 0}; auto cv = v_in | etl::views::as_const() | etl::views::reverse; for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_as_const_view_with_std_vector) { std::vector v_in{0, 1, 2, 3, 4}; std::vector v_out; std::vector v_out_expected{0, 1, 2, 3, 4}; auto cv = etl::ranges::as_const_view(v_in); using cv_reference = decltype(*cv.begin()); static_assert(etl::is_const_v>, "as_const_view over std::vector should dereference to const"); for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected.size(), v_out.size()); for (size_t idx = 0; idx < v_out_expected.size(); ++idx) { CHECK_EQUAL(v_out_expected[idx], v_out[idx]); } } //************************************************************************* /// cache_latest_view tests //************************************************************************* TEST(test_ranges_cache_latest_view_functional) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto cv = etl::ranges::cache_latest_view(v_in); for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(cv.size(), 10u); CHECK_EQUAL(cv.empty(), false); } TEST(test_ranges_cache_latest_view_caches_value) { int dereference_count = 0; auto counting_transform = [&dereference_count](int i) -> int { ++dereference_count; return i * 2; }; etl::vector v_in{1, 2, 3}; auto tv = v_in | etl::views::transform(counting_transform) | etl::views::cache_latest(); auto it = tv.begin(); // First dereference should evaluate dereference_count = 0; int val1 = *it; CHECK_EQUAL(1, dereference_count); CHECK_EQUAL(2, val1); // Second dereference of same position should use cache (no extra // transform call) int val2 = *it; CHECK_EQUAL(1, dereference_count); CHECK_EQUAL(2, val2); // Advance and dereference ++it; int val3 = *it; CHECK_EQUAL(2, dereference_count); CHECK_EQUAL(4, val3); } TEST(test_ranges_cache_latest_view_pipe) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto cv = v_in | etl::views::cache_latest(); for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_views_cache_latest_functional) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto cv = etl::views::cache_latest(v_in); for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_cache_latest_view_pipe_chained_with_take) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2}; auto cv = v_in | etl::views::cache_latest() | etl::views::take(3); for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_cache_latest_view_pipe_chained_with_transform) { auto square = [](int i) -> int { return i * i; }; etl::vector v_in{0, 1, 2, 3, 4}; etl::vector v_out; etl::vector v_out_expected{0, 1, 4, 9, 16}; auto cv = v_in | etl::views::transform(square) | etl::views::cache_latest(); for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_cache_latest_view_empty_range) { etl::vector v_in; auto cv = etl::ranges::cache_latest_view(v_in); CHECK_EQUAL(cv.empty(), true); CHECK_EQUAL(cv.size(), 0u); CHECK(cv.begin() == cv.end()); } TEST(test_ranges_cache_latest_view_with_std_vector) { std::vector v_in{0, 1, 2, 3, 4}; std::vector v_out; std::vector v_out_expected{0, 1, 2, 3, 4}; auto cv = etl::ranges::cache_latest_view(v_in); for (auto i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected.size(), v_out.size()); for (size_t idx = 0; idx < v_out_expected.size(); ++idx) { CHECK_EQUAL(v_out_expected[idx], v_out[idx]); } } TEST(test_ranges_iterate_transform) { auto square = [](int i) -> int { return i * i; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 4, 9, 16, 25, 36, 49, 64, 81}; for (int i : v_in | etl::views::transform(square)) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } //************************************************************************* /// transform_view tests //************************************************************************* TEST(test_ranges_transform_view_functional) { auto square = [](int i) -> int { return i * i; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 4, 9, 16, 25, 36, 49, 64, 81}; auto tv = etl::views::transform(v_in, square); for (auto i : tv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_transform_view_direct_construction) { auto negate = [](int i) -> int { return -i; }; etl::vector v_in{1, 2, 3, 4, 5}; etl::vector v_out; etl::vector v_out_expected{-1, -2, -3, -4, -5}; auto tv = etl::ranges::transform_view(etl::views::all(v_in), negate); for (auto i : tv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_transform_view_pipe) { auto triple = [](int i) -> int { return i * 3; }; etl::vector v_in{1, 2, 3, 4, 5}; etl::vector v_out; etl::vector v_out_expected{3, 6, 9, 12, 15}; auto tv = v_in | etl::views::transform(triple); for (auto i : tv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_transform_view_size) { auto identity = [](int i) -> int { return i; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto tv = v_in | etl::views::transform(identity); CHECK_EQUAL(10u, tv.size()); } TEST(test_ranges_transform_view_empty) { auto identity = [](int i) -> int { return i; }; etl::vector v_in; auto tv = v_in | etl::views::transform(identity); CHECK_EQUAL(true, tv.empty()); CHECK_EQUAL(0u, tv.size()); } TEST(test_ranges_transform_view_non_empty) { auto identity = [](int i) -> int { return i; }; etl::vector v_in{42}; auto tv = v_in | etl::views::transform(identity); CHECK_EQUAL(false, tv.empty()); CHECK_EQUAL(1u, tv.size()); } TEST(test_ranges_transform_view_front) { auto square = [](int i) -> int { return i * i; }; etl::vector v_in{3, 4, 5}; auto tv = v_in | etl::views::transform(square); CHECK_EQUAL(9, tv.front()); } TEST(test_ranges_transform_view_index_operator) { auto square = [](int i) -> int { return i * i; }; etl::vector v_in{1, 2, 3, 4, 5}; auto tv = v_in | etl::views::transform(square); CHECK_EQUAL(1, tv[0]); CHECK_EQUAL(4, tv[1]); CHECK_EQUAL(9, tv[2]); CHECK_EQUAL(16, tv[3]); CHECK_EQUAL(25, tv[4]); } TEST(test_ranges_transform_view_type_change) { auto to_double = [](int i) -> double { return i * 1.5; }; etl::vector v_in{2, 4, 6}; auto tv = v_in | etl::views::transform(to_double); auto it = tv.begin(); CHECK_CLOSE(3.0, *it, 0.001); ++it; CHECK_CLOSE(6.0, *it, 0.001); ++it; CHECK_CLOSE(9.0, *it, 0.001); ++it; CHECK(it == tv.end()); } TEST(test_ranges_transform_view_element_type_is_function_result) { // transform_view must be type-changing: the element type is the result of the // transform function, not the underlying range's element type. auto to_double = [](int i) -> double { return i * 1.5; }; etl::vector v_in{1, 2, 3, 4}; auto tv = v_in | etl::views::transform(to_double); using element_type = etl::remove_cvref_t; static_assert(etl::is_same::value, "transform element should be the function result type"); // Fractional results must survive (they would be truncated to int by the old behaviour). etl::vector v_out; for (auto x : tv) { v_out.push_back(x); } CHECK_CLOSE(1.5, v_out[0], 0.001); CHECK_CLOSE(3.0, v_out[1], 0.001); CHECK_CLOSE(4.5, v_out[2], 0.001); CHECK_CLOSE(6.0, v_out[3], 0.001); } TEST(test_ranges_transform_view_yields_range_then_join) { // A transform that returns a range, joined together, only compiles when the // transform element type is the range returned by the function. etl::array samples = {10, 20, 30, 40}; etl::array dst = {0, 0, 0, 0, 0, 0, 0, 0}; auto stereo = samples | etl::views::transform([](int s) { return etl::views::repeat(s, 2); }) | etl::views::join; etl::copy(stereo.begin(), stereo.end(), dst.begin()); etl::array expected = {10, 10, 20, 20, 30, 30, 40, 40}; for (size_t i = 0; i < dst.size(); ++i) { CHECK_EQUAL(expected[i], dst[i]); } } TEST(test_ranges_transform_view_iterator_increment) { auto square = [](int i) -> int { return i * i; }; etl::vector v_in{1, 2, 3}; auto tv = v_in | etl::views::transform(square); // Pre-increment auto it = tv.begin(); CHECK_EQUAL(1, *it); ++it; CHECK_EQUAL(4, *it); // Post-increment auto it2 = tv.begin(); auto old = it2++; CHECK_EQUAL(1, *old); CHECK_EQUAL(4, *it2); } TEST(test_ranges_transform_view_iterator_equality) { auto identity = [](int i) -> int { return i; }; etl::vector v_in{1, 2, 3}; auto tv = v_in | etl::views::transform(identity); auto b = tv.begin(); auto e = tv.end(); CHECK(b != e); CHECK(b == tv.begin()); CHECK(e == tv.end()); } TEST(test_ranges_transform_view_chained_with_take) { auto square = [](int i) -> int { return i * i; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 4}; auto tv = v_in | etl::views::transform(square) | etl::views::take(3); for (auto i : tv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_transform_view_chained_with_temporary) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 4}; auto tv = v_in | etl::views::transform([](int i) -> int { return i * i; }) | etl::views::take(3); for (auto i : tv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_transform_view_chained_with_drop) { auto square = [](int i) -> int { return i * i; }; etl::vector v_in{0, 1, 2, 3, 4}; etl::vector v_out; etl::vector v_out_expected{9, 16}; auto tv = v_in | etl::views::transform(square) | etl::views::drop(3); for (auto i : tv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_transform_view_chained_transforms) { auto add_one = [](int i) -> int { return i + 1; }; auto multiply = [](int i) -> int { return i * 10; }; etl::vector v_in{0, 1, 2, 3, 4}; etl::vector v_out; etl::vector v_out_expected{10, 20, 30, 40, 50}; auto tv = v_in | etl::views::transform(add_one) | etl::views::transform(multiply); for (auto i : tv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_transform_view_with_std_vector) { auto square = [](int i) -> int { return i * i; }; std::vector v_in{1, 2, 3, 4, 5}; std::vector v_out; std::vector v_out_expected{1, 4, 9, 16, 25}; auto tv = v_in | etl::views::transform(square); for (auto i : tv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected.size(), v_out.size()); for (size_t idx = 0; idx < v_out_expected.size(); ++idx) { CHECK_EQUAL(v_out_expected[idx], v_out[idx]); } } TEST(test_ranges_transform_view_with_std_array) { auto square = [](int i) -> int { return i * i; }; std::array v_in{1, 2, 3, 4, 5}; std::vector v_out; std::vector v_out_expected{1, 4, 9, 16, 25}; auto tv = v_in | etl::views::transform(square); for (auto i : tv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected.size(), v_out.size()); for (size_t idx = 0; idx < v_out_expected.size(); ++idx) { CHECK_EQUAL(v_out_expected[idx], v_out[idx]); } } TEST(test_ranges_transform_view_single_element) { auto negate = [](int i) -> int { return -i; }; etl::vector v_in{42}; etl::vector v_out; etl::vector v_out_expected{-42}; auto tv = v_in | etl::views::transform(negate); for (auto i : tv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } //************************************************************************* /// filter_view tests //************************************************************************* TEST(test_ranges_filter_view_functional) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 2, 4, 6, 8}; auto fv = etl::views::filter(v_in, even); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_filter_view_direct_construction) { auto odd = [](int i) -> bool { return 1 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{1, 3, 5, 7, 9}; auto fv = etl::ranges::filter_view(etl::views::all(v_in), odd); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_filter_view_pipe) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 2, 4, 6, 8}; auto fv = v_in | etl::views::filter(even); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_filter_view_size) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto fv = v_in | etl::views::filter(even); CHECK_EQUAL(5u, fv.size()); } TEST(test_ranges_filter_view_empty) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in; auto fv = v_in | etl::views::filter(even); CHECK_EQUAL(true, fv.empty()); CHECK_EQUAL(0u, fv.size()); } TEST(test_ranges_filter_view_non_empty) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{42}; auto fv = v_in | etl::views::filter(even); CHECK_EQUAL(false, fv.empty()); CHECK_EQUAL(1u, fv.size()); } TEST(test_ranges_filter_view_all_filtered_out) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{1, 3, 5, 7, 9}; auto fv = v_in | etl::views::filter(even); CHECK_EQUAL(true, fv.empty()); CHECK_EQUAL(0u, fv.size()); } TEST(test_ranges_filter_view_all_pass) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 2, 4, 6, 8}; etl::vector v_out; etl::vector v_out_expected{0, 2, 4, 6, 8}; auto fv = v_in | etl::views::filter(even); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(5u, fv.size()); } TEST(test_ranges_filter_view_front) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{1, 2, 3, 4, 5}; auto fv = v_in | etl::views::filter(even); CHECK_EQUAL(2, fv.front()); } TEST(test_ranges_filter_view_index_operator) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto fv = v_in | etl::views::filter(even); CHECK_EQUAL(0, fv[0]); CHECK_EQUAL(2, fv[1]); CHECK_EQUAL(4, fv[2]); CHECK_EQUAL(6, fv[3]); CHECK_EQUAL(8, fv[4]); } TEST(test_ranges_filter_view_iterator_increment) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4}; auto fv = v_in | etl::views::filter(even); // Pre-increment auto it = fv.begin(); CHECK_EQUAL(0, *it); ++it; CHECK_EQUAL(2, *it); // Post-increment auto it2 = fv.begin(); auto old = it2++; CHECK_EQUAL(0, *old); CHECK_EQUAL(2, *it2); } TEST(test_ranges_filter_view_iterator_equality) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4}; auto fv = v_in | etl::views::filter(even); auto b = fv.begin(); auto e = fv.end(); CHECK(b != e); CHECK(b == fv.begin()); CHECK(e == fv.end()); } TEST(test_ranges_filter_view_chained_with_take) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 2}; auto fv = v_in | etl::views::filter(even) | etl::views::take(2); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_filter_view_chained_with_temporary) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 2}; auto fv = v_in | etl::views::filter([](int i) -> bool { return 0 == i % 2; }) | etl::views::take(2); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_filter_view_chained_with_drop) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{4, 6, 8}; auto fv = v_in | etl::views::filter(even) | etl::views::drop(2); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_filter_view_chained_with_transform) { auto even = [](int i) -> bool { return 0 == i % 2; }; auto square = [](int i) -> int { return i * i; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 4, 16, 36, 64}; auto fv = v_in | etl::views::filter(even) | etl::views::transform(square); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_filter_view_with_std_vector) { auto even = [](int i) -> bool { return 0 == i % 2; }; std::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; std::vector v_out; std::vector v_out_expected{0, 2, 4, 6, 8}; auto fv = v_in | etl::views::filter(even); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected.size(), v_out.size()); for (size_t idx = 0; idx < v_out_expected.size(); ++idx) { CHECK_EQUAL(v_out_expected[idx], v_out[idx]); } } TEST(test_ranges_filter_view_with_std_array) { auto even = [](int i) -> bool { return 0 == i % 2; }; std::array v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; std::vector v_out; std::vector v_out_expected{0, 2, 4, 6, 8}; auto fv = v_in | etl::views::filter(even); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected.size(), v_out.size()); for (size_t idx = 0; idx < v_out_expected.size(); ++idx) { CHECK_EQUAL(v_out_expected[idx], v_out[idx]); } } TEST(test_ranges_filter_view_single_element) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{42}; etl::vector v_out; etl::vector v_out_expected{42}; auto fv = v_in | etl::views::filter(even); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_filter_view_c_array) { auto even = [](int i) -> bool { return 0 == i % 2; }; int v_in[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 2, 4, 6, 8}; auto fv = etl::views::filter(v_in, even); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_filter_view_c_array_pipe) { auto even = [](int i) -> bool { return 0 == i % 2; }; int v_in[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 2, 4, 6, 8}; auto fv = v_in | etl::views::filter(even); for (auto i : fv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_filter_view_non_const_reference_type) { // filter must yield mutable element references when the underlying range // is non-const, matching std::ranges::filter_view. std::vector v = {1, 2, 3, 4}; auto fv = v | etl::views::filter([](int i) { return i % 2 == 0; }); using element_ref = decltype(*fv.begin()); static_assert(etl::is_same::value, "filter element should be a non-const reference"); static_assert(!etl::is_const_v>, "filter element should be mutable"); *fv.begin() = 99; // first even element is v[1] CHECK_EQUAL(99, v[1]); } TEST(test_ranges_filter_view_modify_elements) { // Double every even element in place; odd elements are left untouched. std::vector v = {1, 2, 3, 4, 5, 6}; for (auto& element : v | etl::views::filter([](int i) { return i % 2 == 0; })) { element *= 10; } std::vector expected{1, 20, 3, 40, 5, 60}; CHECK_EQUAL(expected, v); } TEST(test_ranges_join_functional) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; auto result = etl::views::join(v); using result_type = etl::vector; result_type v_expected{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; auto expected_view = etl::views::all(v_expected); CHECK_EQUAL(result, expected_view); } TEST(test_ranges_join_pipe) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; auto result = v | etl::views::join; using result_type = etl::vector; result_type v_expected{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; auto expected_view = etl::views::all(v_expected); CHECK_EQUAL(result, expected_view); } TEST(test_ranges_join_degenerated_1) { using range_type = etl::vector; etl::vector v{{1}, {1, 2, 3}, {1}, {7, 8, 9}, {1}}; auto result = v | etl::views::join; using result_type = etl::vector; result_type v_expected{1, 1, 2, 3, 1, 7, 8, 9, 1}; auto expected_view = etl::views::all(v_expected); CHECK_EQUAL(9, result.size()); CHECK_EQUAL(expected_view, result); } TEST(test_ranges_join_degenerated_2) { using range_type = etl::vector; etl::vector v{{}, {1, 2, 3}, {}, {7, 8, 9}, {}}; auto rv = v | etl::views::join; using result_type = etl::vector; result_type v_expected{1, 2, 3, 7, 8, 9}; auto expected_view = etl::views::all(v_expected); CHECK_EQUAL(6, rv.size()); CHECK_EQUAL(expected_view, rv); } TEST(test_ranges_join_iterate) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; using result_type = etl::vector; auto result = v | etl::views::join | etl::ranges::to(); result_type result_v; for (auto i : result) { result_v.emplace_back(i); } result_type v_expected{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; CHECK_EQUAL(result_v, v_expected); } TEST(test_ranges_join_view) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; using result_type = etl::vector; auto result = v | etl::views::join | etl::ranges::to(); result_type v_expected{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}; CHECK_EQUAL(result, v_expected); } TEST(test_ranges_join_with_functional) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; range_type pattern{111, 222}; auto result = etl::views::join_with(v, pattern); using result_type = etl::vector; result_type v_expected{1, 2, 3, 111, 222, 4, 5, 6, 111, 222, 7, 8, 9, 111, 222, 10, 11, 12}; auto expected_view = etl::views::all(v_expected); CHECK_EQUAL(result, expected_view); } TEST(test_ranges_join_with_pipe) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; range_type pattern{111, 222}; auto result = v | etl::views::join_with(pattern); using result_type = etl::vector; result_type v_expected{1, 2, 3, 111, 222, 4, 5, 6, 111, 222, 7, 8, 9, 111, 222, 10, 11, 12}; auto expected_view = etl::views::all(v_expected); CHECK_EQUAL(result, expected_view); } TEST(test_ranges_join_with_degenerated_1) { using range_type = etl::vector; etl::vector v{{1}, {1, 2, 3}, {1}, {7, 8, 9}, {1}}; range_type pattern{111, 222}; auto result = v | etl::views::join_with(pattern); using result_type = etl::vector; result_type v_expected{1, 111, 222, 1, 2, 3, 111, 222, 1, 111, 222, 7, 8, 9, 111, 222, 1}; auto expected_view = etl::views::all(v_expected); CHECK_EQUAL(17, result.size()); CHECK_EQUAL(expected_view, result); } TEST(test_ranges_join_with_degenerated_2) { using range_type = etl::vector; etl::vector v{{}, {1, 2, 3}, {}, {7, 8, 9}, {}}; range_type pattern{111, 222}; auto rv = v | etl::views::join_with(pattern); using result_type = etl::vector; result_type v_expected{111, 222, 1, 2, 3, 111, 222, 111, 222, 7, 8, 9, 111, 222}; auto expected_view = etl::views::all(v_expected); CHECK_EQUAL(14, rv.size()); CHECK_EQUAL(expected_view, rv); } TEST(test_ranges_join_with_iterate) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; range_type pattern{111, 222}; using result_type = etl::vector; auto result = v | etl::views::join_with(pattern) | etl::ranges::to(); result_type result_v; for (auto i : result) { result_v.emplace_back(i); } result_type v_expected{1, 2, 3, 111, 222, 4, 5, 6, 111, 222, 7, 8, 9, 111, 222, 10, 11, 12}; CHECK_EQUAL(result_v, v_expected); } TEST(test_ranges_join_with_view) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; range_type pattern{111, 222}; using result_type = etl::vector; auto result = v | etl::views::join_with(pattern) | etl::ranges::to(); result_type v_expected{1, 2, 3, 111, 222, 4, 5, 6, 111, 222, 7, 8, 9, 111, 222, 10, 11, 12}; CHECK_EQUAL(result, v_expected); } TEST(test_ranges_join_with_functional_single) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; int pattern{111}; auto result = etl::views::join_with(v, pattern); using result_type = etl::vector; result_type v_expected{1, 2, 3, 111, 4, 5, 6, 111, 7, 8, 9, 111, 10, 11, 12}; auto expected_view = etl::views::all(v_expected); CHECK_EQUAL(result, expected_view); } TEST(test_ranges_join_with_functional_single_immediate) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; auto result = etl::views::join_with(v, 111); using result_type = etl::vector; result_type v_expected{1, 2, 3, 111, 4, 5, 6, 111, 7, 8, 9, 111, 10, 11, 12}; auto expected_view = etl::views::all(v_expected); CHECK_EQUAL(result, expected_view); } TEST(test_ranges_join_with_pipe_single) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; int pattern{111}; auto result = v | etl::views::join_with(pattern); using result_type = etl::vector; result_type v_expected{1, 2, 3, 111, 4, 5, 6, 111, 7, 8, 9, 111, 10, 11, 12}; auto expected_view = etl::views::all(v_expected); CHECK_EQUAL(result, expected_view); } TEST(test_ranges_join_with_iterate_single) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; int pattern{111}; using result_type = etl::vector; auto result = v | etl::views::join_with(pattern) | etl::ranges::to(); result_type result_v; for (auto i : result) { result_v.emplace_back(i); } result_type v_expected{1, 2, 3, 111, 4, 5, 6, 111, 7, 8, 9, 111, 10, 11, 12}; CHECK_EQUAL(result_v, v_expected); } TEST(test_ranges_join_with_view_single) { using range_type = etl::vector; etl::vector v{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12}}; int pattern{111}; using result_type = etl::vector; auto result = v | etl::views::join_with(pattern) | etl::ranges::to(); result_type v_expected{1, 2, 3, 111, 4, 5, 6, 111, 7, 8, 9, 111, 10, 11, 12}; CHECK_EQUAL(result, v_expected); } TEST(test_ranges_join_with_view_yields_range_then_join_with) { // join_with must support inner ranges whose iterators yield prvalues // (e.g. repeat_view produced by a type-changing transform), and its declared // reference type must stay consistent with what operator* actually yields. etl::array samples = {10, 20, 30}; etl::array dst = {0, 0, 0, 0, 0, 0, 0, 0}; auto stereo = samples | etl::views::transform([](int s) { return etl::views::repeat(s, 2); }) | etl::views::join_with(0); using iterator_type = decltype(stereo.begin()); using declared_reference = typename iterator_type::reference; using actual_deref = decltype(*etl::declval()); static_assert(etl::is_same::value, "join_with_iterator::reference must match operator*"); etl::copy(stereo.begin(), stereo.end(), dst.begin()); etl::array expected = {10, 10, 0, 20, 20, 0, 30, 30}; for (size_t i = 0; i < dst.size(); ++i) { CHECK_EQUAL(expected[i], dst[i]); } } TEST(test_ranges_join_with_writable_reference) { // For a mutable range pattern, join_with must yield mutable references and be // writable, matching std::ranges::join_with_view (reference is the common // reference of the inner range's and the pattern's references: int&). etl::vector, 2> v{{1, 2, 3}, {4, 5, 6}}; etl::vector pattern{0}; auto jv = etl::views::join_with(v, pattern); using element_ref = decltype(*jv.begin()); static_assert(etl::is_same::value, "join_with element should be a non-const reference for a mutable range pattern"); static_assert(!etl::is_const_v>, "join_with element should be mutable"); // Sequence: 1, 2, 3, [0], 4, 5, 6 auto it = jv.begin(); *it = 99; // first inner element -> v[0][0] CHECK_EQUAL(99, v[0][0]); ++it; // 2 ++it; // 3 ++it; // pattern separator *it = 77; CHECK_EQUAL(77, pattern[0]); } TEST(test_ranges_join_with_single_value_reference_is_const) { // A single-value pattern is backed by a value (single_view) and is therefore // read as const, so the common reference degrades to const int&. (This is a // minor deviation from std::ranges, where a single-element pattern is writable.) etl::vector, 2> v{{1, 2, 3}, {4, 5, 6}}; auto jv = etl::views::join_with(v, 0); using element_ref = decltype(*jv.begin()); static_assert(etl::is_same::value, "single-value join_with pattern should be read as const"); etl::vector out; for (auto x : jv) { out.push_back(x); } etl::vector expected{1, 2, 3, 0, 4, 5, 6}; CHECK_EQUAL(expected, out); } TEST(test_ranges_join_with_common_value_type) { // When the inner range and the pattern have different (but common-convertible) // element types, the element type is their common type, per // [range.join.with.iterator]. etl::vector, 2> v{{1, 2, 3}, {4, 5, 6}}; etl::vector pattern{char(0)}; auto jv = etl::views::join_with(v, pattern); using element_type = etl::remove_cvref_t; static_assert(etl::is_same::value, "join_with element type should be the common type of inner and pattern"); etl::vector out; for (auto x : jv) { out.push_back(x); } etl::vector expected{1, 2, 3, 0, 4, 5, 6}; CHECK_EQUAL(expected, out); } //************************************************************************* // split_view and views::split tests //************************************************************************* TEST(test_ranges_split_view_int_vector) { etl::vector v_in{1, 2, 0, 3, 4, 0, 5}; auto sv = etl::ranges::split_view(v_in, 0); std::vector> expected{{1, 2}, {3, 4}, {5}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_split_view_functional_single_delim) { // Split {1, 2, 0, 3, 4, 0, 5, 6} by 0 => {1,2}, {3,4}, {5,6} std::vector v_in{1, 2, 0, 3, 4, 0, 5, 6}; auto sv = etl::ranges::split_view(v_in, 0); std::vector> expected{{1, 2}, {3, 4}, {5, 6}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_split_view_multi_pattern) { // Split {1, 2, 0, 0, 3, 4, 0, 0, 5} by pattern {0, 0} => {1,2}, {3,4}, // {5} std::vector v_in{1, 2, 0, 0, 3, 4, 0, 0, 5}; std::vector delim{0, 0}; auto sv = etl::ranges::split_view(v_in, delim); std::vector> expected{{1, 2}, {3, 4}, {5}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_split_view_pipe) { // Pipe syntax: {1, 0, 2, 0, 3} | split(0) => {1}, {2}, {3} std::vector v_in{1, 0, 2, 0, 3}; auto sv = v_in | etl::views::split(0); std::vector> expected{{1}, {2}, {3}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_split_view_empty_input) { // Split empty range => one empty subrange std::vector v_in{}; auto sv = etl::ranges::split_view(v_in, 0); size_t count = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(actual.size(), 0U); ++count; } CHECK_EQUAL(count, 1U); } TEST(test_ranges_split_view_no_delim) { // No delimiter found => one subrange with all elements std::vector v_in{1, 2, 3}; auto sv = etl::ranges::split_view(v_in, 0); size_t count = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); std::vector expected_sub{1, 2, 3}; CHECK_EQUAL(expected_sub, actual); ++count; } CHECK_EQUAL(count, 1U); } TEST(test_ranges_split_view_delim_at_edges) { // Delimiter at start and end: {0, 1, 2, 0} => {}, {1,2}, {} std::vector v_in{0, 1, 2, 0}; auto sv = etl::ranges::split_view(v_in, 0); std::vector> expected{{}, {1, 2}, {}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_split_view_consecutive_delim) { // Consecutive delimiters: {1, 0, 0, 2} => {1}, {}, {2} std::vector v_in{1, 0, 0, 2}; auto sv = etl::ranges::split_view(v_in, 0); std::vector> expected{{1}, {}, {2}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_split_view_pipe_multi_pattern) { // Pipe with multi-element pattern: {1, 2, 9, 9, 3, 4, 9, 9, 5} | // split({9,9}) => {1,2}, {3,4}, {5} std::vector v_in{1, 2, 9, 9, 3, 4, 9, 9, 5}; std::vector delim{9, 9}; auto sv = v_in | etl::views::split(delim); std::vector> expected{{1, 2}, {3, 4}, {5}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_split_view_etl_vector) { // Works with etl::vector too etl::vector v_in{1, 0, 2, 0, 3}; auto sv = etl::ranges::split_view(v_in, 0); std::vector> expected{{1}, {2}, {3}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } //************************************************************************* TEST(test_ranges_split_view_non_const_reference_type) { // split subranges must expose mutable element references when the // underlying range is non-const, matching std::ranges::split_view. std::vector v_in{1, 0, 2}; auto sv = etl::ranges::split_view(v_in, 0); auto first_seg = *sv.begin(); using element_ref = decltype(*first_seg.begin()); static_assert(etl::is_same::value, "split element should be a non-const reference"); static_assert(!etl::is_const_v>, "split element should be mutable"); *first_seg.begin() = 99; CHECK_EQUAL(99, v_in[0]); } //************************************************************************* TEST(test_ranges_split_view_modify_elements) { // Split on 0, then negate every element of every segment in place. std::vector v_in{1, 2, 0, 3, 0, 4, 5}; auto sv = etl::ranges::split_view(v_in, 0); for (auto seg : sv) { for (auto& element : seg) { element = -element; } } // Delimiters (the zeros) are not part of any segment and stay untouched. std::vector expected{-1, -2, 0, -3, 0, -4, -5}; CHECK_EQUAL(expected, v_in); } //************************************************************************* // lazy_split_view and views::lazy_split tests //************************************************************************* TEST(test_ranges_lazy_split_view_int_vector) { etl::vector v_in{1, 2, 0, 3, 4, 0, 5}; auto sv = etl::ranges::lazy_split_view(v_in, 0); std::vector> expected{{1, 2}, {3, 4}, {5}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_lazy_split_view_functional_single_delim) { // Split {1, 2, 0, 3, 4, 0, 5, 6} by 0 => {1,2}, {3,4}, {5,6} std::vector v_in{1, 2, 0, 3, 4, 0, 5, 6}; auto sv = etl::ranges::lazy_split_view(v_in, 0); std::vector> expected{{1, 2}, {3, 4}, {5, 6}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_lazy_split_view_multi_pattern) { // Split {1, 2, 0, 0, 3, 4, 0, 0, 5} by pattern {0, 0} => {1,2}, {3,4}, // {5} std::vector v_in{1, 2, 0, 0, 3, 4, 0, 0, 5}; std::vector delim{0, 0}; auto sv = etl::ranges::lazy_split_view(v_in, delim); std::vector> expected{{1, 2}, {3, 4}, {5}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_lazy_split_view_pipe) { // Pipe syntax: {1, 0, 2, 0, 3} | lazy_split(0) => {1}, {2}, {3} std::vector v_in{1, 0, 2, 0, 3}; auto sv = v_in | etl::views::lazy_split(0); std::vector> expected{{1}, {2}, {3}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_lazy_split_view_empty_input) { // Split empty range => one empty subrange std::vector v_in{}; auto sv = etl::ranges::lazy_split_view(v_in, 0); size_t count = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(actual.size(), 0U); ++count; } CHECK_EQUAL(count, 1U); } TEST(test_ranges_lazy_split_view_no_delim) { // No delimiter found => one subrange with all elements std::vector v_in{1, 2, 3}; auto sv = etl::ranges::lazy_split_view(v_in, 0); size_t count = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); std::vector expected_sub{1, 2, 3}; CHECK_EQUAL(expected_sub, actual); ++count; } CHECK_EQUAL(count, 1U); } TEST(test_ranges_lazy_split_view_delim_at_edges) { // Delimiter at start and end: {0, 1, 2, 0} => {}, {1,2}, {} std::vector v_in{0, 1, 2, 0}; auto sv = etl::ranges::lazy_split_view(v_in, 0); std::vector> expected{{}, {1, 2}, {}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_lazy_split_view_consecutive_delim) { // Consecutive delimiters: {1, 0, 0, 2} => {1}, {}, {2} std::vector v_in{1, 0, 0, 2}; auto sv = etl::ranges::lazy_split_view(v_in, 0); std::vector> expected{{1}, {}, {2}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_lazy_split_view_pipe_multi_pattern) { // Pipe with multi-element pattern: {1, 2, 9, 9, 3, 4, 9, 9, 5} | // lazy_split({9,9}) => {1,2}, {3,4}, {5} std::vector v_in{1, 2, 9, 9, 3, 4, 9, 9, 5}; std::vector delim{9, 9}; auto sv = v_in | etl::views::lazy_split(delim); std::vector> expected{{1, 2}, {3, 4}, {5}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_lazy_split_view_etl_vector) { // Works with etl::vector too etl::vector v_in{1, 0, 2, 0, 3}; auto sv = etl::ranges::lazy_split_view(v_in, 0); std::vector> expected{{1}, {2}, {3}}; size_t idx = 0; for (auto sub : sv) { std::vector actual(sub.begin(), sub.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(idx, expected.size()); } TEST(test_ranges_lazy_split_view_inner_range_lazy_iteration) { // Verify that the inner range can be iterated element-by-element (lazily) std::vector v_in{10, 20, 0, 30, 40, 50}; auto sv = etl::ranges::lazy_split_view(v_in, 0); auto outer_it = sv.begin(); // First segment: {10, 20} auto inner1 = *outer_it; auto inner_it = inner1.begin(); CHECK_EQUAL(*inner_it, 10); ++inner_it; CHECK_EQUAL(*inner_it, 20); ++inner_it; CHECK(inner_it == inner1.end()); // Second segment: {30, 40, 50} ++outer_it; auto inner2 = *outer_it; auto inner_it2 = inner2.begin(); CHECK_EQUAL(*inner_it2, 30); ++inner_it2; CHECK_EQUAL(*inner_it2, 40); ++inner_it2; CHECK_EQUAL(*inner_it2, 50); ++inner_it2; CHECK(inner_it2 == inner2.end()); ++outer_it; CHECK(outer_it == sv.end()); } TEST(test_ranges_lazy_split_view_inner_range_empty_check) { // Inner range empty() method std::vector v_in{0, 1, 0}; auto sv = etl::ranges::lazy_split_view(v_in, 0); auto it = sv.begin(); // First segment is empty auto seg0 = *it; CHECK(seg0.empty()); ++it; auto seg1 = *it; CHECK(!seg1.empty()); ++it; auto seg2 = *it; CHECK(seg2.empty()); } TEST(test_ranges_lazy_split_view_non_const_reference_type) { // lazy_split inner-range elements must be mutable references when the // underlying range is non-const, matching std::ranges::lazy_split_view. std::vector v_in{1, 2, 0, 3}; auto sv = etl::ranges::lazy_split_view(v_in, 0); auto first_seg = *sv.begin(); using element_ref = decltype(*first_seg.begin()); static_assert(etl::is_same::value, "lazy_split element should be a non-const reference"); static_assert(!etl::is_const_v>, "lazy_split element should be mutable"); *first_seg.begin() = 99; CHECK_EQUAL(99, v_in[0]); } TEST(test_ranges_lazy_split_view_modify_elements) { // Split lazily on 0, then double every element of every segment in place. std::vector v_in{1, 2, 0, 3, 0, 4}; auto sv = etl::ranges::lazy_split_view(v_in, 0); for (auto seg : sv) { for (auto& element : seg) { element *= 2; } } // Delimiters (the zeros) are skipped and remain unchanged. std::vector expected{2, 4, 0, 6, 0, 8}; CHECK_EQUAL(expected, v_in); } TEST(test_counted) { { std::vector vec{1, 2, 3, 4, 5}; auto result = etl::views::counted(vec.begin(), 3); CHECK_EQUAL(result.size(), 3); CHECK_EQUAL(result[0], 1); CHECK_EQUAL(result[1], 2); CHECK_EQUAL(result[2], 3); } { std::list list{1, 2, 3, 4, 5}; auto result = etl::views::counted(list.begin(), 3); CHECK_EQUAL(result.size(), 3); CHECK_EQUAL(result[0], 1); CHECK_EQUAL(result[1], 2); CHECK_EQUAL(result[2], 3); } } TEST(test_ranges_concat_view_1) { std::vector vec{1, 2, 3, 4}; using result_type = std::vector; auto cv = etl::views::concat(vec); result_type result = etl::views::concat(vec) | etl::ranges::to(); result_type expected_result{1, 2, 3, 4}; CHECK_EQUAL(cv.size(), 4); CHECK_EQUAL(result.size(), 4); CHECK_EQUAL(result, expected_result); } TEST(test_ranges_concat_view_2) { std::vector vec{1, 2, 3, 4}; std::list list{6, 7, 8, 9, 10}; auto cv = etl::views::concat(vec, list); using result_type = std::vector; result_type result = etl::views::concat(vec, list) | etl::ranges::to(); result_type expected_result{1, 2, 3, 4, 6, 7, 8, 9, 10}; CHECK_EQUAL(cv.size(), 9); CHECK_EQUAL(result.size(), 9); CHECK_EQUAL(result, expected_result); } TEST(test_ranges_concat_view_2_same_type) { std::vector vec0{1, 2, 3, 4}; std::vector vec1{6, 7, 8, 9, 10}; auto cv = etl::views::concat(vec0, vec1); using result_type = std::vector; result_type result = etl::views::concat(vec0, vec1) | etl::ranges::to(); std::vector expected_result{1, 2, 3, 4, 6, 7, 8, 9, 10}; CHECK_EQUAL(cv.size(), 9); CHECK_EQUAL(result.size(), 9); CHECK_EQUAL(result, expected_result); } TEST(test_ranges_concat_view_3) { std::vector vec{1, 2, 3, 4}; std::list list{6, 7, 8, 9, 10}; std::array arr{20, 21, 22}; auto cv = etl::views::concat(vec, list, arr); using result_type = std::vector; result_type result = etl::views::concat(vec, list, arr) | etl::ranges::to(); std::vector expected_result{1, 2, 3, 4, 6, 7, 8, 9, 10, 20, 21, 22}; CHECK_EQUAL(cv.size(), 12); CHECK_EQUAL(result.size(), 12); CHECK_EQUAL(result, expected_result); auto it = cv.begin(); CHECK(it != cv.end()); CHECK_EQUAL(*it, 1); ++it; CHECK_EQUAL(*it, 2); it++; CHECK_EQUAL(*it, 3); CHECK_EQUAL(it[0], 3); CHECK_EQUAL(it[1], 4); CHECK_EQUAL(it[2], 6); it += 3; CHECK_EQUAL(*it, 7); it -= 2; CHECK_EQUAL(*it, 4); --it; CHECK_EQUAL(*it, 3); it--; CHECK_EQUAL(*it, 2); CHECK(it != cv.end()); it += 8; CHECK_EQUAL(*it, 20); it += 2; CHECK_EQUAL(*it, 22); CHECK(it != cv.end()); ++it; CHECK(it == cv.end()); } TEST(test_ranges_concat_view_3_same_type) { std::vector vec0{1, 2, 3, 4}; std::vector vec1{6, 7, 8, 9, 10}; std::vector vec2{20, 21, 22}; auto cv = etl::views::concat(vec0, vec1, vec2); using result_type = std::vector; result_type result = etl::views::concat(vec0, vec1, vec2) | etl::ranges::to(); std::vector expected_result{1, 2, 3, 4, 6, 7, 8, 9, 10, 20, 21, 22}; CHECK_EQUAL(cv.size(), 12); CHECK_EQUAL(result.size(), 12); CHECK_EQUAL(result, expected_result); auto it = cv.begin(); CHECK(it != cv.end()); CHECK_EQUAL(*it, 1); ++it; CHECK_EQUAL(*it, 2); it++; CHECK_EQUAL(*it, 3); CHECK_EQUAL(it[0], 3); CHECK_EQUAL(it[1], 4); CHECK_EQUAL(it[2], 6); it += 3; CHECK_EQUAL(*it, 7); it -= 2; CHECK_EQUAL(*it, 4); --it; CHECK_EQUAL(*it, 3); it--; CHECK_EQUAL(*it, 2); CHECK(it != cv.end()); it += 8; CHECK_EQUAL(*it, 20); it += 2; CHECK_EQUAL(*it, 22); CHECK(it != cv.end()); ++it; CHECK(it == cv.end()); } TEST(test_ranges_concat_view_3_same_range) { std::vector vec0{1, 2, 3, 4, 5}; auto cv = etl::views::concat(vec0, vec0, vec0); using result_type = std::vector; result_type result = etl::views::concat(vec0, vec0, vec0) | etl::ranges::to(); std::vector expected_result{1, 2, 3, 4, 5, 1, 2, 3, 4, 5, 1, 2, 3, 4, 5}; CHECK_EQUAL(cv.size(), 15); CHECK_EQUAL(result.size(), 15); CHECK_EQUAL(result, expected_result); auto it = cv.begin(); CHECK(it != cv.end()); CHECK_EQUAL(*it, 1); ++it; CHECK_EQUAL(*it, 2); it++; CHECK_EQUAL(*it, 3); CHECK_EQUAL(it[0], 3); CHECK_EQUAL(it[1], 4); CHECK_EQUAL(it[2], 5); it += 3; CHECK_EQUAL(*it, 1); it -= 2; CHECK_EQUAL(*it, 4); --it; CHECK_EQUAL(*it, 3); it--; CHECK_EQUAL(*it, 2); CHECK(it != cv.end()); it += 11; CHECK_EQUAL(*it, 3); it += 2; CHECK_EQUAL(*it, 5); CHECK(it != cv.end()); ++it; CHECK(it == cv.end()); } //************************************************************************* // common_view tests //************************************************************************* TEST(test_ranges_common_view_functional) { etl::vector v_in{0, 1, 2, 3, 4}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4}; auto cv = etl::ranges::common_view(v_in); for (int i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(*cv.begin(), 0); CHECK_EQUAL(cv.size(), 5); CHECK_EQUAL(*cv.cbegin(), 0); CHECK_EQUAL(cv.empty(), false); CHECK_EQUAL(cv, true); CHECK_EQUAL(cv.front(), 0); CHECK_EQUAL(cv.back(), 4); CHECK_EQUAL(cv[2], 2); } TEST(test_ranges_common_view_from_view) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{3, 4, 5, 6, 7, 8, 9}; auto cv = etl::ranges::common_view(etl::views::drop(v_in, 3)); for (int i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(*cv.begin(), 3); CHECK_EQUAL(cv.size(), 7); CHECK_EQUAL(cv.empty(), false); CHECK_EQUAL(cv.front(), 3); CHECK_EQUAL(cv.back(), 9); } TEST(test_ranges_common_view_pipe) { etl::vector v_in{0, 1, 2, 3, 4}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4}; auto cv = v_in | etl::views::common; for (int i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(*cv.begin(), 0); CHECK_EQUAL(cv.size(), 5); CHECK_EQUAL(cv.empty(), false); CHECK_EQUAL(cv.front(), 0); CHECK_EQUAL(cv.back(), 4); } TEST(test_ranges_common_view_pipe_chain) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{4, 3, 2, 1, 0}; auto cv = v_in | etl::views::take(5) | etl::views::reverse | etl::views::common; for (int i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(cv.size(), 5); CHECK_EQUAL(cv.front(), 4); CHECK_EQUAL(cv.back(), 0); } TEST(test_ranges_common_view_empty) { etl::vector v_in{}; auto cv = etl::ranges::common_view(v_in); CHECK_EQUAL(cv.size(), 0); CHECK_EQUAL(cv.empty(), true); CHECK_EQUAL(cv.begin(), cv.end()); } TEST(test_ranges_common_view_same_begin_end_type) { // For a common range (begin/end same type), common_view should work as // pass-through etl::vector v_in{10, 20, 30}; auto cv = etl::views::common(v_in); auto it_begin = cv.begin(); auto it_end = cv.end(); // Verify same type via compilation and correct values CHECK(it_begin != it_end); CHECK_EQUAL(*it_begin, 10); CHECK_EQUAL(cv.size(), 3); CHECK_EQUAL(cv.front(), 10); CHECK_EQUAL(cv.back(), 30); } TEST(test_ranges_common_view_iterate) { etl::vector v_in{1, 2, 3, 4, 5}; using result_type = etl::vector; result_type result = v_in | etl::views::common | etl::ranges::to(); result_type v_expected{1, 2, 3, 4, 5}; CHECK_EQUAL(result, v_expected); } TEST(test_ranges_common_view_with_filter) { auto even = [](int i) -> bool { return 0 == i % 2; }; etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 2, 4, 6, 8}; auto cv = v_in | etl::views::filter(even) | etl::views::common(); for (int i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_common_view_with_transform) { auto times_two = [](int i) -> int { return i * 2; }; etl::vector v_in{1, 2, 3, 4, 5}; etl::vector v_out; etl::vector v_out_expected{2, 4, 6, 8, 10}; auto cv = v_in | etl::views::transform(times_two) | etl::views::common; for (int i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } TEST(test_ranges_common_view_std_vector) { std::vector v_in{10, 20, 30, 40, 50}; std::vector v_out; std::vector v_out_expected{10, 20, 30, 40, 50}; auto cv = etl::ranges::common_view(etl::ranges::ref_view(v_in)); for (int i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(cv.size(), 5); CHECK_EQUAL(cv.front(), 10); CHECK_EQUAL(cv.back(), 50); } TEST(test_ranges_common_view_c_array) { int v_in[] = {1, 2, 3, 4, 5}; etl::vector v_out; etl::vector v_out_expected{1, 2, 3, 4, 5}; auto cv = etl::ranges::common_view(etl::ranges::ref_view(v_in)); for (int i : cv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(cv.size(), 5); } //************************************************************************* TEST(test_ranges_elements_of_from_lvalue) { std::vector v{1, 2, 3, 4, 5}; auto eo = etl::ranges::elements_of{v}; // The wrapped range should refer to the same data CHECK_EQUAL(v.size(), eo.range.size()); CHECK_EQUAL(v[0], eo.range[0]); CHECK_EQUAL(v[4], eo.range[4]); } //************************************************************************* TEST(test_ranges_elements_of_from_rvalue) { auto eo = etl::ranges::elements_of{std::vector{10, 20, 30}}; CHECK_EQUAL(3U, eo.range.size()); CHECK_EQUAL(10, eo.range[0]); CHECK_EQUAL(20, eo.range[1]); CHECK_EQUAL(30, eo.range[2]); } //************************************************************************* TEST(test_ranges_elements_of_deduction_guide) { std::vector v{1, 2, 3}; // CTAD should deduce elements_of&> auto eo = etl::ranges::elements_of{v}; (void)eo; // CTAD from rvalue should deduce elements_of&&> auto eo2 = etl::ranges::elements_of{std::vector{4, 5, 6}}; (void)eo2; } //************************************************************************* TEST(test_ranges_elements_of_c_array) { int arr[] = {10, 20, 30, 40, 50}; auto eo = etl::ranges::elements_of{arr}; CHECK_EQUAL(10, eo.range[0]); CHECK_EQUAL(50, eo.range[4]); } //************************************************************************* TEST(test_ranges_elements_view_pair_first) { std::vector> v = {{1, 1.1}, {2, 2.2}, {3, 3.3}}; auto ev = etl::ranges::elements_view, 0>(etl::ranges::views::all(v)); auto it = ev.begin(); CHECK_EQUAL(1, *it); ++it; CHECK_EQUAL(2, *it); ++it; CHECK_EQUAL(3, *it); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_elements_view_pair_second) { std::vector> v = {{1, 1.1}, {2, 2.2}, {3, 3.3}}; auto ev = etl::ranges::elements_view, 1>(etl::ranges::views::all(v)); auto it = ev.begin(); CHECK_CLOSE(1.1, *it, 0.001); ++it; CHECK_CLOSE(2.2, *it, 0.001); ++it; CHECK_CLOSE(3.3, *it, 0.001); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_elements_view_tuple) { std::vector> v = {etl::make_tuple(10, 1.5, 'a'), etl::make_tuple(20, 2.5, 'b'), etl::make_tuple(30, 3.5, 'c')}; // Extract element 2 (char) auto ev = etl::ranges::elements_view, 2>(etl::ranges::views::all(v)); auto it = ev.begin(); CHECK_EQUAL('a', *it); ++it; CHECK_EQUAL('b', *it); ++it; CHECK_EQUAL('c', *it); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_elements_view_size) { std::vector> v = {{1, 10}, {2, 20}, {3, 30}, {4, 40}}; auto ev = etl::ranges::elements_view, 0>(etl::ranges::views::all(v)); CHECK_EQUAL(4U, ev.size()); } //************************************************************************* TEST(test_ranges_elements_view_empty) { std::vector> v; auto ev = etl::ranges::elements_view, 0>(etl::ranges::views::all(v)); CHECK(ev.empty()); CHECK(ev.begin() == ev.end()); } //************************************************************************* TEST(test_ranges_views_elements_adaptor) { std::vector> v = {{1, 1.1}, {2, 2.2}, {3, 3.3}}; auto ev = etl::views::elements<0>(v); auto it = ev.begin(); CHECK_EQUAL(1, *it); ++it; CHECK_EQUAL(2, *it); ++it; CHECK_EQUAL(3, *it); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_views_elements_pipe) { std::vector> v = {{1, 1.1}, {2, 2.2}, {3, 3.3}}; auto ev = v | etl::views::elements<1>; auto it = ev.begin(); CHECK_CLOSE(1.1, *it, 0.001); ++it; CHECK_CLOSE(2.2, *it, 0.001); ++it; CHECK_CLOSE(3.3, *it, 0.001); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_keys_view_alias) { std::vector> v = {{10, 1.1}, {20, 2.2}, {30, 3.3}}; using range_t = etl::ranges::views::all_t; etl::ranges::keys_view kv(etl::ranges::views::all(v)); auto it = kv.begin(); CHECK_EQUAL(10, *it); ++it; CHECK_EQUAL(20, *it); ++it; CHECK_EQUAL(30, *it); ++it; CHECK(it == kv.end()); } //************************************************************************* TEST(test_ranges_values_view_alias) { std::vector> v = {{10, 1.1}, {20, 2.2}, {30, 3.3}}; using range_t = etl::ranges::views::all_t; etl::ranges::values_view vv(etl::ranges::views::all(v)); auto it = vv.begin(); CHECK_CLOSE(1.1, *it, 0.001); ++it; CHECK_CLOSE(2.2, *it, 0.001); ++it; CHECK_CLOSE(3.3, *it, 0.001); ++it; CHECK(it == vv.end()); } //************************************************************************* TEST(test_ranges_views_keys) { std::vector> v = {{10, 1.1}, {20, 2.2}, {30, 3.3}}; auto ev = v | etl::views::keys; auto it = ev.begin(); CHECK_EQUAL(10, *it); ++it; CHECK_EQUAL(20, *it); ++it; CHECK_EQUAL(30, *it); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_views_values) { std::vector> v = {{10, 1.1}, {20, 2.2}, {30, 3.3}}; auto ev = v | etl::views::values; auto it = ev.begin(); CHECK_CLOSE(1.1, *it, 0.001); ++it; CHECK_CLOSE(2.2, *it, 0.001); ++it; CHECK_CLOSE(3.3, *it, 0.001); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_views_keys_direct_call) { std::vector> v = {{10, 1.1}, {20, 2.2}, {30, 3.3}}; auto ev = etl::views::keys(v); auto it = ev.begin(); CHECK_EQUAL(10, *it); ++it; CHECK_EQUAL(20, *it); ++it; CHECK_EQUAL(30, *it); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_views_values_direct_call) { std::vector> v = {{10, 1.1}, {20, 2.2}, {30, 3.3}}; auto ev = etl::views::values(v); auto it = ev.begin(); CHECK_CLOSE(1.1, *it, 0.001); ++it; CHECK_CLOSE(2.2, *it, 0.001); ++it; CHECK_CLOSE(3.3, *it, 0.001); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_elements_view_with_etl_tuple) { std::vector> v = {etl::make_tuple(1, 10.0, 'x'), etl::make_tuple(2, 20.0, 'y'), etl::make_tuple(3, 30.0, 'z')}; // Extract element 0 via pipe auto ev0 = v | etl::views::elements<0>; auto it0 = ev0.begin(); CHECK_EQUAL(1, *it0); ++it0; CHECK_EQUAL(2, *it0); ++it0; CHECK_EQUAL(3, *it0); ++it0; CHECK(it0 == ev0.end()); // Extract element 1 via pipe auto ev1 = v | etl::views::elements<1>; auto it1 = ev1.begin(); CHECK_CLOSE(10.0, *it1, 0.001); ++it1; CHECK_CLOSE(20.0, *it1, 0.001); ++it1; CHECK_CLOSE(30.0, *it1, 0.001); ++it1; CHECK(it1 == ev1.end()); // Extract element 2 via pipe auto ev2 = v | etl::views::elements<2>; auto it2 = ev2.begin(); CHECK_EQUAL('x', *it2); ++it2; CHECK_EQUAL('y', *it2); ++it2; CHECK_EQUAL('z', *it2); ++it2; CHECK(it2 == ev2.end()); } //************************************************************************* TEST(test_ranges_elements_view_non_const_reference_type) { // elements must yield a mutable reference to the selected tuple element // when the underlying range is non-const, matching std::ranges::elements_view. std::vector> v = {{1, 1.1}, {2, 2.2}}; auto ev = v | etl::views::keys; using element_ref = decltype(*ev.begin()); static_assert(etl::is_same::value, "elements element should be a non-const reference"); static_assert(!etl::is_const_v>, "elements element should be mutable"); *ev.begin() = 99; CHECK_EQUAL(99, v[0].first); } //************************************************************************* TEST(test_ranges_elements_view_modify_elements) { // Write through the values (second element) of each pair in place. std::vector> v = {{1, 10}, {2, 20}, {3, 30}}; for (auto& value : v | etl::views::values) { value += 1; } CHECK_EQUAL(11, v[0].second); CHECK_EQUAL(21, v[1].second); CHECK_EQUAL(31, v[2].second); } //************************************************************************* TEST(test_ranges_enumerate_view_basic) { std::vector v = {10, 20, 30}; auto ev = etl::ranges::enumerate_view(etl::ranges::views::all(v)); auto it = ev.begin(); CHECK_EQUAL(0U, etl::get<0>(*it)); CHECK_EQUAL(10, etl::get<1>(*it)); ++it; CHECK_EQUAL(1U, etl::get<0>(*it)); CHECK_EQUAL(20, etl::get<1>(*it)); ++it; CHECK_EQUAL(2U, etl::get<0>(*it)); CHECK_EQUAL(30, etl::get<1>(*it)); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_enumerate_view_pipe) { std::vector v = {"a", "b", "c"}; auto ev = v | etl::views::enumerate; auto it = ev.begin(); CHECK_EQUAL(0U, etl::get<0>(*it)); CHECK_EQUAL(std::string("a"), etl::get<1>(*it)); ++it; CHECK_EQUAL(1U, etl::get<0>(*it)); CHECK_EQUAL(std::string("b"), etl::get<1>(*it)); ++it; CHECK_EQUAL(2U, etl::get<0>(*it)); CHECK_EQUAL(std::string("c"), etl::get<1>(*it)); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_enumerate_view_empty) { std::vector v; auto ev = v | etl::views::enumerate; CHECK(ev.begin() == ev.end()); CHECK_EQUAL(0U, ev.size()); } //************************************************************************* TEST(test_ranges_enumerate_view_size) { std::vector v = {1, 2, 3, 4, 5}; auto ev = v | etl::views::enumerate; CHECK_EQUAL(5U, ev.size()); } //************************************************************************* TEST(test_ranges_enumerate_view_range_for) { std::vector v = {100, 200, 300}; auto ev = v | etl::views::enumerate; size_t expected_index = 0; int expected_values[] = {100, 200, 300}; for (auto&& [idx, val] : ev) { CHECK_EQUAL(expected_index, idx); CHECK_EQUAL(expected_values[expected_index], val); ++expected_index; } CHECK_EQUAL(3U, expected_index); } //************************************************************************* TEST(test_ranges_enumerate_view_chained_with_take) { std::vector v = {10, 20, 30, 40, 50}; auto ev = v | etl::views::enumerate | etl::views::take(3); auto it = ev.begin(); CHECK_EQUAL(0U, etl::get<0>(*it)); CHECK_EQUAL(10, etl::get<1>(*it)); ++it; CHECK_EQUAL(1U, etl::get<0>(*it)); CHECK_EQUAL(20, etl::get<1>(*it)); ++it; CHECK_EQUAL(2U, etl::get<0>(*it)); CHECK_EQUAL(30, etl::get<1>(*it)); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_enumerate_view_single_element) { std::vector v = {42}; auto ev = v | etl::views::enumerate; auto it = ev.begin(); CHECK_EQUAL(0U, etl::get<0>(*it)); CHECK_EQUAL(42, etl::get<1>(*it)); ++it; CHECK(it == ev.end()); } //************************************************************************* TEST(test_ranges_enumerate_view_non_const_reference_type) { // The value element of the tuple must be a mutable reference when the // underlying range is non-const, matching std::ranges::enumerate_view. std::vector v = {10, 20, 30}; auto ev = v | etl::views::enumerate; using value_ref = decltype(etl::get<1>(*ev.begin())); static_assert(etl::is_same::value, "enumerate value element should be a non-const reference"); static_assert(!etl::is_const_v>, "enumerate value element should be mutable"); etl::get<1>(*ev.begin()) = 99; CHECK_EQUAL(99, v[0]); } //************************************************************************* TEST(test_ranges_enumerate_view_modify_elements) { // Add the index to each element in place via structured bindings. std::vector v = {10, 20, 30}; for (auto&& [index, value] : v | etl::views::enumerate) { value += static_cast(index); } std::vector expected{10, 21, 32}; CHECK_EQUAL(expected, v); } //************************************************************************* TEST(test_ranges_zip_view_basic) { std::vector v1 = {1, 2, 3}; std::vector v2 = {"a", "b", "c"}; auto zv = etl::views::zip(v1, v2); auto it = zv.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL(std::string("a"), etl::get<1>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL(std::string("b"), etl::get<1>(*it)); ++it; CHECK_EQUAL(3, etl::get<0>(*it)); CHECK_EQUAL(std::string("c"), etl::get<1>(*it)); ++it; CHECK(it == zv.end()); } //************************************************************************* TEST(test_ranges_zip_view_different_lengths) { std::vector v1 = {1, 2, 3, 4, 5}; std::vector v2 = {10.0, 20.0, 30.0}; auto zv = etl::views::zip(v1, v2); CHECK_EQUAL(3U, zv.size()); auto it = zv.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_CLOSE(10.0, etl::get<1>(*it), 0.01); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_CLOSE(20.0, etl::get<1>(*it), 0.01); ++it; CHECK_EQUAL(3, etl::get<0>(*it)); CHECK_CLOSE(30.0, etl::get<1>(*it), 0.01); ++it; CHECK(it == zv.end()); } //************************************************************************* TEST(test_ranges_zip_view_three_ranges) { std::vector v1 = {1, 2, 3}; std::vector v2 = {1.5, 2.5, 3.5}; std::array v3 = {'x', 'y', 'z'}; auto zv = etl::views::zip(v1, v2, v3); CHECK_EQUAL(3U, zv.size()); auto it = zv.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_CLOSE(1.5, etl::get<1>(*it), 0.01); CHECK_EQUAL('x', etl::get<2>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_CLOSE(2.5, etl::get<1>(*it), 0.01); CHECK_EQUAL('y', etl::get<2>(*it)); ++it; CHECK_EQUAL(3, etl::get<0>(*it)); CHECK_CLOSE(3.5, etl::get<1>(*it), 0.01); CHECK_EQUAL('z', etl::get<2>(*it)); ++it; CHECK(it == zv.end()); } //************************************************************************* TEST(test_ranges_zip_view_empty) { std::vector v1; std::vector v2 = {1.0, 2.0}; auto zv = etl::views::zip(v1, v2); CHECK_EQUAL(0U, zv.size()); CHECK(zv.begin() == zv.end()); } //************************************************************************* TEST(test_ranges_zip_view_single_range) { std::vector v1 = {10, 20, 30}; auto zv = etl::views::zip(v1); CHECK_EQUAL(3U, zv.size()); auto it = zv.begin(); CHECK_EQUAL(10, etl::get<0>(*it)); ++it; CHECK_EQUAL(20, etl::get<0>(*it)); ++it; CHECK_EQUAL(30, etl::get<0>(*it)); ++it; CHECK(it == zv.end()); } //************************************************************************* TEST(test_ranges_zip_view_range_for) { std::vector v1 = {1, 2, 3}; std::vector v2 = {10, 20, 30}; auto zv = etl::views::zip(v1, v2); int expected_first[] = {1, 2, 3}; int expected_second[] = {10, 20, 30}; size_t index = 0; for (auto&& [a, b] : zv) { CHECK_EQUAL(expected_first[index], a); CHECK_EQUAL(expected_second[index], b); ++index; } CHECK_EQUAL(3U, index); } //************************************************************************* TEST(test_ranges_zip_view_with_list) { std::vector v1 = {1, 2, 3, 4}; std::list l1 = {100, 200, 300}; auto zv = etl::views::zip(v1, l1); CHECK_EQUAL(3U, zv.size()); auto it = zv.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL(100, etl::get<1>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL(200, etl::get<1>(*it)); ++it; CHECK_EQUAL(3, etl::get<0>(*it)); CHECK_EQUAL(300, etl::get<1>(*it)); ++it; CHECK(it == zv.end()); } //************************************************************************* TEST(test_ranges_zip_view_chained_with_take) { std::vector v1 = {1, 2, 3, 4, 5}; std::vector v2 = {10, 20, 30, 40, 50}; auto zv = etl::views::zip(v1, v2) | etl::views::take(2); auto it = zv.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL(10, etl::get<1>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL(20, etl::get<1>(*it)); ++it; CHECK(it == zv.end()); } //************************************************************************* TEST(test_ranges_zip_view_non_const_reference_type) { // Each zipped element must be a mutable reference into its source range // when that range is non-const, matching std::ranges::zip_view. std::vector v1 = {1, 2, 3}; std::vector v2 = {'a', 'b', 'c'}; auto zv = etl::views::zip(v1, v2); using first_ref = decltype(etl::get<0>(*zv.begin())); using second_ref = decltype(etl::get<1>(*zv.begin())); static_assert(etl::is_same::value, "zip element 0 should be a non-const reference"); static_assert(etl::is_same::value, "zip element 1 should be a non-const reference"); etl::get<0>(*zv.begin()) = 99; etl::get<1>(*zv.begin()) = 'Z'; CHECK_EQUAL(99, v1[0]); CHECK_EQUAL('Z', v2[0]); } //************************************************************************* TEST(test_ranges_zip_view_modify_elements) { // Write through both zipped ranges in place. std::vector v1 = {1, 2, 3}; std::vector v2 = {10, 20, 30}; for (auto&& [a, b] : etl::views::zip(v1, v2)) { a += 1; b *= 2; } std::vector expected1{2, 3, 4}; std::vector expected2{20, 40, 60}; CHECK_EQUAL(expected1, v1); CHECK_EQUAL(expected2, v2); } //************************************************************************* TEST(test_ranges_zip_transform_view_basic) { std::vector v1 = {1, 2, 3}; std::vector v2 = {10, 20, 30}; auto ztv = etl::views::zip_transform([](int a, int b) { return a + b; }, v1, v2); auto it = ztv.begin(); CHECK_EQUAL(11, *it); ++it; CHECK_EQUAL(22, *it); ++it; CHECK_EQUAL(33, *it); ++it; CHECK(it == ztv.end()); } //************************************************************************* TEST(test_ranges_zip_transform_view_different_lengths) { std::vector v1 = {1, 2, 3, 4, 5}; std::vector v2 = {10.5, 20.5, 30.5}; auto ztv = etl::views::zip_transform([](int a, double b) { return a + b; }, v1, v2); CHECK_EQUAL(3U, ztv.size()); auto it = ztv.begin(); CHECK_CLOSE(11.5, *it, 0.01); ++it; CHECK_CLOSE(22.5, *it, 0.01); ++it; CHECK_CLOSE(33.5, *it, 0.01); ++it; CHECK(it == ztv.end()); } //************************************************************************* TEST(test_ranges_zip_transform_view_three_ranges) { std::vector v1 = {1, 2, 3}; std::vector v2 = {10, 20, 30}; std::vector v3 = {100, 200, 300}; auto ztv = etl::views::zip_transform([](int a, int b, int c) { return a + b + c; }, v1, v2, v3); CHECK_EQUAL(3U, ztv.size()); auto it = ztv.begin(); CHECK_EQUAL(111, *it); ++it; CHECK_EQUAL(222, *it); ++it; CHECK_EQUAL(333, *it); ++it; CHECK(it == ztv.end()); } //************************************************************************* TEST(test_ranges_zip_transform_view_empty) { std::vector v1; std::vector v2 = {1, 2, 3}; auto ztv = etl::views::zip_transform([](int a, int b) { return a * b; }, v1, v2); CHECK_EQUAL(0U, ztv.size()); CHECK(ztv.begin() == ztv.end()); } //************************************************************************* TEST(test_ranges_zip_transform_view_single_range) { std::vector v1 = {10, 20, 30}; auto ztv = etl::views::zip_transform([](int a) { return a * 2; }, v1); CHECK_EQUAL(3U, ztv.size()); auto it = ztv.begin(); CHECK_EQUAL(20, *it); ++it; CHECK_EQUAL(40, *it); ++it; CHECK_EQUAL(60, *it); ++it; CHECK(it == ztv.end()); } //************************************************************************* TEST(test_ranges_zip_transform_view_range_for) { std::vector v1 = {1, 2, 3}; std::vector v2 = {10, 20, 30}; auto ztv = etl::views::zip_transform([](int a, int b) { return a * b; }, v1, v2); int expected[] = {10, 40, 90}; size_t index = 0; for (auto val : ztv) { CHECK_EQUAL(expected[index], val); ++index; } CHECK_EQUAL(3U, index); } //************************************************************************* TEST(test_ranges_zip_transform_view_with_list) { std::vector v1 = {1, 2, 3, 4}; std::list l1 = {100, 200, 300}; auto ztv = etl::views::zip_transform([](int a, int b) { return a + b; }, v1, l1); CHECK_EQUAL(3U, ztv.size()); auto it = ztv.begin(); CHECK_EQUAL(101, *it); ++it; CHECK_EQUAL(202, *it); ++it; CHECK_EQUAL(303, *it); ++it; CHECK(it == ztv.end()); } //************************************************************************* TEST(test_ranges_zip_transform_view_chained_with_take) { std::vector v1 = {1, 2, 3, 4, 5}; std::vector v2 = {10, 20, 30, 40, 50}; auto ztv = etl::views::zip_transform([](int a, int b) { return a + b; }, v1, v2) | etl::views::take(2); auto it = ztv.begin(); CHECK_EQUAL(11, *it); ++it; CHECK_EQUAL(22, *it); ++it; CHECK(it == ztv.end()); } //************************************************************************* TEST(test_ranges_zip_transform_view_string_concat) { std::vector v1 = {"hello", "good", "nice"}; std::vector v2 = {" world", " morning", " day"}; auto ztv = etl::views::zip_transform([](const std::string& a, const std::string& b) { return a + b; }, v1, v2); auto it = ztv.begin(); CHECK_EQUAL(std::string("hello world"), *it); ++it; CHECK_EQUAL(std::string("good morning"), *it); ++it; CHECK_EQUAL(std::string("nice day"), *it); ++it; CHECK(it == ztv.end()); } //************************************************************************* TEST(test_ranges_zip_transform_view_returns_different_type) { std::vector v1 = {1, 2, 3}; std::vector v2 = {4, 5, 6}; auto ztv = etl::views::zip_transform([](int a, int b) -> double { return static_cast(a) / b; }, v1, v2); auto it = ztv.begin(); CHECK_CLOSE(0.25, *it, 0.01); ++it; CHECK_CLOSE(0.4, *it, 0.01); ++it; CHECK_CLOSE(0.5, *it, 0.01); ++it; CHECK(it == ztv.end()); } //************************************************************************* TEST(test_ranges_adjacent_view_basic) { std::vector v = {1, 2, 3, 4, 5}; auto av = etl::views::adjacent<2>(v); CHECK_EQUAL(4U, av.size()); auto it = av.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL(2, etl::get<1>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL(3, etl::get<1>(*it)); ++it; CHECK_EQUAL(3, etl::get<0>(*it)); CHECK_EQUAL(4, etl::get<1>(*it)); ++it; CHECK_EQUAL(4, etl::get<0>(*it)); CHECK_EQUAL(5, etl::get<1>(*it)); ++it; CHECK(it == av.end()); } //************************************************************************* TEST(test_ranges_adjacent_view_triple) { std::vector v = {10, 20, 30, 40, 50}; auto av = etl::views::adjacent<3>(v); CHECK_EQUAL(3U, av.size()); auto it = av.begin(); CHECK_EQUAL(10, etl::get<0>(*it)); CHECK_EQUAL(20, etl::get<1>(*it)); CHECK_EQUAL(30, etl::get<2>(*it)); ++it; CHECK_EQUAL(20, etl::get<0>(*it)); CHECK_EQUAL(30, etl::get<1>(*it)); CHECK_EQUAL(40, etl::get<2>(*it)); ++it; CHECK_EQUAL(30, etl::get<0>(*it)); CHECK_EQUAL(40, etl::get<1>(*it)); CHECK_EQUAL(50, etl::get<2>(*it)); ++it; CHECK(it == av.end()); } //************************************************************************* TEST(test_ranges_adjacent_view_single_window) { std::vector v = {1}; auto av = etl::views::adjacent<1>(v); CHECK_EQUAL(1U, av.size()); auto it = av.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); ++it; CHECK(it == av.end()); } //************************************************************************* TEST(test_ranges_adjacent_view_window_equals_range_size) { std::vector v = {1, 2, 3}; auto av = etl::views::adjacent<3>(v); CHECK_EQUAL(1U, av.size()); auto it = av.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL(2, etl::get<1>(*it)); CHECK_EQUAL(3, etl::get<2>(*it)); ++it; CHECK(it == av.end()); } //************************************************************************* TEST(test_ranges_adjacent_view_window_larger_than_range) { std::vector v = {1, 2}; auto av = etl::views::adjacent<5>(v); CHECK_EQUAL(0U, av.size()); CHECK(av.begin() == av.end()); } //************************************************************************* TEST(test_ranges_adjacent_view_empty_range) { std::vector v; auto av = etl::views::adjacent<2>(v); CHECK_EQUAL(0U, av.size()); CHECK(av.begin() == av.end()); } //************************************************************************* TEST(test_ranges_adjacent_view_range_for) { std::vector v = {1, 2, 3, 4}; auto av = etl::views::adjacent<2>(v); std::vector firsts; std::vector seconds; for (auto [a, b] : av) { firsts.push_back(a); seconds.push_back(b); } CHECK_EQUAL(3U, firsts.size()); CHECK_EQUAL(1, firsts[0]); CHECK_EQUAL(2, firsts[1]); CHECK_EQUAL(3, firsts[2]); CHECK_EQUAL(2, seconds[0]); CHECK_EQUAL(3, seconds[1]); CHECK_EQUAL(4, seconds[2]); } //************************************************************************* TEST(test_ranges_adjacent_view_pairwise) { std::vector v = {1, 2, 3, 4}; auto av = etl::views::pairwise(v); CHECK_EQUAL(3U, av.size()); auto it = av.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL(2, etl::get<1>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL(3, etl::get<1>(*it)); ++it; CHECK_EQUAL(3, etl::get<0>(*it)); CHECK_EQUAL(4, etl::get<1>(*it)); ++it; CHECK(it == av.end()); } //************************************************************************* TEST(test_ranges_adjacent_view_pipe) { std::vector v = {10, 20, 30, 40, 50}; auto av = v | etl::views::adjacent<2>(); CHECK_EQUAL(4U, av.size()); auto it = av.begin(); CHECK_EQUAL(10, etl::get<0>(*it)); CHECK_EQUAL(20, etl::get<1>(*it)); ++it; CHECK_EQUAL(20, etl::get<0>(*it)); CHECK_EQUAL(30, etl::get<1>(*it)); ++it; CHECK_EQUAL(30, etl::get<0>(*it)); CHECK_EQUAL(40, etl::get<1>(*it)); ++it; CHECK_EQUAL(40, etl::get<0>(*it)); CHECK_EQUAL(50, etl::get<1>(*it)); ++it; CHECK(it == av.end()); } //************************************************************************* TEST(test_ranges_adjacent_view_chained_with_take) { std::vector v = {1, 2, 3, 4, 5}; auto av = v | etl::views::adjacent<2>() | etl::views::take(2); auto it = av.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL(2, etl::get<1>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL(3, etl::get<1>(*it)); ++it; CHECK(it == av.end()); } //************************************************************************* TEST(test_ranges_adjacent_view_with_strings) { std::vector v = {"a", "b", "c", "d"}; auto av = etl::views::adjacent<2>(v); CHECK_EQUAL(3U, av.size()); auto it = av.begin(); CHECK_EQUAL(std::string("a"), etl::get<0>(*it)); CHECK_EQUAL(std::string("b"), etl::get<1>(*it)); ++it; CHECK_EQUAL(std::string("b"), etl::get<0>(*it)); CHECK_EQUAL(std::string("c"), etl::get<1>(*it)); ++it; CHECK_EQUAL(std::string("c"), etl::get<0>(*it)); CHECK_EQUAL(std::string("d"), etl::get<1>(*it)); ++it; CHECK(it == av.end()); } //************************************************************************* TEST(test_ranges_adjacent_view_quad) { std::vector v = {1, 2, 3, 4, 5, 6}; auto av = etl::views::adjacent<4>(v); CHECK_EQUAL(3U, av.size()); auto it = av.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL(2, etl::get<1>(*it)); CHECK_EQUAL(3, etl::get<2>(*it)); CHECK_EQUAL(4, etl::get<3>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL(3, etl::get<1>(*it)); CHECK_EQUAL(4, etl::get<2>(*it)); CHECK_EQUAL(5, etl::get<3>(*it)); ++it; CHECK_EQUAL(3, etl::get<0>(*it)); CHECK_EQUAL(4, etl::get<1>(*it)); CHECK_EQUAL(5, etl::get<2>(*it)); CHECK_EQUAL(6, etl::get<3>(*it)); ++it; CHECK(it == av.end()); } //************************************************************************* TEST(test_ranges_adjacent_view_non_const_reference_type) { // Each window element must be a mutable reference into the underlying // range when it is non-const, matching std::ranges::adjacent_view. std::vector v = {1, 2, 3}; auto av = etl::views::adjacent<2>(v); using first_ref = decltype(etl::get<0>(*av.begin())); using second_ref = decltype(etl::get<1>(*av.begin())); static_assert(etl::is_same::value, "adjacent element 0 should be a non-const reference"); static_assert(etl::is_same::value, "adjacent element 1 should be a non-const reference"); etl::get<0>(*av.begin()) = 99; CHECK_EQUAL(99, v[0]); } //************************************************************************* TEST(test_ranges_adjacent_view_modify_elements) { // Negate the first element of every adjacent pair in place. Each element // 0..n-2 is the start of exactly one window; the last element is only a // second member, so it is left unchanged. std::vector v = {1, 2, 3, 4}; for (auto&& window : etl::views::adjacent<2>(v)) { etl::get<0>(window) = -etl::get<0>(window); } std::vector expected{-1, -2, -3, 4}; CHECK_EQUAL(expected, v); } //************************************************************************* TEST(test_ranges_adjacent_transform_view_basic_sum) { std::vector v = {1, 2, 3, 4, 5}; auto atv = etl::views::adjacent_transform<2>(v, [](int a, int b) { return a + b; }); CHECK_EQUAL(4U, atv.size()); auto it = atv.begin(); CHECK_EQUAL(3, *it); // 1+2 ++it; CHECK_EQUAL(5, *it); // 2+3 ++it; CHECK_EQUAL(7, *it); // 3+4 ++it; CHECK_EQUAL(9, *it); // 4+5 ++it; CHECK(it == atv.end()); } //************************************************************************* TEST(test_ranges_adjacent_transform_view_triple_product) { std::vector v = {1, 2, 3, 4, 5}; auto atv = etl::views::adjacent_transform<3>(v, [](int a, int b, int c) { return a * b * c; }); CHECK_EQUAL(3U, atv.size()); auto it = atv.begin(); CHECK_EQUAL(6, *it); // 1*2*3 ++it; CHECK_EQUAL(24, *it); // 2*3*4 ++it; CHECK_EQUAL(60, *it); // 3*4*5 ++it; CHECK(it == atv.end()); } //************************************************************************* TEST(test_ranges_adjacent_transform_view_single_window) { std::vector v = {10, 20, 30}; // Window size 1: function applied to each element individually auto atv = etl::views::adjacent_transform<1>(v, [](int a) { return a * 2; }); CHECK_EQUAL(3U, atv.size()); auto it = atv.begin(); CHECK_EQUAL(20, *it); ++it; CHECK_EQUAL(40, *it); ++it; CHECK_EQUAL(60, *it); ++it; CHECK(it == atv.end()); } //************************************************************************* TEST(test_ranges_adjacent_transform_view_window_equals_range_size) { std::vector v = {1, 2, 3}; auto atv = etl::views::adjacent_transform<3>(v, [](int a, int b, int c) { return a + b + c; }); CHECK_EQUAL(1U, atv.size()); auto it = atv.begin(); CHECK_EQUAL(6, *it); // 1+2+3 ++it; CHECK(it == atv.end()); } //************************************************************************* TEST(test_ranges_adjacent_transform_view_window_larger_than_range) { std::vector v = {1, 2}; auto atv = etl::views::adjacent_transform<3>(v, [](int a, int b, int c) { return a + b + c; }); CHECK_EQUAL(0U, atv.size()); CHECK(atv.begin() == atv.end()); } //************************************************************************* TEST(test_ranges_adjacent_transform_view_empty_range) { std::vector v = {}; auto atv = etl::views::adjacent_transform<2>(v, [](int a, int b) { return a + b; }); CHECK_EQUAL(0U, atv.size()); CHECK(atv.begin() == atv.end()); } //************************************************************************* TEST(test_ranges_adjacent_transform_view_range_for) { std::vector v = {1, 2, 3, 4, 5}; std::vector expected = {3, 5, 7, 9}; auto atv = etl::views::adjacent_transform<2>(v, [](int a, int b) { return a + b; }); std::vector result; for (auto val : atv) { result.push_back(val); } CHECK_EQUAL(expected.size(), result.size()); for (size_t i = 0; i < expected.size(); ++i) { CHECK_EQUAL(expected[i], result[i]); } } //************************************************************************* TEST(test_ranges_adjacent_transform_view_pairwise_transform) { std::vector v = {10, 20, 30, 40}; auto atv = etl::views::pairwise_transform(v, [](int a, int b) { return b - a; }); CHECK_EQUAL(3U, atv.size()); auto it = atv.begin(); CHECK_EQUAL(10, *it); // 20-10 ++it; CHECK_EQUAL(10, *it); // 30-20 ++it; CHECK_EQUAL(10, *it); // 40-30 ++it; CHECK(it == atv.end()); } //************************************************************************* TEST(test_ranges_adjacent_transform_view_pipe) { std::vector v = {1, 2, 3, 4, 5}; auto sum = [](int a, int b) { return a + b; }; auto atv = v | etl::views::adjacent_transform<2>(sum); CHECK_EQUAL(4U, atv.size()); auto it = atv.begin(); CHECK_EQUAL(3, *it); // 1+2 ++it; CHECK_EQUAL(5, *it); // 2+3 ++it; CHECK_EQUAL(7, *it); // 3+4 ++it; CHECK_EQUAL(9, *it); // 4+5 ++it; CHECK(it == atv.end()); } //************************************************************************* TEST(test_ranges_adjacent_transform_view_chained_with_take) { std::vector v = {1, 2, 3, 4, 5}; auto sum = [](int a, int b) { return a + b; }; auto atv = v | etl::views::adjacent_transform<2>(sum) | etl::views::take(2); auto it = atv.begin(); CHECK_EQUAL(3, *it); // 1+2 ++it; CHECK_EQUAL(5, *it); // 2+3 ++it; CHECK(it == atv.end()); } //************************************************************************* TEST(test_ranges_adjacent_transform_view_different_return_type) { std::vector v = {1, 2, 3, 4}; // Returns double instead of int auto avg = [](int a, int b) { return (a + b) / 2.0; }; auto atv = etl::views::adjacent_transform<2>(v, avg); CHECK_EQUAL(3U, atv.size()); auto it = atv.begin(); CHECK_CLOSE(1.5, *it, 0.001); // (1+2)/2.0 ++it; CHECK_CLOSE(2.5, *it, 0.001); // (2+3)/2.0 ++it; CHECK_CLOSE(3.5, *it, 0.001); // (3+4)/2.0 ++it; CHECK(it == atv.end()); } //************************************************************************* TEST(test_ranges_adjacent_transform_view_pairwise_transform_pipe) { std::vector v = {5, 10, 15, 20}; auto diff = [](int a, int b) { return b - a; }; auto atv = v | etl::views::pairwise_transform(diff); CHECK_EQUAL(3U, atv.size()); auto it = atv.begin(); CHECK_EQUAL(5, *it); ++it; CHECK_EQUAL(5, *it); ++it; CHECK_EQUAL(5, *it); ++it; CHECK(it == atv.end()); } //************************************************************************* TEST(test_ranges_chunk_view_basic) { std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; auto cv = etl::ranges::chunk_view(v, 3); std::vector> expected{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_view_rvalue_range_owning_view) { // Chunking an rvalue range stores it in an owning_view (by value). // The owning_view's const begin()/end() must still yield the mutable // 'iterator' rather than a 'const_iterator', otherwise instantiation fails. auto cv = etl::ranges::views::chunk(std::vector{1, 2, 3, 4, 5, 6, 7}, 3); std::vector> expected{{1, 2, 3}, {4, 5, 6}, {7}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_view_remainder) { // Range size not evenly divisible by chunk size std::vector v = {1, 2, 3, 4, 5, 6, 7}; auto cv = etl::ranges::chunk_view(v, 3); std::vector> expected{{1, 2, 3}, {4, 5, 6}, {7}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_view_single_element_chunks) { std::vector v = {10, 20, 30}; auto cv = etl::ranges::chunk_view(v, 1); std::vector> expected{{10}, {20}, {30}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_view_chunk_larger_than_range) { std::vector v = {1, 2, 3}; auto cv = etl::ranges::chunk_view(v, 10); size_t count = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); std::vector expected{1, 2, 3}; CHECK_EQUAL(expected, actual); ++count; } CHECK_EQUAL(1U, count); } //************************************************************************* TEST(test_ranges_chunk_view_empty_range) { std::vector v; auto cv = etl::ranges::chunk_view(v, 3); size_t count = 0; for (auto chunk : cv) { (void)chunk; ++count; } CHECK_EQUAL(0U, count); } //************************************************************************* TEST(test_ranges_chunk_view_pipe) { std::vector v = {1, 2, 3, 4, 5, 6}; auto cv = v | etl::views::chunk(2); std::vector> expected{{1, 2}, {3, 4}, {5, 6}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_view_pipe_with_remainder) { std::vector v = {1, 2, 3, 4, 5}; auto cv = v | etl::views::chunk(2); std::vector> expected{{1, 2}, {3, 4}, {5}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_view_functional_call) { std::vector v = {1, 2, 3, 4, 5, 6}; auto cv = etl::views::chunk(v, 3); std::vector> expected{{1, 2, 3}, {4, 5, 6}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_view_etl_vector) { etl::vector v = {1, 2, 3, 4, 5, 6, 7, 8}; auto cv = etl::ranges::chunk_view(v, 3); std::vector> expected{{1, 2, 3}, {4, 5, 6}, {7, 8}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_view_array) { std::array a = {10, 20, 30, 40, 50, 60}; auto cv = etl::ranges::chunk_view(a, 2); std::vector> expected{{10, 20}, {30, 40}, {50, 60}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_view_pipe_chain_take_chunk) { // Take first 6, then chunk by 2 std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; auto cv = v | etl::views::take(6) | etl::views::chunk(2); std::vector> expected{{1, 2}, {3, 4}, {5, 6}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_view_pipe_chain_drop_chunk) { // Drop first 2, then chunk by 3 std::vector v = {1, 2, 3, 4, 5, 6, 7, 8}; auto cv = v | etl::views::drop(2) | etl::views::chunk(3); std::vector> expected{{3, 4, 5}, {6, 7, 8}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_view_non_const_reference_type) { // The chunk elements must expose a non-const iterator/reference when the // underlying range is non-const, matching std::ranges::chunk_view. std::vector v = {1, 2, 3, 4}; auto cv = etl::ranges::chunk_view(v, 2); auto first_chunk = *cv.begin(); using element_ref = decltype(*first_chunk.begin()); static_assert(etl::is_same::value, "chunk element should be a non-const reference"); static_assert(!etl::is_const_v>, "chunk element should be mutable"); // Prove it at runtime by writing through the chunk. *first_chunk.begin() = 99; CHECK_EQUAL(99, v[0]); } //************************************************************************* TEST(test_ranges_chunk_view_modify_elements) { // Write through the chunks and verify the underlying range is mutated. std::vector v = {1, 2, 3, 4, 5, 6, 7}; auto cv = etl::ranges::chunk_view(v, 3); for (auto chunk : cv) { for (auto& element : chunk) { element *= 2; } } std::vector expected{2, 4, 6, 8, 10, 12, 14}; CHECK_EQUAL(expected, v); } //************************************************************************* TEST(test_ranges_chunk_view_modify_elements_pipe) { // Write through chunks produced via the pipe syntax. std::vector v = {10, 20, 30, 40, 50}; for (auto chunk : v | etl::views::chunk(2)) { for (auto& element : chunk) { element += 1; } } std::vector expected{11, 21, 31, 41, 51}; CHECK_EQUAL(expected, v); } //************************************************************************* TEST(test_ranges_chunk_view_modify_elements_etl_vector) { // Non-const access also works with ETL containers. etl::vector v = {1, 2, 3, 4, 5, 6}; auto cv = etl::ranges::chunk_view(v, 2); for (auto chunk : cv) { for (auto& element : chunk) { element = -element; } } etl::vector expected = {-1, -2, -3, -4, -5, -6}; CHECK(expected == v); } //************************************************************************* // slide_view tests //************************************************************************* //************************************************************************* TEST(test_ranges_slide_view_basic) { std::vector v = {1, 2, 3, 4, 5}; auto sv = etl::ranges::slide_view(v, 3); std::vector> expected{{1, 2, 3}, {2, 3, 4}, {3, 4, 5}}; size_t idx = 0; for (auto window : sv) { std::vector actual(window.begin(), window.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_slide_view_window_size_1) { std::vector v = {10, 20, 30}; auto sv = etl::ranges::slide_view(v, 1); std::vector> expected{{10}, {20}, {30}}; size_t idx = 0; for (auto window : sv) { std::vector actual(window.begin(), window.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_slide_view_window_equals_range) { std::vector v = {1, 2, 3}; auto sv = etl::ranges::slide_view(v, 3); size_t count = 0; for (auto window : sv) { std::vector actual(window.begin(), window.end()); std::vector expected{1, 2, 3}; CHECK_EQUAL(expected, actual); ++count; } CHECK_EQUAL(1U, count); } //************************************************************************* TEST(test_ranges_slide_view_window_larger_than_range) { std::vector v = {1, 2, 3}; auto sv = etl::ranges::slide_view(v, 5); size_t count = 0; for (auto window : sv) { (void)window; ++count; } CHECK_EQUAL(0U, count); } //************************************************************************* TEST(test_ranges_slide_view_empty_range) { std::vector v; auto sv = etl::ranges::slide_view(v, 3); size_t count = 0; for (auto window : sv) { (void)window; ++count; } CHECK_EQUAL(0U, count); } //************************************************************************* TEST(test_ranges_slide_view_size) { std::vector v = {1, 2, 3, 4, 5}; CHECK_EQUAL(3U, etl::ranges::slide_view(v, 3).size()); CHECK_EQUAL(5U, etl::ranges::slide_view(v, 1).size()); CHECK_EQUAL(1U, etl::ranges::slide_view(v, 5).size()); CHECK_EQUAL(0U, etl::ranges::slide_view(v, 6).size()); } //************************************************************************* TEST(test_ranges_slide_view_pipe) { std::vector v = {1, 2, 3, 4, 5}; auto sv = v | etl::views::slide(3); std::vector> expected{{1, 2, 3}, {2, 3, 4}, {3, 4, 5}}; size_t idx = 0; for (auto window : sv) { std::vector actual(window.begin(), window.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_slide_view_functional_call) { std::vector v = {1, 2, 3, 4, 5}; auto sv = etl::views::slide(v, 2); std::vector> expected{{1, 2}, {2, 3}, {3, 4}, {4, 5}}; size_t idx = 0; for (auto window : sv) { std::vector actual(window.begin(), window.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_slide_view_etl_vector) { etl::vector v = {1, 2, 3, 4, 5, 6}; auto sv = etl::ranges::slide_view(v, 4); std::vector> expected{{1, 2, 3, 4}, {2, 3, 4, 5}, {3, 4, 5, 6}}; size_t idx = 0; for (auto window : sv) { std::vector actual(window.begin(), window.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_slide_view_array) { std::array a = {10, 20, 30, 40, 50}; auto sv = etl::ranges::slide_view(a, 2); std::vector> expected{{10, 20}, {20, 30}, {30, 40}, {40, 50}}; size_t idx = 0; for (auto window : sv) { std::vector actual(window.begin(), window.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_slide_view_pipe_chain_take_slide) { // Take first 5, then slide with window 3 std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; auto sv = v | etl::views::take(5) | etl::views::slide(3); std::vector> expected{{1, 2, 3}, {2, 3, 4}, {3, 4, 5}}; size_t idx = 0; for (auto window : sv) { std::vector actual(window.begin(), window.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_slide_view_pipe_chain_drop_slide) { // Drop first 2, then slide with window 3 std::vector v = {1, 2, 3, 4, 5, 6, 7}; auto sv = v | etl::views::drop(2) | etl::views::slide(3); std::vector> expected{{3, 4, 5}, {4, 5, 6}, {5, 6, 7}}; size_t idx = 0; for (auto window : sv) { std::vector actual(window.begin(), window.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_slide_view_non_const_reference_type) { // A slide window must expose mutable element references when the // underlying range is non-const, matching std::ranges::slide_view. std::vector v = {1, 2, 3, 4}; auto sv = etl::ranges::slide_view(v, 2); auto first_window = *sv.begin(); using element_ref = decltype(*first_window.begin()); static_assert(etl::is_same::value, "slide window element should be a non-const reference"); static_assert(!etl::is_const_v>, "slide window element should be mutable"); *first_window.begin() = 99; CHECK_EQUAL(99, v[0]); } //************************************************************************* TEST(test_ranges_slide_view_modify_elements) { // Each underlying element is the start of exactly one window, so writing // through the first element of every window doubles all but the tail. std::vector v = {1, 2, 3, 4, 5}; auto sv = etl::ranges::slide_view(v, 2); for (auto window : sv) { auto it = window.begin(); *it *= 2; } // Windows start at indices 0..3, so the final element is untouched. std::vector expected{2, 4, 6, 8, 5}; CHECK_EQUAL(expected, v); } //************************************************************************* // chunk_by_view tests //************************************************************************* //************************************************************************* TEST(test_ranges_chunk_by_view_basic) { // Group consecutive equal elements std::vector v = {1, 1, 2, 2, 2, 3, 3, 1}; auto cv = etl::ranges::chunk_by_view(v, [](int a, int b) { return a == b; }); std::vector> expected{{1, 1}, {2, 2, 2}, {3, 3}, {1}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_by_view_less_than) { // Split where values stop being strictly increasing std::vector v = {1, 2, 3, 1, 2, 1}; auto cv = etl::ranges::chunk_by_view(v, [](int a, int b) { return a < b; }); std::vector> expected{{1, 2, 3}, {1, 2}, {1}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_by_view_single_element) { std::vector v = {42}; auto cv = etl::ranges::chunk_by_view(v, [](int a, int b) { return a == b; }); size_t count = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); std::vector expected{42}; CHECK_EQUAL(expected, actual); ++count; } CHECK_EQUAL(1U, count); } //************************************************************************* TEST(test_ranges_chunk_by_view_empty_range) { std::vector v; auto cv = etl::ranges::chunk_by_view(v, [](int a, int b) { return a == b; }); size_t count = 0; for (auto chunk : cv) { (void)chunk; ++count; } CHECK_EQUAL(0U, count); } //************************************************************************* TEST(test_ranges_chunk_by_view_all_same) { // All elements satisfy predicate => single chunk std::vector v = {5, 5, 5, 5}; auto cv = etl::ranges::chunk_by_view(v, [](int a, int b) { return a == b; }); size_t count = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); std::vector expected{5, 5, 5, 5}; CHECK_EQUAL(expected, actual); ++count; } CHECK_EQUAL(1U, count); } //************************************************************************* TEST(test_ranges_chunk_by_view_all_different) { // No adjacent pair satisfies predicate => each element is its own chunk std::vector v = {1, 2, 1, 2, 1}; auto cv = etl::ranges::chunk_by_view(v, [](int a, int b) { return a == b; }); std::vector> expected{{1}, {2}, {1}, {2}, {1}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_by_view_pipe) { std::vector v = {1, 1, 2, 2, 3}; auto cv = v | etl::views::chunk_by([](int a, int b) { return a == b; }); std::vector> expected{{1, 1}, {2, 2}, {3}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_by_view_functional_call) { std::vector v = {1, 2, 3, 1, 2}; auto cv = etl::views::chunk_by(v, [](int a, int b) { return a < b; }); std::vector> expected{{1, 2, 3}, {1, 2}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_by_view_etl_vector) { etl::vector v = {1, 1, 2, 3, 3}; auto cv = etl::ranges::chunk_by_view(v, [](int a, int b) { return a == b; }); std::vector> expected{{1, 1}, {2}, {3, 3}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_by_view_array) { std::array a = {1, 1, 2, 2, 3, 3}; auto cv = etl::ranges::chunk_by_view(a, [](int x, int y) { return x == y; }); std::vector> expected{{1, 1}, {2, 2}, {3, 3}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_by_view_pipe_chain_take_chunk_by) { // Take first 5, then chunk_by equal std::vector v = {1, 1, 2, 2, 3, 3, 4}; auto cv = v | etl::views::take(5) | etl::views::chunk_by([](int a, int b) { return a == b; }); std::vector> expected{{1, 1}, {2, 2}, {3}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_by_view_pipe_chain_drop_chunk_by) { // Drop first 2, then chunk_by strictly increasing std::vector v = {1, 1, 2, 3, 1, 2}; auto cv = v | etl::views::drop(2) | etl::views::chunk_by([](int a, int b) { return a < b; }); std::vector> expected{{2, 3}, {1, 2}}; size_t idx = 0; for (auto chunk : cv) { std::vector actual(chunk.begin(), chunk.end()); CHECK_EQUAL(expected[idx], actual); ++idx; } CHECK_EQUAL(expected.size(), idx); } //************************************************************************* TEST(test_ranges_chunk_by_view_non_const_reference_type) { // chunk_by chunks must expose mutable element references when the // underlying range is non-const, matching std::ranges::chunk_by_view. std::vector v = {1, 1, 2}; auto cv = etl::ranges::chunk_by_view(v, [](int a, int b) { return a == b; }); auto first_chunk = *cv.begin(); using element_ref = decltype(*first_chunk.begin()); static_assert(etl::is_same::value, "chunk_by element should be a non-const reference"); static_assert(!etl::is_const_v>, "chunk_by element should be mutable"); *first_chunk.begin() = 99; CHECK_EQUAL(99, v[0]); } //************************************************************************* TEST(test_ranges_chunk_by_view_modify_elements) { // Group consecutive equal elements, then negate every element in place. // Each chunk boundary is computed from the chunk start forwards before // that chunk's elements are modified, so the grouping stays correct. std::vector v = {1, 1, 2, 2, 2, 3}; auto cv = etl::ranges::chunk_by_view(v, [](int a, int b) { return a == b; }); for (auto chunk : cv) { for (auto& element : chunk) { element = -element; } } std::vector expected{-1, -1, -2, -2, -2, -3}; CHECK_EQUAL(expected, v); } //************************************************************************* // stride_view tests //************************************************************************* //************************************************************************* TEST(test_ranges_stride_view_basic) { std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; auto sv = etl::ranges::stride_view(v, 3); std::vector expected{1, 4, 7}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_stride_of_one) { std::vector v = {10, 20, 30}; auto sv = etl::ranges::stride_view(v, 1); std::vector expected{10, 20, 30}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_stride_of_two) { std::vector v = {1, 2, 3, 4, 5, 6}; auto sv = etl::ranges::stride_view(v, 2); std::vector expected{1, 3, 5}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_stride_larger_than_range) { std::vector v = {1, 2, 3}; auto sv = etl::ranges::stride_view(v, 10); std::vector expected{1}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_stride_equals_range_size) { std::vector v = {1, 2, 3}; auto sv = etl::ranges::stride_view(v, 3); std::vector expected{1}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_empty_range) { std::vector v; auto sv = etl::ranges::stride_view(v, 3); size_t count = 0; for (auto val : sv) { (void)val; ++count; } CHECK_EQUAL(0U, count); } //************************************************************************* TEST(test_ranges_stride_view_single_element) { std::vector v = {42}; auto sv = etl::ranges::stride_view(v, 5); std::vector expected{42}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_pipe) { std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; auto sv = v | etl::views::stride(3); std::vector expected{1, 4, 7}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_pipe_stride_of_two) { std::vector v = {10, 20, 30, 40, 50}; auto sv = v | etl::views::stride(2); std::vector expected{10, 30, 50}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_functional_call) { std::vector v = {1, 2, 3, 4, 5, 6}; auto sv = etl::views::stride(v, 2); std::vector expected{1, 3, 5}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_etl_vector) { etl::vector v = {1, 2, 3, 4, 5, 6, 7, 8}; auto sv = etl::ranges::stride_view(v, 3); std::vector expected{1, 4, 7}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_array) { std::array a = {10, 20, 30, 40, 50, 60}; auto sv = etl::ranges::stride_view(a, 2); std::vector expected{10, 30, 50}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_not_evenly_divisible) { std::vector v = {1, 2, 3, 4, 5, 6, 7}; auto sv = etl::ranges::stride_view(v, 3); std::vector expected{1, 4, 7}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_pipe_chain_take_stride) { // Take first 6, then stride by 2 std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; auto sv = v | etl::views::take(6) | etl::views::stride(2); std::vector expected{1, 3, 5}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_pipe_chain_drop_stride) { // Drop first 2, then stride by 3 std::vector v = {1, 2, 3, 4, 5, 6, 7, 8, 9}; auto sv = v | etl::views::drop(2) | etl::views::stride(3); std::vector expected{3, 6, 9}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_pipe_chain_stride_transform) { // Stride by 2, then transform (multiply by 10) std::vector v = {1, 2, 3, 4, 5}; auto mul10 = [](int x) { return x * 10; }; auto sv = v | etl::views::stride(2) | etl::views::transform(mul10); std::vector expected{10, 30, 50}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_pipe_chain_filter_stride) { // Filter even, then stride by 2 std::vector v = {1, 2, 3, 4, 5, 6, 7, 8}; auto is_even = [](int x) { return x % 2 == 0; }; auto sv = v | etl::views::filter(is_even) | etl::views::stride(2); std::vector expected{2, 6}; std::vector actual; for (auto val : sv) { actual.push_back(val); } CHECK_EQUAL(expected, actual); } //************************************************************************* TEST(test_ranges_stride_view_non_const_reference_type) { // stride must yield mutable element references when the underlying range // is non-const, matching std::ranges::stride_view. std::vector v = {1, 2, 3, 4}; auto sv = etl::ranges::stride_view(v, 2); using element_ref = decltype(*sv.begin()); static_assert(etl::is_same::value, "stride element should be a non-const reference"); static_assert(!etl::is_const_v>, "stride element should be mutable"); *sv.begin() = 99; CHECK_EQUAL(99, v[0]); } //************************************************************************* TEST(test_ranges_stride_view_modify_elements) { // Stride by 2 and double every visited element in place. std::vector v = {1, 2, 3, 4, 5, 6}; auto sv = etl::ranges::stride_view(v, 2); for (auto& element : sv) { element *= 2; } // Elements at indices 0, 2, 4 are visited (1, 3, 5 -> 2, 6, 10). std::vector expected{2, 2, 6, 4, 10, 6}; CHECK_EQUAL(expected, v); } //************************************************************************* TEST(test_ranges_cartesian_product_view_basic) { std::vector v1 = {1, 2}; std::vector v2 = {"a", "b", "c"}; auto cp = etl::views::cartesian_product(v1, v2); auto it = cp.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL(std::string("a"), etl::get<1>(*it)); ++it; CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL(std::string("b"), etl::get<1>(*it)); ++it; CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL(std::string("c"), etl::get<1>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL(std::string("a"), etl::get<1>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL(std::string("b"), etl::get<1>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL(std::string("c"), etl::get<1>(*it)); ++it; CHECK(it == cp.end()); } //************************************************************************* TEST(test_ranges_cartesian_product_view_size) { std::vector v1 = {1, 2, 3}; std::vector v2 = {10, 20}; auto cp = etl::views::cartesian_product(v1, v2); CHECK_EQUAL(6U, cp.size()); } //************************************************************************* TEST(test_ranges_cartesian_product_view_three_ranges) { std::vector v1 = {1, 2}; std::vector v2 = {'a', 'b'}; std::vector v3 = {0.5}; auto cp = etl::views::cartesian_product(v1, v2, v3); CHECK_EQUAL(4U, cp.size()); std::vector> expected = {{1, 'a', 0.5}, {1, 'b', 0.5}, {2, 'a', 0.5}, {2, 'b', 0.5}}; size_t idx = 0; for (auto val : cp) { CHECK_EQUAL(etl::get<0>(expected[idx]), etl::get<0>(val)); CHECK_EQUAL(etl::get<1>(expected[idx]), etl::get<1>(val)); CHECK_CLOSE(etl::get<2>(expected[idx]), etl::get<2>(val), 0.01); ++idx; } CHECK_EQUAL(4U, idx); } //************************************************************************* TEST(test_ranges_cartesian_product_view_empty_range) { std::vector v1 = {1, 2, 3}; std::vector v2; auto cp = etl::views::cartesian_product(v1, v2); CHECK_EQUAL(0U, cp.size()); CHECK(cp.begin() == cp.end()); } //************************************************************************* TEST(test_ranges_cartesian_product_view_single_range) { std::vector v1 = {10, 20, 30}; auto cp = etl::views::cartesian_product(v1); CHECK_EQUAL(3U, cp.size()); auto it = cp.begin(); CHECK_EQUAL(10, etl::get<0>(*it)); ++it; CHECK_EQUAL(20, etl::get<0>(*it)); ++it; CHECK_EQUAL(30, etl::get<0>(*it)); ++it; CHECK(it == cp.end()); } //************************************************************************* TEST(test_ranges_cartesian_product_view_range_for) { std::vector v1 = {1, 2}; std::vector v2 = {10, 20}; auto cp = etl::views::cartesian_product(v1, v2); std::vector> result; for (auto val : cp) { result.push_back(val); } CHECK_EQUAL(4U, result.size()); CHECK_EQUAL(1, etl::get<0>(result[0])); CHECK_EQUAL(10, etl::get<1>(result[0])); CHECK_EQUAL(1, etl::get<0>(result[1])); CHECK_EQUAL(20, etl::get<1>(result[1])); CHECK_EQUAL(2, etl::get<0>(result[2])); CHECK_EQUAL(10, etl::get<1>(result[2])); CHECK_EQUAL(2, etl::get<0>(result[3])); CHECK_EQUAL(20, etl::get<1>(result[3])); } //************************************************************************* TEST(test_ranges_cartesian_product_view_with_array) { std::array a1 = {1, 2}; std::array a2 = {'x', 'y', 'z'}; auto cp = etl::views::cartesian_product(a1, a2); CHECK_EQUAL(6U, cp.size()); auto it = cp.begin(); CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL('x', etl::get<1>(*it)); ++it; CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL('y', etl::get<1>(*it)); ++it; CHECK_EQUAL(1, etl::get<0>(*it)); CHECK_EQUAL('z', etl::get<1>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL('x', etl::get<1>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL('y', etl::get<1>(*it)); ++it; CHECK_EQUAL(2, etl::get<0>(*it)); CHECK_EQUAL('z', etl::get<1>(*it)); ++it; CHECK(it == cp.end()); } //************************************************************************* TEST(test_ranges_cartesian_product_view_chained_with_take) { std::vector v1 = {1, 2, 3}; std::vector v2 = {10, 20, 30}; auto cp = etl::views::cartesian_product(v1, v2) | etl::views::take(4); std::vector> result; for (auto val : cp) { result.push_back(val); } CHECK_EQUAL(4U, result.size()); CHECK_EQUAL(1, etl::get<0>(result[0])); CHECK_EQUAL(10, etl::get<1>(result[0])); CHECK_EQUAL(1, etl::get<0>(result[1])); CHECK_EQUAL(20, etl::get<1>(result[1])); CHECK_EQUAL(1, etl::get<0>(result[2])); CHECK_EQUAL(30, etl::get<1>(result[2])); CHECK_EQUAL(2, etl::get<0>(result[3])); CHECK_EQUAL(10, etl::get<1>(result[3])); } //************************************************************************* TEST(test_ranges_cartesian_product_view_single_elements) { std::vector v1 = {42}; std::vector v2 = {'z'}; auto cp = etl::views::cartesian_product(v1, v2); CHECK_EQUAL(1U, cp.size()); auto it = cp.begin(); CHECK_EQUAL(42, etl::get<0>(*it)); CHECK_EQUAL('z', etl::get<1>(*it)); ++it; CHECK(it == cp.end()); } //************************************************************************* TEST(test_ranges_cartesian_product_view_first_range_empty) { std::vector v1; std::vector v2 = {1, 2, 3}; auto cp = etl::views::cartesian_product(v1, v2); CHECK_EQUAL(0U, cp.size()); CHECK(cp.begin() == cp.end()); } //************************************************************************* /// to_input_view tests //************************************************************************* TEST(test_ranges_to_input_view_functional) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto iv = etl::ranges::to_input_view(v_in); // Iterator category should be input_iterator_tag using iv_iterator = decltype(iv.begin()); using iv_category = typename etl::iterator_traits::iterator_category; static_assert(etl::is_same_v, "to_input_view iterator should have input_iterator_tag"); for (auto i : iv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(iv.size(), 10u); CHECK_EQUAL(iv.empty(), false); } //************************************************************************* TEST(test_ranges_to_input_view_empty_range) { etl::vector v_in; auto iv = etl::ranges::to_input_view(v_in); CHECK_EQUAL(iv.size(), 0u); CHECK_EQUAL(iv.empty(), true); CHECK(iv.begin() == iv.end()); } //************************************************************************* TEST(test_ranges_to_input_view_reflects_base_changes) { etl::vector v_in{0, 1, 2, 3, 4}; auto iv = etl::ranges::to_input_view(v_in); CHECK_EQUAL(iv.front(), 0); CHECK_EQUAL(iv.size(), 5u); v_in[0] = 99; CHECK_EQUAL(iv.front(), 99); } //************************************************************************* TEST(test_ranges_to_input_view_pipe) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto iv = v_in | etl::views::to_input(); using iv_iterator = decltype(iv.begin()); using iv_category = typename etl::iterator_traits::iterator_category; static_assert(etl::is_same_v, "piped to_input view iterator should have input_iterator_tag"); for (auto i : iv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); CHECK_EQUAL(iv.size(), 10u); } //************************************************************************* TEST(test_ranges_views_to_input_functional) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; auto iv = etl::views::to_input(v_in); using iv_iterator = decltype(iv.begin()); using iv_category = typename etl::iterator_traits::iterator_category; static_assert(etl::is_same_v, "views::to_input iterator should have input_iterator_tag"); for (auto i : iv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } //************************************************************************* TEST(test_ranges_to_input_view_pipe_chained_with_take) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{0, 1, 2}; auto iv = v_in | etl::views::to_input() | etl::views::take(3); for (auto i : iv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } //************************************************************************* TEST(test_ranges_to_input_view_pipe_chained_with_drop) { etl::vector v_in{0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; etl::vector v_out; etl::vector v_out_expected{7, 8, 9}; auto iv = v_in | etl::views::to_input() | etl::views::drop(7); for (auto i : iv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } //************************************************************************* TEST(test_ranges_to_input_view_pipe_chained_with_transform) { etl::vector v_in{0, 1, 2, 3, 4}; etl::vector v_out; etl::vector v_out_expected{0, 2, 4, 6, 8}; auto doubler = [](int i) { return i * 2; }; auto iv = v_in | etl::views::to_input() | etl::views::transform(doubler); for (auto i : iv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected, v_out); } //************************************************************************* TEST(test_ranges_to_input_view_with_std_vector) { std::vector v_in{0, 1, 2, 3, 4}; std::vector v_out; std::vector v_out_expected{0, 1, 2, 3, 4}; auto iv = etl::ranges::to_input_view(v_in); using iv_iterator = decltype(iv.begin()); using iv_category = typename etl::iterator_traits::iterator_category; static_assert(etl::is_same_v, "to_input_view over std::vector should have input_iterator_tag"); for (auto i : iv) { v_out.push_back(i); } CHECK_EQUAL(v_out_expected.size(), v_out.size()); for (size_t idx = 0; idx < v_out_expected.size(); ++idx) { CHECK_EQUAL(v_out_expected[idx], v_out[idx]); } } //************************************************************************* TEST(test_ranges_to_input_view_downgrades_from_random_access) { // std::vector has random_access_iterator; verify to_input downgrades it std::vector v_in{10, 20, 30}; using original_category = typename etl::iterator_traits< std::vector::iterator>::iterator_category; static_assert(etl::is_same_v, "std::vector iterator should be random_access"); auto iv = etl::ranges::to_input_view(v_in); using iv_iterator = decltype(iv.begin()); using iv_category = typename etl::iterator_traits::iterator_category; static_assert(etl::is_same_v, "to_input_view should downgrade to input_iterator_tag"); etl::vector v_out; for (auto i : iv) { v_out.push_back(i); } CHECK_EQUAL(3u, v_out.size()); CHECK_EQUAL(10, v_out[0]); CHECK_EQUAL(20, v_out[1]); CHECK_EQUAL(30, v_out[2]); } //************************************************************************* TEST(test_ranges_to_input_view_downgrades_from_bidirectional) { // std::list has bidirectional_iterator; verify to_input downgrades it std::list l_in{10, 20, 30}; using original_category = typename etl::iterator_traits< std::list::iterator>::iterator_category; static_assert(etl::is_same_v, "std::list iterator should be bidirectional"); auto iv = etl::ranges::to_input_view(l_in); using iv_iterator = decltype(iv.begin()); using iv_category = typename etl::iterator_traits::iterator_category; static_assert(etl::is_same_v, "to_input_view should downgrade to input_iterator_tag"); etl::vector v_out; for (auto i : iv) { v_out.push_back(i); } CHECK_EQUAL(3u, v_out.size()); CHECK_EQUAL(10, v_out[0]); CHECK_EQUAL(20, v_out[1]); CHECK_EQUAL(30, v_out[2]); } TEST(test_ranges_to_input_view_non_const_reference_type) { // to_input_view must preserve the underlying range's mutable references, // matching std::ranges::as_input_view. std::vector v_in{1, 2, 3}; auto iv = etl::ranges::to_input_view(v_in); using element_ref = decltype(*iv.begin()); static_assert(etl::is_same::value, "to_input element should be a non-const reference"); static_assert(!etl::is_const_v>, "to_input element should be mutable"); *iv.begin() = 99; CHECK_EQUAL(99, v_in[0]); } TEST(test_ranges_to_input_view_modify_elements) { // Write through every element of the input view in place. std::vector v_in{1, 2, 3, 4}; auto iv = etl::ranges::to_input_view(v_in); for (auto& element : iv) { element *= 10; } std::vector expected{10, 20, 30, 40}; CHECK_EQUAL(expected, v_in); } } #include "etl/private/diagnostic_pop.h" } // namespace #endif #endif