Skip to content

Commit 9ec1309

Browse files
<ranges>: Fix dispatching for views::counted (#5223)
1 parent 22b5573 commit 9ec1309

File tree

3 files changed

+58
-19
lines changed

3 files changed

+58
-19
lines changed

stl/inc/ranges

+2-3
Original file line numberDiff line numberDiff line change
@@ -4216,12 +4216,11 @@ namespace ranges {
42164216
using _Decayed = decay_t<_It>;
42174217
_STL_INTERNAL_STATIC_ASSERT(input_or_output_iterator<_Decayed>);
42184218
if constexpr (contiguous_iterator<_Decayed>) {
4219-
return {_St::_Span,
4220-
noexcept(span(_STD to_address(_STD declval<_It>()), iter_difference_t<_Decayed>{}))};
4219+
return {_St::_Span, true};
42214220
} else if constexpr (random_access_iterator<_Decayed>) {
42224221
return {_St::_Subrange,
42234222
noexcept(subrange(_STD declval<_It>(), _STD declval<_It>() + iter_difference_t<_Decayed>{}))};
4224-
} else if constexpr (constructible_from<_Decayed, _It>) {
4223+
} else if constexpr (is_convertible_v<_It, _Decayed>) {
42254224
return {_St::_Subrange_counted,
42264225
noexcept(subrange(
42274226
counted_iterator(_STD declval<_It>(), iter_difference_t<_Decayed>{}), default_sentinel))};

tests/std/include/range_algorithm_support.hpp

+14-14
Original file line numberDiff line numberDiff line change
@@ -964,7 +964,12 @@ namespace test {
964964
requires std::signed_integral<Diff> && requires { typename std::iterator_traits<It>::iterator_category; }
965965
struct redifference_iterator_category_base<Diff, It> {
966966
using iterator_category = std::iterator_traits<It>::iterator_category;
967-
using iterator_concept = decltype([] {
967+
};
968+
969+
template <std::_Signed_integer_like Diff, std::input_iterator It>
970+
class redifference_iterator : public redifference_iterator_category_base<Diff, It> {
971+
public:
972+
using iterator_concept = decltype([] {
968973
if constexpr (std::contiguous_iterator<It>) {
969974
return std::contiguous_iterator_tag{};
970975
} else if constexpr (std::random_access_iterator<It>) {
@@ -977,13 +982,8 @@ namespace test {
977982
return std::input_iterator_tag{};
978983
}
979984
}());
980-
};
981-
982-
template <std::_Signed_integer_like Diff, std::input_iterator It>
983-
class redifference_iterator : public redifference_iterator_category_base<Diff, It> {
984-
public:
985-
using value_type = std::iter_value_t<It>;
986-
using difference_type = Diff;
985+
using value_type = std::iter_value_t<It>;
986+
using difference_type = Diff;
987987

988988
redifference_iterator() = default;
989989
constexpr explicit redifference_iterator(It it) : i_{std::move(it)} {}
@@ -1052,22 +1052,22 @@ namespace test {
10521052
return i.i_ == j.i_;
10531053
}
10541054

1055-
[[nodiscard]] friend constexpr redifference_iterator operator+(
1056-
const redifference_iterator& it, std::same_as<difference_type> auto n)
1055+
template <std::same_as<difference_type> I> // TRANSITION, DevCom-10735214, should be abbreviated
1056+
[[nodiscard]] friend constexpr redifference_iterator operator+(const redifference_iterator& it, I n)
10571057
requires std::random_access_iterator<It>
10581058
{
10591059
return redifference_iterator{it.i_ + static_cast<std::iter_difference_t<It>>(n)};
10601060
}
10611061

1062-
[[nodiscard]] friend constexpr redifference_iterator operator+(
1063-
std::same_as<difference_type> auto n, const redifference_iterator& it)
1062+
template <std::same_as<difference_type> I> // TRANSITION, DevCom-10735214, should be abbreviated
1063+
[[nodiscard]] friend constexpr redifference_iterator operator+(I n, const redifference_iterator& it)
10641064
requires std::random_access_iterator<It>
10651065
{
10661066
return redifference_iterator{it.i_ + static_cast<std::iter_difference_t<It>>(n)};
10671067
}
10681068

1069-
[[nodiscard]] friend constexpr redifference_iterator operator-(
1070-
const redifference_iterator& it, std::same_as<difference_type> auto n)
1069+
template <std::same_as<difference_type> I> // TRANSITION, DevCom-10735214, should be abbreviated
1070+
[[nodiscard]] friend constexpr redifference_iterator operator-(const redifference_iterator& it, I n)
10711071
requires std::random_access_iterator<It>
10721072
{
10731073
return redifference_iterator{it.i_ - static_cast<std::iter_difference_t<It>>(n)};

tests/std/tests/P0896R4_views_counted/test.cpp

+42-2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,12 @@ template <class I>
1414
concept Countable = requires { typename iter_difference_t<remove_cvref_t<I>>; }
1515
&& requires(I&& i, iter_difference_t<remove_cvref_t<I>> n) { views::counted(forward<I>(i), n); };
1616

17+
template <class I>
18+
concept CanConstructCountedSubrange = requires { typename iter_difference_t<remove_cvref_t<I>>; }
19+
&& requires(I&& i, iter_difference_t<remove_cvref_t<I>> n) {
20+
ranges::subrange(counted_iterator(forward<I>(i), n), default_sentinel);
21+
};
22+
1723
template <input_or_output_iterator Iter>
1824
struct convertible_difference {
1925
constexpr convertible_difference(const int _val_) noexcept : _val(_val_) {}
@@ -31,8 +37,7 @@ struct instantiator {
3137

3238
template <input_or_output_iterator Iter>
3339
static constexpr void call() {
34-
using ranges::contiguous_range, ranges::equal, ranges::iterator_t, ranges::random_access_range, ranges::size,
35-
ranges::subrange;
40+
using ranges::equal, ranges::size, ranges::subrange;
3641
int input[] = {13, 42, 1729, -1, -1};
3742

3843
static_assert(Countable<Iter>);
@@ -41,6 +46,10 @@ struct instantiator {
4146
auto result = ranges::views::counted(Iter{input}, convertible_difference<Iter>{3});
4247
if constexpr (contiguous_iterator<Iter>) {
4348
static_assert(same_as<decltype(result), span<remove_reference_t<iter_reference_t<Iter>>, dynamic_extent>>);
49+
50+
const test::redifference_iterator<_Signed128, Iter> rediff_it{Iter{input}};
51+
ranges::contiguous_range auto rediff_result = ranges::views::counted(rediff_it, _Signed128{4});
52+
assert(size(rediff_result) == 4);
4453
} else if constexpr (random_access_iterator<Iter>) {
4554
static_assert(same_as<decltype(result), subrange<Iter, Iter>>);
4655
} else {
@@ -53,6 +62,37 @@ struct instantiator {
5362
}
5463
};
5564

65+
// Also test GH-5183: "<ranges>: views::counted::_Choose() misses difference casting for contiguous_iterator case"
66+
struct ExplicitCopyCtorIter {
67+
using difference_type = int;
68+
69+
ExplicitCopyCtorIter() = default;
70+
ExplicitCopyCtorIter(ExplicitCopyCtorIter&&) = default;
71+
ExplicitCopyCtorIter& operator=(ExplicitCopyCtorIter&&) = default;
72+
explicit ExplicitCopyCtorIter(const ExplicitCopyCtorIter&) = default;
73+
int operator*();
74+
ExplicitCopyCtorIter& operator++();
75+
void operator++(int);
76+
};
77+
static_assert(!Countable<ExplicitCopyCtorIter&>);
78+
static_assert(!CanConstructCountedSubrange<ExplicitCopyCtorIter&>);
79+
80+
struct ImplicitCopyOnlyIter {
81+
using difference_type = int;
82+
83+
ImplicitCopyOnlyIter() = default;
84+
ImplicitCopyOnlyIter(ImplicitCopyOnlyIter&&) = default;
85+
ImplicitCopyOnlyIter& operator=(ImplicitCopyOnlyIter&&) = default;
86+
explicit ImplicitCopyOnlyIter(const ImplicitCopyOnlyIter&) = delete;
87+
template <int = 0>
88+
ImplicitCopyOnlyIter(const ImplicitCopyOnlyIter&);
89+
int operator*();
90+
ImplicitCopyOnlyIter& operator++();
91+
void operator++(int);
92+
};
93+
static_assert(Countable<ImplicitCopyOnlyIter&>);
94+
static_assert(CanConstructCountedSubrange<ImplicitCopyOnlyIter&>);
95+
5696
int main() {
5797
static_assert(with_writable_iterators<instantiator, int>::call());
5898
with_writable_iterators<instantiator, int>::call();

0 commit comments

Comments
 (0)