From c6979f312afbdafb614ba6118f703732398763bb Mon Sep 17 00:00:00 2001 From: Ole Erik Peistorpet Date: Mon, 27 May 2024 16:56:28 +0200 Subject: [PATCH] view::generate always std::input_range --- ...l_assignable.h => detail_iter_with_func.h} | 23 ++++++++- unit_test/view_gtest.cpp | 21 +++++--- view/generate.h | 49 ++++++++++++++----- view/transform_iterator.h | 35 +++---------- 4 files changed, 79 insertions(+), 49 deletions(-) rename auxi/{detail_assignable.h => detail_iter_with_func.h} (74%) diff --git a/auxi/detail_assignable.h b/auxi/detail_iter_with_func.h similarity index 74% rename from auxi/detail_assignable.h rename to auxi/detail_iter_with_func.h index 830eecec..b20220d4 100644 --- a/auxi/detail_assignable.h +++ b/auxi/detail_iter_with_func.h @@ -6,7 +6,7 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include "core_util.h" +#include "../util.h" // for TightPair namespace oel::_detail @@ -60,4 +60,25 @@ namespace oel::_detail public: using Type = T; }; + + + template< typename T, typename Func, bool /*IsConstCallable*/ > + struct IterWithFuncBase + { + using FnRef = const Func &; + + static constexpr auto canCallConst = true; + + TightPair< T, typename AssignableWrap::Type > m; + }; + + template< typename T, typename Func > + struct IterWithFuncBase + { + using FnRef = Func &; + + static constexpr auto canCallConst = false; + + TightPair< T, typename AssignableWrap::Type > mutable m; + }; } \ No newline at end of file diff --git a/unit_test/view_gtest.cpp b/unit_test/view_gtest.cpp index 59286efe..641a22ae 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; @@ -274,6 +273,13 @@ struct Ints TEST(viewTest, viewGenerate) { + { + auto v = view::generate([] { return 7; }, 1); + for (auto i : v) + EXPECT_EQ(7, i); + + static_assert(sizeof v.begin() <= sizeof(ptrdiff_t)); + } auto d = view::generate(Ints{1}, 2) | oel::to_dynarray(); ASSERT_EQ(2U, d.size()); @@ -282,6 +288,12 @@ TEST(viewTest, viewGenerate) d.assign(oel::view::generate(Ints{}, 0)); EXPECT_TRUE(d.empty()); + +#if OEL_STD_RANGES + using G = decltype( view::generate(Ints{}, 2) ); + static_assert(std::ranges::input_range); + static_assert(std::ranges::sized_range); +#endif } TEST(viewTest, viewMoveEndDifferentType) @@ -305,9 +317,6 @@ TEST(viewTest, viewMoveMutableEmptyAndSize) EXPECT_EQ(1U, v.size()); } -using IntGenIter = oel::iterator_t; -static_assert(std::input_iterator); - TEST(viewTest, chainWithStd) { auto f = [](int i) { return -i; }; diff --git a/view/generate.h b/view/generate.h index c9f90b79..7cd87265 100644 --- a/view/generate.h +++ b/view/generate.h @@ -6,8 +6,8 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include "counted.h" -#include "../auxi/detail_assignable.h" +#include "subrange.h" +#include "../auxi/detail_iter_with_func.h" /** @file */ @@ -15,27 +15,48 @@ namespace oel { +struct _defaultSentinel {}; + + template< typename Generator > -class generate_iterator +class _generateIterator + : private _detail::IterWithFuncBase< ptrdiff_t, Generator, std::is_invocable_v > { - typename _detail::AssignableWrap::Type mutable _g; + using _base = typename _generateIterator::IterWithFuncBase; + + using _base::m; public: using iterator_category = std::input_iterator_tag; - using reference = decltype( std::declval()() ); + using difference_type = ptrdiff_t; + 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 generate_iterator(Generator g) : _g{std::move(g)} {} + constexpr _generateIterator(Generator g, difference_type count) : _base{{count, std::move(g)}} {} constexpr reference operator*() const { - return static_cast(_g)(); + typename _base::FnRef g = m.second(); + return g(); } - constexpr generate_iterator & operator++() OEL_ALWAYS_INLINE { return *this; } - constexpr void operator++(int) & OEL_ALWAYS_INLINE {} + constexpr _generateIterator & operator++() OEL_ALWAYS_INLINE { --m.first; return *this; } + + constexpr void operator++(int) & OEL_ALWAYS_INLINE { --m.first; } + + friend constexpr difference_type operator - + (_defaultSentinel, const _generateIterator & right) { return right.m.first; } + friend constexpr difference_type operator - + (const _generateIterator & left, _defaultSentinel) { return -left.m.first; } + + friend constexpr bool operator==(const _generateIterator & left, _defaultSentinel) { return 0 == left.m.first; } + + friend constexpr bool operator==(_defaultSentinel left, const _generateIterator & right) { return right == left; } + + friend constexpr bool operator!=(const _generateIterator & left, _defaultSentinel) { return 0 != left.m.first; } + + friend constexpr bool operator!=(_defaultSentinel, const _generateIterator & right) { return 0 != right.m.first; } }; @@ -43,9 +64,11 @@ namespace view { //! Returns a view that generates `count` elements by calling the given generator function /** -* 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(generate_iterator{std::move(generator)}, count); }; +* Almost same as `generate_n` in the Range-v3 library. */ +inline constexpr auto generate = [](auto generator, ptrdiff_t count) + { + return subrange(_generateIterator{std::move(generator), count}, _defaultSentinel{}); + }; } } // oel diff --git a/view/transform_iterator.h b/view/transform_iterator.h index 9d6c158e..8f494c63 100644 --- a/view/transform_iterator.h +++ b/view/transform_iterator.h @@ -6,39 +6,14 @@ // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) -#include "../util.h" // for TightPair -#include "../auxi/detail_assignable.h" +#include "../auxi/detail_iter_with_func.h" +#include "../auxi/range_traits.h" /** @file */ namespace oel { -namespace _detail -{ - template< typename Func, typename Iter, - bool = std::is_invocable_v< const Func &, decltype(*std::declval()) > - > - struct TransformIterBase - { - using FnRef = const Func &; - - static constexpr auto canCallConst = true; - - TightPair< Iter, typename AssignableWrap::Type > m; - }; - - template< typename Func, typename Iter > - struct TransformIterBase - { - using FnRef = Func &; - - static constexpr auto canCallConst = false; - - TightPair< Iter, typename AssignableWrap::Type > mutable m; - }; -} - /** @brief Similar to boost::transform_iterator * @@ -49,9 +24,11 @@ namespace _detail * - Function objects (including lambda) can have non-const `operator()`, then merely std::input_iterator is modeled */ template< typename UnaryFunc, typename Iterator > class transform_iterator - : private _detail::TransformIterBase + : private _detail::IterWithFuncBase< Iterator, UnaryFunc, + std::is_invocable_v< const UnaryFunc &, decltype(*std::declval()) > + > { - using _super = typename transform_iterator::TransformIterBase; + using _super = typename transform_iterator::IterWithFuncBase; using _super::m;