From ca276ca5471a4e7a137f68a81feb150282eae62f Mon Sep 17 00:00:00 2001 From: Dan Goodliffe Date: Wed, 7 Feb 2024 23:50:50 +0000 Subject: Add stripiter A generic iterator wrapper returning a tuple of 3 references to the original values, as processed in the fashion of an OpenGL triangle strip. --- lib/collections.h | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ test/test-lib.cpp | 20 +++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/lib/collections.h b/lib/collections.h index 943b986..6cee10c 100644 --- a/lib/collections.h +++ b/lib/collections.h @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -160,3 +161,62 @@ template struct pair_range { }; template pair_range(std::pair) -> pair_range; + +template struct stripiter { + [[nodiscard]] constexpr bool + operator!=(const stripiter & other) const + { + return current != other.current; + } + + [[nodiscard]] constexpr bool + operator==(const stripiter & other) const + { + return current == other.current; + } + + constexpr stripiter & + operator++() + { + ++current; + off = 1 - off; + return *this; + } + + constexpr stripiter & + operator--() + { + --current; + off = 1 - off; + return *this; + } + + constexpr auto + operator-(const stripiter & other) const + { + return current - other.current; + } + + constexpr auto + operator*() const + { + return std::tie(*(current - (2 - off)), *(current - off - 1), *current); + } + + iter current; + uint8_t off {}; +}; + +template struct std::iterator_traits> : std::iterator_traits { }; + +constexpr auto +strip_begin(IterableCollection auto & cont) +{ + return stripiter {cont.begin() + 2}; +} + +constexpr auto +strip_end(IterableCollection auto & cont) +{ + return stripiter {cont.end()}; +} diff --git a/test/test-lib.cpp b/test/test-lib.cpp index 58b769a..5f0b5e5 100644 --- a/test/test-lib.cpp +++ b/test/test-lib.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include #include @@ -49,3 +50,22 @@ BOOST_AUTO_TEST_CASE(generate_move_and_delete) } BOOST_CHECK(active.empty()); } + +constexpr std::array TRIANGLE_STRIP_IN {0, 1, 2, 3, 4, 5}; +static_assert(std::distance(strip_begin(TRIANGLE_STRIP_IN), strip_end(TRIANGLE_STRIP_IN)) == 4); + +BOOST_AUTO_TEST_CASE(triangle_strip_iter) +{ + constexpr std::array TRIANGLE_STRIP_EXPECTED {0, 1, 2, 2, 1, 3, 2, 3, 4, 4, 3, 5}; + + std::vector out; + std::for_each(strip_begin(TRIANGLE_STRIP_IN), strip_end(TRIANGLE_STRIP_IN), [&out](const auto & t) { + const auto [a, b, c] = t; + out.push_back(a); + out.push_back(b); + out.push_back(c); + }); + BOOST_REQUIRE_EQUAL(out.size(), (TRIANGLE_STRIP_IN.size() - 2) * 3); + BOOST_CHECK_EQUAL_COLLECTIONS( + out.begin(), out.end(), TRIANGLE_STRIP_EXPECTED.begin(), TRIANGLE_STRIP_EXPECTED.end()); +} -- cgit v1.2.3