From 3e71a141cccc94bcf2ad7f42481b5d0eb8eedaff Mon Sep 17 00:00:00 2001 From: Ole Erik Peistorpet Date: Thu, 28 Sep 2023 23:41:54 +0200 Subject: [PATCH] Fixed view-related compile errors Also CMAKE_CXX_STANDARD in workflow yml --- .github/workflows/cmake-multi-platform.yml | 30 +++++++++++-- unit_test/dynarray_other_gtest.cpp | 2 + unit_test/incl_view_counted.cpp | 5 --- unit_test/test_classes.h | 2 +- unit_test/view_gtest.cpp | 34 ++++++++------- view/counted.h | 4 +- view/detail/core.h | 17 ++++++++ view/move.h | 2 +- view/subrange.h | 4 +- view/transform.h | 4 +- view/transform_iterator.h | 49 +++++++++++++++------- 11 files changed, 107 insertions(+), 46 deletions(-) diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index 76985a8d..523b61a4 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -10,17 +10,40 @@ jobs: runs-on: ${{ matrix.os }} strategy: - # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. Consider changing this to true when your workflow is stable. - fail-fast: false + # Set fail-fast to false to ensure that feedback is delivered for all matrix combinations. + fail-fast: true matrix: os: [ubuntu-20.04, ubuntu-latest, macos-latest] - mem_bound_debug: [off, on] + cpp_standard: [17, 20] + mem_bound_debug: [off] include: - os: ubuntu-20.04 gcc_version: 7 + cpp_standard: 17 + - os: ubuntu-20.04 + gcc_version: 8 + cpp_standard: 14 + mem_bound_debug: on + - os: ubuntu-20.04 + gcc_version: 9 + cpp_standard: 20 + - os: ubuntu-latest + gcc_version: 10 + cpp_standard: 20 + mem_bound_debug: on + - os: ubuntu-latest + gcc_version: 11 + cpp_standard: 17 - os: ubuntu-latest gcc_version: 12 + cpp_standard: 20 + - os: macos-latest + cpp_standard: 14 + mem_bound_debug: on + exclude: + - os: macos-latest + cpp_standard: 17 steps: - if: runner.os == 'Linux' @@ -39,6 +62,7 @@ jobs: run: > cmake -B ${{ github.workspace }}/build -D CMAKE_BUILD_TYPE=Release + -D CMAKE_CXX_STANDARD=${{ matrix.cpp_standard }} -D MEM_BOUND_DEBUG=${{ matrix.mem_bound_debug }} -S ${{ github.workspace }}/unit_test diff --git a/unit_test/dynarray_other_gtest.cpp b/unit_test/dynarray_other_gtest.cpp index c265d4cf..26c606ad 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/incl_view_counted.cpp b/unit_test/incl_view_counted.cpp index 19d9d1ae..0dbb0e16 100644 --- a/unit_test/incl_view_counted.cpp +++ b/unit_test/incl_view_counted.cpp @@ -1,6 +1 @@ #include - -constexpr auto v() -{ - return oel::view::counted((int *)nullptr, 0); -} \ No newline at end of file diff --git a/unit_test/test_classes.h b/unit_test/test_classes.h index 5dbcc718..152e753e 100644 --- a/unit_test/test_classes.h +++ b/unit_test/test_classes.h @@ -24,7 +24,7 @@ class MemoryLeakDetector; extern MemoryLeakDetector* leakDetector; -#if __cpp_lib_ranges >= 201911 +#if (defined _MSC_VER and __cpp_lib_ranges >= 201911) or __cpp_lib_ranges > 202000 #include diff --git a/unit_test/view_gtest.cpp b/unit_test/view_gtest.cpp index 0ce32df1..dc526963 100644 --- a/unit_test/view_gtest.cpp +++ b/unit_test/view_gtest.cpp @@ -21,6 +21,9 @@ constexpr auto transformIterFromIntPtr(const int * p) return oel::transform_iterator{F{}, p}; } +template< typename S > +constexpr oel::sentinel_wrapper makeSentinel(S se) { return {se}; } + TEST(viewTest, basicView) { using BV = oel::basic_view; @@ -38,7 +41,7 @@ TEST(viewTest, basicView) EXPECT_EQ(2, ssize(v)); } constexpr auto it = transformIterFromIntPtr(src); - constexpr auto v = view::subrange(it, src + 3); + constexpr auto v = view::subrange(it, makeSentinel(src + 3)); EXPECT_EQ(3, ssize(v)); } @@ -70,18 +73,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 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::forward_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::forward_range); @@ -96,17 +102,17 @@ TEST(viewTest, viewTransformBasics) EXPECT_TRUE( it++ == v.begin() ); EXPECT_TRUE( it != v.begin() ); } - EXPECT_TRUE( v.begin() == v.begin().base() ); - EXPECT_FALSE( r + 1 == v.begin() ); - EXPECT_FALSE( v.begin() != r + 0 ); - EXPECT_TRUE( r + 1 != v.begin() ); + EXPECT_TRUE( v.begin() == makeSentinel(v.begin().base()) ); + EXPECT_FALSE( makeSentinel(r + 1) == v.begin() ); + EXPECT_FALSE( v.begin() != makeSentinel(r + 0) ); + EXPECT_TRUE( makeSentinel(r + 1) != v.begin() ); auto nested = view::transform(v, [](double d) { return d; }); auto const it = nested.begin(); - EXPECT_TRUE(r + 0 == it); - EXPECT_TRUE(r + 1 != it); - EXPECT_FALSE(it == r + 1); - EXPECT_FALSE(it != r + 0); + EXPECT_TRUE(makeSentinel(r + 0) == it.base()); + EXPECT_TRUE(makeSentinel(r + 1) != it.base()); + EXPECT_FALSE(it.base() == makeSentinel(r + 1)); + EXPECT_FALSE(it.base() != makeSentinel(r + 0)); } #if __cplusplus > 201500 or _HAS_CXX17 @@ -118,7 +124,7 @@ constexpr auto multBy2(StdArrInt2 a) StdArrInt2 res{}; struct { constexpr auto operator()(int i) const { return 2 * i; } - } mult2; + } mult2{}; auto v = view::transform(a, mult2); std::ptrdiff_t i{}; for (auto val : v) @@ -225,10 +231,10 @@ TEST(viewTest, viewMoveEndDifferentType) auto nonEmpty = [i = -1](int j) { return i + j; }; int src[1]; oel::transform_iterator it{nonEmpty, src + 0}; - auto v = view::move(view::subrange(it, src + 1)); + auto v = view::move(view::subrange( it, makeSentinel(src + 1) )); EXPECT_NE(v.begin(), v.end()); - EXPECT_EQ(src + 1, v.end().base()); + EXPECT_EQ(src + 1, v.end().base()._s); } #if OEL_STD_RANGES diff --git a/view/counted.h b/view/counted.h index 575d6872..9da5a94e 100644 --- a/view/counted.h +++ b/view/counted.h @@ -45,8 +45,8 @@ class counted_view constexpr bool empty() const noexcept { return 0 == _size; } - constexpr decltype(auto) operator[](difference_type index) const OEL_ALWAYS_INLINE - OEL_REQUIRES(iter_is_random_access) { return _begin[index]; } + constexpr decltype(auto) operator[](difference_type index) const + OEL_REQUIRES(iter_is_random_access) OEL_ALWAYS_INLINE { return _begin[index]; } protected: Iterator _begin; diff --git a/view/detail/core.h b/view/detail/core.h index d5b57801..fa6bf087 100644 --- a/view/detail/core.h +++ b/view/detail/core.h @@ -22,6 +22,12 @@ namespace oel { + +template< typename Sentinel > +struct sentinel_wrapper { Sentinel _s; }; + + + namespace _detail { template< typename T, @@ -89,3 +95,14 @@ namespace _detail } } // oel + + +#if !OEL_STD_RANGES +namespace std +{ +// Small hack to let std::move_iterator< sentinel_wrapper > compile +template< typename S > +struct iterator_traits< oel::sentinel_wrapper > : iterator_traits {}; + +} +#endif diff --git a/view/move.h b/view/move.h index cc43fc22..ed9c2f43 100644 --- a/view/move.h +++ b/view/move.h @@ -41,7 +41,7 @@ namespace _detail using S = std::conditional_t< std::is_same_v< iterator_t, sentinel_t >, _iter, - std::move_sentinel< sentinel_t > // What is it good for? + std::move_sentinel< sentinel_t > >; #else using S = std::move_iterator< sentinel_t >; diff --git a/view/subrange.h b/view/subrange.h index 1a266e6d..72ecfa3a 100644 --- a/view/subrange.h +++ b/view/subrange.h @@ -39,8 +39,8 @@ class basic_view constexpr bool empty() const { return _begin == _end; } - constexpr decltype(auto) operator[](difference_type index) const OEL_ALWAYS_INLINE - OEL_REQUIRES(iter_is_random_access) { return _begin[index]; } + constexpr decltype(auto) operator[](difference_type index) const + OEL_REQUIRES(iter_is_random_access) OEL_ALWAYS_INLINE { return _begin[index]; } protected: Iterator _begin; diff --git a/view/transform.h b/view/transform.h index 78fd9f43..e4ae48af 100644 --- a/view/transform.h +++ b/view/transform.h @@ -32,9 +32,9 @@ namespace _detail } template< typename Sentinel, typename... None > - constexpr Sentinel _makeSent(Sentinel last, None...) + constexpr sentinel_wrapper _makeSent(Sentinel last, None...) { - return last; + return {last}; } public: diff --git a/view/transform_iterator.h b/view/transform_iterator.h index d0095b25..252e6253 100644 --- a/view/transform_iterator.h +++ b/view/transform_iterator.h @@ -76,26 +76,43 @@ class transform_iterator template< typename S > OEL_REQUIRES(std::sized_sentinel_for) - friend constexpr difference_type operator -(const transform_iterator & left, S right) { return left._m.first - right; } + friend constexpr difference_type operator - + (sentinel_wrapper left, const transform_iterator & right) { return left._s - right._m.first; } template< typename S > 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; } + friend constexpr difference_type operator - + (const transform_iterator & left, sentinel_wrapper right) { return left._m.first - right._s; } + + 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 > + friend constexpr bool operator== + (const transform_iterator & left, sentinel_wrapper right) { return left._m.first == right._s; } + + template< typename S > + friend constexpr bool operator== + (sentinel_wrapper left, const transform_iterator & right) { return right._m.first == left._s; } + + template< typename S > + friend constexpr bool operator!= + (const transform_iterator & left, sentinel_wrapper right) { return left._m.first != right._s; } + + template< typename S > + friend constexpr bool operator!= + (sentinel_wrapper left, const transform_iterator & right) { return right._m.first != left._s; } }; -template< typename F, typename I > -constexpr bool disable_sized_sentinel_for< transform_iterator, transform_iterator > - = !iter_is_random_access; +#if __cpp_lib_concepts < 201907 + template< typename F, typename I > + constexpr bool disable_sized_sentinel_for< transform_iterator, transform_iterator > + = disable_sized_sentinel_for; + + template< typename S, typename F, typename I > + constexpr bool disable_sized_sentinel_for< sentinel_wrapper, transform_iterator > + = disable_sized_sentinel_for; +#endif } // namespace oel