From 021b0da9e70a8f2f3dde75a1907ae2d1f7bc2224 Mon Sep 17 00:00:00 2001 From: Ole Erik Peistorpet Date: Mon, 27 May 2024 13:59:39 +0200 Subject: [PATCH] Hack: generate_iterator with mutable member for std::input_iterator concept. Also constexpr unit test --- unit_test/view_gtest.cpp | 28 ++++++++++++++++++++++++---- view/generate.h | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 52 insertions(+), 12 deletions(-) diff --git a/unit_test/view_gtest.cpp b/unit_test/view_gtest.cpp index 0e17ce74..afe1c43d 100644 --- a/unit_test/view_gtest.cpp +++ b/unit_test/view_gtest.cpp @@ -144,10 +144,9 @@ using StdArrInt2 = std::array; constexpr auto multBy2(StdArrInt2 a) { StdArrInt2 res{}; - struct - { constexpr auto operator()(int i) const { return 2 * i; } - } mult2{}; + auto mult2 = [j = 2](int i) { return i * j; }; auto v = view::transform(a, mult2); + size_t i{}; for (auto val : v) res[i++] = val; @@ -244,6 +243,27 @@ TEST(viewTest, viewTransformAsOutput) EXPECT_EQ(-2, test[1].second); } +constexpr StdArrInt2 generatedArray() +{ + StdArrInt2 res{}; + int i{1}; + auto v = view::generate([&i] { return i++; }, 2); + auto it = v.begin(); + for (auto & val : res) + { + val = *it; + it++; + } + return res; +} + +constexpr void testViewGenerateConstexpr() +{ + constexpr auto res = generatedArray(); + static_assert(res[0] == 1); + static_assert(res[1] == 2); +} + struct Ints { int i; @@ -285,7 +305,7 @@ TEST(viewTest, viewMoveMutableEmptyAndSize) } using IntGenIter = oel::iterator_t; -static_assert(std::input_or_output_iterator); +static_assert(std::input_iterator); TEST(viewTest, chainWithStd) { diff --git a/view/generate.h b/view/generate.h index fe7ec4ac..2e4c9b1d 100644 --- a/view/generate.h +++ b/view/generate.h @@ -14,27 +14,47 @@ namespace oel { +namespace _detail +{ + template< typename G, bool = std::is_invocable_v > + struct GenerateIterBase + { + using FnRef = const G &; + + typename _detail::AssignableWrap::Type f; + }; + + template< typename G > + struct GenerateIterBase + { + using FnRef = G &; + + typename _detail::AssignableWrap::Type mutable f; + }; +} + template< typename Generator > -class _generateIterator +class generate_iterator + : private _detail::GenerateIterBase { - typename _detail::AssignableWrap::Type _g; + using _base = typename generate_iterator::GenerateIterBase; public: using iterator_category = std::input_iterator_tag; - using reference = decltype( std::declval()() ); + using reference = decltype( std::declval()() ); using pointer = void; using value_type = std::remove_cv_t< std::remove_reference_t >; using difference_type = ptrdiff_t; - constexpr explicit _generateIterator(Generator g) : _g{std::move(g)} {} + constexpr explicit generate_iterator(Generator g) : _base{std::move(g)} {} - constexpr reference operator*() + constexpr reference operator*() const { - return static_cast(_g)(); + typename _base::FnRef g = this->f; return g(); } - constexpr _generateIterator & operator++() OEL_ALWAYS_INLINE { return *this; } + constexpr generate_iterator & operator++() OEL_ALWAYS_INLINE { return *this; } constexpr void operator++(int) & OEL_ALWAYS_INLINE {} }; @@ -45,7 +65,7 @@ namespace view /** * Like `generate_n` in the Range-v3 library, but this is only for use within OE-Lib. */ inline constexpr auto generate = - [](auto generator, ptrdiff_t count) { return counted(_generateIterator{std::move(generator)}, count); }; + [](auto generator, ptrdiff_t count) { return counted(generate_iterator{std::move(generator)}, count); }; } } // oel