From a22128d0a7b3e111b3e712b4f1f5bc339f597e79 Mon Sep 17 00:00:00 2001 From: Ole Erik Peistorpet Date: Mon, 11 Jul 2022 23:00:22 +0200 Subject: [PATCH] Fixed transform_iterator compile error corner case Unit tests updated. When compiling with MSVC 2019, more constraints needed for transform_iterator equality operators. --- unit_test/dynarray_other_gtest.cpp | 2 ++ unit_test/view_gtest.cpp | 20 +++++++++++++++++--- view/transform_iterator.h | 29 +++++++++++++++++++---------- 3 files changed, 38 insertions(+), 13 deletions(-) diff --git a/unit_test/dynarray_other_gtest.cpp b/unit_test/dynarray_other_gtest.cpp index e299dda9..cf4ee4ae 100644 --- a/unit_test/dynarray_other_gtest.cpp +++ b/unit_test/dynarray_other_gtest.cpp @@ -29,6 +29,8 @@ namespace #if __cpp_lib_concepts >= 201907 static_assert(std::contiguous_iterator); static_assert(std::contiguous_iterator); + static_assert(std::sized_sentinel_for); + static_assert(std::sized_sentinel_for); #endif static_assert(std::is_same::value_type, float>(), "?"); diff --git a/unit_test/view_gtest.cpp b/unit_test/view_gtest.cpp index 848a7493..57c3bb4d 100644 --- a/unit_test/view_gtest.cpp +++ b/unit_test/view_gtest.cpp @@ -70,18 +70,21 @@ TEST(viewTest, viewTransformBasics) { using Elem = double; - struct MoveOnly + struct MoveOnlyF { std::unique_ptr p; auto operator()(Elem &) const { return 0; } }; Elem r[1]; - auto v = view::transform(r, [](Elem &) { return 0; }); + auto v = r | view::transform([](Elem &) { return 0; }); + auto v2 = view::transform(r, MoveOnlyF{}); + auto itMoveOnly = v2.begin(); using IEmptyLambda = decltype(v.begin()); - using IMoveOnly = oel::transform_iterator; + using IMoveOnly = decltype(itMoveOnly); static_assert(std::is_same< IEmptyLambda::iterator_category, std::bidirectional_iterator_tag >(), "?"); static_assert(std::is_same< IMoveOnly::iterator_category, std::input_iterator_tag >(), "?"); + static_assert(std::is_same< decltype(itMoveOnly++), void >(), "?"); static_assert(sizeof(IEmptyLambda) == sizeof(Elem *), "Not critical, this assert can be removed"); #if OEL_STD_RANGES static_assert(std::ranges::bidirectional_range); @@ -244,4 +247,15 @@ TEST(viewTest, viewMoveMutableEmptyAndSize) EXPECT_FALSE(v.empty()); EXPECT_EQ(1U, v.size()); } + +TEST(viewTest, chainWithStd) +{ + auto f = [](int i) { return -i; }; + int src[] {0, 1}; + + void( src | view::move() | std::views::drop_while([](int i) { return i <= 0; }) ); + void( src | std::views::reverse | view::transform(f) | std::views::take(1) ); + void( src | view::transform(f) | std::views::drop(1) | view::move() ); +} + #endif diff --git a/view/transform_iterator.h b/view/transform_iterator.h index f24f05cf..f2100115 100644 --- a/view/transform_iterator.h +++ b/view/transform_iterator.h @@ -99,16 +99,25 @@ class transform_iterator OEL_REQUIRES(std::sized_sentinel_for) friend constexpr difference_type operator -(S left, const transform_iterator & right) { return left - right._m.first; } - constexpr bool operator==(const transform_iterator & right) const { return _m.first == right._m.first; } - constexpr bool operator!=(const transform_iterator & right) const { return _m.first != right._m.first; } - template< typename Sentinel > - friend constexpr bool operator==(const transform_iterator & left, Sentinel right) { return left._m.first == right; } - template< typename Sentinel > - friend constexpr bool operator==(Sentinel left, const transform_iterator & right) { return right._m.first == left; } - template< typename Sentinel > - friend constexpr bool operator!=(const transform_iterator & left, Sentinel right) { return left._m.first != right; } - template< typename Sentinel > - friend constexpr bool operator!=(Sentinel left, const transform_iterator & right) { return right._m.first != left; } + constexpr bool operator==(const transform_iterator & right) const { return _m.first == right._m.first; } + + constexpr bool operator!=(const transform_iterator & right) const { return _m.first != right._m.first; } + + template< typename S > + OEL_REQUIRES(std::sentinel_for) + friend constexpr bool operator==(const transform_iterator & left, S right) { return left._m.first == right; } + + template< typename S > + OEL_REQUIRES(std::sentinel_for) + friend constexpr bool operator==(S left, const transform_iterator & right) { return right._m.first == left; } + + template< typename S > + OEL_REQUIRES(std::sentinel_for) + friend constexpr bool operator!=(const transform_iterator & left, S right) { return left._m.first != right; } + + template< typename S > + OEL_REQUIRES(std::sentinel_for) + friend constexpr bool operator!=(S left, const transform_iterator & right) { return right._m.first != left; } }; template< typename F, typename I >