From 4050987fec3513c51e58cb1325b6d70733181d1f Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 6 Jan 2025 17:41:00 +0800 Subject: [PATCH 1/4] Fix dispatching for `views::counted` --- stl/inc/ranges | 5 +-- tests/std/include/range_algorithm_support.hpp | 16 +++---- .../std/tests/P0896R4_views_counted/test.cpp | 44 ++++++++++++++++++- 3 files changed, 52 insertions(+), 13 deletions(-) diff --git a/stl/inc/ranges b/stl/inc/ranges index 38289d7320a..49b69fa59e9 100644 --- a/stl/inc/ranges +++ b/stl/inc/ranges @@ -4216,12 +4216,11 @@ namespace ranges { using _Decayed = decay_t<_It>; _STL_INTERNAL_STATIC_ASSERT(input_or_output_iterator<_Decayed>); if constexpr (contiguous_iterator<_Decayed>) { - return {_St::_Span, - noexcept(span(_STD to_address(_STD declval<_It>()), iter_difference_t<_Decayed>{}))}; + return {_St::_Span, true}; } else if constexpr (random_access_iterator<_Decayed>) { return {_St::_Subrange, noexcept(subrange(_STD declval<_It>(), _STD declval<_It>() + iter_difference_t<_Decayed>{}))}; - } else if constexpr (constructible_from<_Decayed, _It>) { + } else if constexpr (is_convertible_v<_It, _Decayed>) { return {_St::_Subrange_counted, noexcept(subrange( counted_iterator(_STD declval<_It>(), iter_difference_t<_Decayed>{}), default_sentinel))}; diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index 056b84b2982..92160943e9e 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -964,7 +964,12 @@ namespace test { requires std::signed_integral && requires { typename std::iterator_traits::iterator_category; } struct redifference_iterator_category_base { using iterator_category = std::iterator_traits::iterator_category; - using iterator_concept = decltype([] { + }; + + template + class redifference_iterator : public redifference_iterator_category_base { + public: + using iterator_concept = decltype([] { if constexpr (std::contiguous_iterator) { return std::contiguous_iterator_tag{}; } else if constexpr (std::random_access_iterator) { @@ -977,13 +982,8 @@ namespace test { return std::input_iterator_tag{}; } }()); - }; - - template - class redifference_iterator : public redifference_iterator_category_base { - public: - using value_type = std::iter_value_t; - using difference_type = Diff; + using value_type = std::iter_value_t; + using difference_type = Diff; redifference_iterator() = default; constexpr explicit redifference_iterator(It it) : i_{std::move(it)} {} diff --git a/tests/std/tests/P0896R4_views_counted/test.cpp b/tests/std/tests/P0896R4_views_counted/test.cpp index a033fb72643..95ec4e66f55 100644 --- a/tests/std/tests/P0896R4_views_counted/test.cpp +++ b/tests/std/tests/P0896R4_views_counted/test.cpp @@ -14,6 +14,12 @@ template concept Countable = requires { typename iter_difference_t>; } && requires(I&& i, iter_difference_t> n) { views::counted(forward(i), n); }; +template +concept CanConstructCountedSubrange = requires { typename iter_difference_t>; } + && requires(I&& i, iter_difference_t> n) { + ranges::subrange(counted_iterator(forward(i), n), default_sentinel); + }; + template struct convertible_difference { constexpr convertible_difference(const int _val_) noexcept : _val(_val_) {} @@ -31,8 +37,7 @@ struct instantiator { template static constexpr void call() { - using ranges::contiguous_range, ranges::equal, ranges::iterator_t, ranges::random_access_range, ranges::size, - ranges::subrange; + using ranges::equal, ranges::size, ranges::subrange; int input[] = {13, 42, 1729, -1, -1}; static_assert(Countable); @@ -41,6 +46,10 @@ struct instantiator { auto result = ranges::views::counted(Iter{input}, convertible_difference{3}); if constexpr (contiguous_iterator) { static_assert(same_as>, dynamic_extent>>); + + const test::redifference_iterator<_Signed128, Iter> rediff_it{Iter{input}}; + ranges::contiguous_range auto rediff_result = ranges::views::counted(Iter{input}, _Signed128{4}); + assert(size(rediff_result) == 4); } else if constexpr (random_access_iterator) { static_assert(same_as>); } else { @@ -53,6 +62,37 @@ struct instantiator { } }; +// Also test GH-5183: ": views::counted::_Choose() misses difference casting for contiguous_iterator case" +struct ExplicitCopyCtorIter { + using difference_type = int; + + ExplicitCopyCtorIter() = default; + ExplicitCopyCtorIter(ExplicitCopyCtorIter&&) = default; + ExplicitCopyCtorIter& operator=(ExplicitCopyCtorIter&&) = default; + explicit ExplicitCopyCtorIter(const ExplicitCopyCtorIter&) = default; + int operator*(); + ExplicitCopyCtorIter& operator++(); + void operator++(int); +}; +static_assert(!Countable); +static_assert(!CanConstructCountedSubrange); + +struct ImplicitCopyOnlyIter { + using difference_type = int; + + ImplicitCopyOnlyIter() = default; + ImplicitCopyOnlyIter(ImplicitCopyOnlyIter&&) = default; + ImplicitCopyOnlyIter& operator=(ImplicitCopyOnlyIter&&) = default; + explicit ImplicitCopyOnlyIter(const ImplicitCopyOnlyIter&) = delete; + template + ImplicitCopyOnlyIter(const ImplicitCopyOnlyIter&); + int operator*(); + ImplicitCopyOnlyIter& operator++(); + void operator++(int); +}; +static_assert(Countable); +static_assert(CanConstructCountedSubrange); + int main() { static_assert(with_writable_iterators::call()); with_writable_iterators::call(); From 74d0d0f715d9fd9dd30aec55da7b1bd011ffe6eb Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Mon, 6 Jan 2025 18:17:46 +0800 Subject: [PATCH 2/4] Fix copy-pasta --- tests/std/tests/P0896R4_views_counted/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0896R4_views_counted/test.cpp b/tests/std/tests/P0896R4_views_counted/test.cpp index 95ec4e66f55..e20d1177c26 100644 --- a/tests/std/tests/P0896R4_views_counted/test.cpp +++ b/tests/std/tests/P0896R4_views_counted/test.cpp @@ -48,7 +48,7 @@ struct instantiator { static_assert(same_as>, dynamic_extent>>); const test::redifference_iterator<_Signed128, Iter> rediff_it{Iter{input}}; - ranges::contiguous_range auto rediff_result = ranges::views::counted(Iter{input}, _Signed128{4}); + ranges::contiguous_range auto rediff_result = ranges::views::counted(rediff_it, _Signed128{4}); assert(size(rediff_result) == 4); } else if constexpr (random_access_iterator) { static_assert(same_as>); From 0dc2672433904dc8593ca4ece9f6bf6d51e1bab3 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Tue, 7 Jan 2025 16:07:10 +0800 Subject: [PATCH 3/4] Use "usual" method to implement `iterator_concept` --- tests/std/include/range_algorithm_support.hpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index 92160943e9e..e8ba5dbe319 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -969,19 +969,11 @@ namespace test { template class redifference_iterator : public redifference_iterator_category_base { public: - using iterator_concept = decltype([] { - if constexpr (std::contiguous_iterator) { - return std::contiguous_iterator_tag{}; - } else if constexpr (std::random_access_iterator) { - return std::random_access_iterator_tag{}; - } else if constexpr (std::bidirectional_iterator) { - return std::bidirectional_iterator_tag{}; - } else if constexpr (std::forward_iterator) { - return std::forward_iterator_tag{}; - } else { - return std::input_iterator_tag{}; - } - }()); + using iterator_concept = std::conditional_t, std::contiguous_iterator_tag, + std::conditional_t, std::random_access_iterator_tag, + std::conditional_t, std::bidirectional_iterator_tag, + std::conditional_t, std::forward_iterator_tag, + std::input_iterator_tag>>>>; using value_type = std::iter_value_t; using difference_type = Diff; From 1dd7739d60f043dc663160e37742ca5f4f9e399a Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Thu, 9 Jan 2025 01:40:35 +0800 Subject: [PATCH 4/4] Workaround for DevCom-10735214 --- tests/std/include/range_algorithm_support.hpp | 30 ++++++++++++------- 1 file changed, 19 insertions(+), 11 deletions(-) diff --git a/tests/std/include/range_algorithm_support.hpp b/tests/std/include/range_algorithm_support.hpp index e8ba5dbe319..96b44d2616a 100644 --- a/tests/std/include/range_algorithm_support.hpp +++ b/tests/std/include/range_algorithm_support.hpp @@ -969,11 +969,19 @@ namespace test { template class redifference_iterator : public redifference_iterator_category_base { public: - using iterator_concept = std::conditional_t, std::contiguous_iterator_tag, - std::conditional_t, std::random_access_iterator_tag, - std::conditional_t, std::bidirectional_iterator_tag, - std::conditional_t, std::forward_iterator_tag, - std::input_iterator_tag>>>>; + using iterator_concept = decltype([] { + if constexpr (std::contiguous_iterator) { + return std::contiguous_iterator_tag{}; + } else if constexpr (std::random_access_iterator) { + return std::random_access_iterator_tag{}; + } else if constexpr (std::bidirectional_iterator) { + return std::bidirectional_iterator_tag{}; + } else if constexpr (std::forward_iterator) { + return std::forward_iterator_tag{}; + } else { + return std::input_iterator_tag{}; + } + }()); using value_type = std::iter_value_t; using difference_type = Diff; @@ -1044,22 +1052,22 @@ namespace test { return i.i_ == j.i_; } - [[nodiscard]] friend constexpr redifference_iterator operator+( - const redifference_iterator& it, std::same_as auto n) + template I> // TRANSITION, DevCom-10735214, should be abbreviated + [[nodiscard]] friend constexpr redifference_iterator operator+(const redifference_iterator& it, I n) requires std::random_access_iterator { return redifference_iterator{it.i_ + static_cast>(n)}; } - [[nodiscard]] friend constexpr redifference_iterator operator+( - std::same_as auto n, const redifference_iterator& it) + template I> // TRANSITION, DevCom-10735214, should be abbreviated + [[nodiscard]] friend constexpr redifference_iterator operator+(I n, const redifference_iterator& it) requires std::random_access_iterator { return redifference_iterator{it.i_ + static_cast>(n)}; } - [[nodiscard]] friend constexpr redifference_iterator operator-( - const redifference_iterator& it, std::same_as auto n) + template I> // TRANSITION, DevCom-10735214, should be abbreviated + [[nodiscard]] friend constexpr redifference_iterator operator-(const redifference_iterator& it, I n) requires std::random_access_iterator { return redifference_iterator{it.i_ - static_cast>(n)};