diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/begin.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.common.view/begin.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/begin.pass.cpp @@ -66,16 +66,11 @@ { SizedForwardView view{buf, buf + 8}; std::ranges::common_view common(view); - using CommonIter = std::common_iterator>; - std::same_as auto begin = common.begin(); - assert(begin == std::ranges::begin(view)); - } - { - SizedForwardView view{buf, buf + 8}; - std::ranges::common_view const common(view); - using CommonIter = std::common_iterator>; + using CommonIter = std::common_iterator>; std::same_as auto begin = common.begin(); assert(begin == std::ranges::begin(view)); + std::same_as auto cbegin = std::as_const(common).begin(); + assert(cbegin == std::ranges::begin(view)); } { diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/end.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.common.view/end.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/end.pass.cpp @@ -51,7 +51,7 @@ { int buf[8] = {1, 2, 3, 4, 5, 6, 7, 8}; - using CommonForwardIter = std::common_iterator>; + using CommonForwardIter = std::common_iterator>; using CommonIntIter = std::common_iterator>; { diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h b/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h --- a/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/types.h @@ -52,15 +52,8 @@ int* end_; constexpr explicit SizedForwardView(int* b, int* e) : begin_(b), end_(e) { } constexpr auto begin() const { return forward_iterator(begin_); } - constexpr auto end() const { return sentinel_wrapper>(forward_iterator(end_)); } + constexpr auto end() const { return sized_sentinel>(forward_iterator(end_)); } }; -// Required to make SizedForwardView a sized view. -constexpr auto operator-(sentinel_wrapper sent, ForwardIter iter) { - return sent.base().base() - iter.base(); -} -constexpr auto operator-(ForwardIter iter, sentinel_wrapper sent) { - return iter.base() - sent.base().base(); -} static_assert(std::ranges::view); static_assert(std::ranges::forward_range); static_assert(std::ranges::sized_range); @@ -71,15 +64,8 @@ int* end_; constexpr explicit SizedRandomAccessView(int* b, int* e) : begin_(b), end_(e) { } constexpr auto begin() const { return random_access_iterator(begin_); } - constexpr auto end() const { return sentinel_wrapper>(random_access_iterator(end_)); } + constexpr auto end() const { return sized_sentinel>(random_access_iterator(end_)); } }; -// Required to make SizedRandomAccessView a sized view. -constexpr auto operator-(sentinel_wrapper sent, RandomAccessIter iter) { - return sent.base().base() - iter.base(); -} -constexpr auto operator-(RandomAccessIter iter, sentinel_wrapper sent) { - return iter.base() - sent.base().base(); -} static_assert(std::ranges::view); static_assert(std::ranges::random_access_range); static_assert(std::ranges::sized_range); diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/base.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/base.pass.cpp @@ -24,20 +24,13 @@ constexpr bool test() { int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; - auto sw = sentinel_wrapper(buffer + 8); // Note: not 4, but that's OK. - { - const std::ranges::take_view tv(MoveOnlyView{buffer}, 4); - assert(tv.end().base().base() == sw.base()); - ASSERT_SAME_TYPE(decltype(tv.end().base()), sentinel_wrapper); + std::ranges::take_view tv(MoveOnlyView(buffer), 4); + std::same_as> auto sw1 = tv.end().base(); + assert(base(sw1) == buffer + 8); + std::same_as> auto sw2 = std::as_const(tv).end().base(); + assert(base(sw2) == buffer + 8); } - - { - std::ranges::take_view tv(MoveOnlyView{buffer}, 4); - assert(tv.end().base().base() == sw.base()); - ASSERT_SAME_TYPE(decltype(tv.end().base()), sentinel_wrapper); - } - return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/ctor.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/ctor.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take/sentinel/ctor.pass.cpp @@ -27,27 +27,39 @@ { // Test the default ctor. - std::ranges::take_view tv(MoveOnlyView{buffer}, 4); - assert(decltype(tv.end()){} == std::ranges::next(tv.begin(), 4)); + using TakeView = std::ranges::take_view; + using Sentinel = std::ranges::sentinel_t; + Sentinel s; + TakeView tv = TakeView(MoveOnlyView(buffer), 4); + assert(tv.begin() + 4 == s); } { - std::ranges::take_view nonConst(MoveOnlyView{buffer}, 5); - const std::ranges::take_view tvConst(MoveOnlyView{buffer}, 5); - auto sent1 = nonConst.end(); - // Convert to const. Note, we cannot go the other way. - std::remove_cv_t sent2 = sent1; - - assert(sent1 == std::ranges::next(tvConst.begin(), 5)); - assert(sent2 == std::ranges::next(tvConst.begin(), 5)); + // Test the conversion from "sentinel" to "sentinel-to-const". + using TakeView = std::ranges::take_view; + using Sentinel = std::ranges::sentinel_t; + using ConstSentinel = std::ranges::sentinel_t; + static_assert(std::is_convertible_v); + TakeView tv = TakeView(MoveOnlyView(buffer), 4); + Sentinel s = tv.end(); + ConstSentinel cs = s; + cs = s; // test assignment also + assert(tv.begin() + 4 == s); + assert(tv.begin() + 4 == cs); + assert(std::as_const(tv).begin() + 4 == s); + assert(std::as_const(tv).begin() + 4 == cs); } { - std::ranges::take_view tv(CopyableView{buffer}, 6); - auto sw = sentinel_wrapper(buffer + 6); - using Sent = decltype(tv.end()); - Sent sent = Sent(sw); - assert(sent.base().base() == sw.base()); + // Test the constructor from "base-sentinel" to "sentinel". + using TakeView = std::ranges::take_view; + using Sentinel = std::ranges::sentinel_t; + sentinel_wrapper sw1 = MoveOnlyView(buffer).end(); + static_assert( std::is_constructible_v>); + static_assert(!std::is_convertible_v, Sentinel>); + auto s = Sentinel(sw1); + std::same_as> auto sw2 = s.base(); + assert(base(sw2) == base(sw1)); } return true; diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/types.h b/libcxx/test/std/ranges/range.adaptors/range.take/types.h --- a/libcxx/test/std/ranges/range.adaptors/range.take/types.h +++ b/libcxx/test/std/ranges/range.adaptors/range.take/types.h @@ -37,15 +37,8 @@ int *ptr_; constexpr explicit SizedForwardView(int* ptr) : ptr_(ptr) {} constexpr auto begin() const { return ForwardIter(ptr_); } - constexpr auto end() const { return sentinel_wrapper(ForwardIter(ptr_ + 8)); } + constexpr auto end() const { return sized_sentinel(ForwardIter(ptr_ + 8)); } }; -// Required to make SizedForwardView a sized view. -constexpr auto operator-(sentinel_wrapper sent, ForwardIter iter) { - return sent.base().base() - iter.base(); -} -constexpr auto operator-(ForwardIter iter, sentinel_wrapper sent) { - return iter.base() - sent.base().base(); -} static_assert(std::ranges::view); static_assert(std::ranges::forward_range); static_assert(std::ranges::sized_range); @@ -55,15 +48,8 @@ int *ptr_; constexpr explicit SizedRandomAccessView(int* ptr) : ptr_(ptr) {} constexpr auto begin() const { return RandomAccessIter(ptr_); } - constexpr auto end() const { return sentinel_wrapper(RandomAccessIter(ptr_ + 8)); } + constexpr auto end() const { return sized_sentinel(RandomAccessIter(ptr_ + 8)); } }; -// Required to make SizedRandomAccessView a sized view. -constexpr auto operator-(sentinel_wrapper sent, RandomAccessIter iter) { - return sent.base().base() - iter.base(); -} -constexpr auto operator-(RandomAccessIter iter, sentinel_wrapper sent) { - return iter.base() - sent.base().base(); -} static_assert(std::ranges::view); static_assert(std::ranges::random_access_range); static_assert(std::ranges::sized_range); diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/end.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.transform/end.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/end.pass.cpp @@ -25,44 +25,58 @@ #include "types.h" template -concept EndInvocable = requires(T t) { t.end(); }; - -template -concept EndIsIter = requires(T t) { ++t.end(); }; +concept HasConstQualifiedEnd = requires(const T& t) { t.end(); }; constexpr bool test() { { - std::ranges::transform_view transformView(MoveOnlyView{}, PlusOneMutable{}); - assert(transformView.end().base() == globalBuff + 8); + using TransformView = std::ranges::transform_view; + static_assert(std::ranges::common_range); + TransformView tv; + auto end = tv.end(); + ASSERT_SAME_TYPE(decltype(end.base()), std::ranges::sentinel_t); + assert(base(end.base()) == globalBuff + 8); + static_assert(!HasConstQualifiedEnd); } - { - std::ranges::transform_view transformView(ForwardView{}, PlusOneMutable{}); - assert(transformView.end().base().base() == globalBuff + 8); + using TransformView = std::ranges::transform_view; + static_assert(!std::ranges::common_range); + TransformView tv; + auto end = tv.end(); + ASSERT_SAME_TYPE(decltype(end.base()), std::ranges::sentinel_t); + assert(base(base(end.base())) == globalBuff + 8); + static_assert(!HasConstQualifiedEnd); } - { - std::ranges::transform_view transformView(InputView{}, PlusOneMutable{}); - assert(transformView.end().base() == globalBuff + 8); + using TransformView = std::ranges::transform_view; + static_assert(!std::ranges::common_range); + TransformView tv; + auto end = tv.end(); + ASSERT_SAME_TYPE(decltype(end.base()), std::ranges::sentinel_t); + assert(base(base(end.base())) == globalBuff + 8); + auto cend = std::as_const(tv).end(); + ASSERT_SAME_TYPE(decltype(cend.base()), std::ranges::sentinel_t); + assert(base(base(cend.base())) == globalBuff + 8); } - { - const std::ranges::transform_view transformView(MoveOnlyView{}, PlusOne{}); - assert(transformView.end().base() == globalBuff + 8); + using TransformView = std::ranges::transform_view; + static_assert(std::ranges::common_range); + TransformView tv; + auto end = tv.end(); + ASSERT_SAME_TYPE(decltype(end.base()), std::ranges::sentinel_t); + assert(end.base() == globalBuff + 8); + static_assert(!HasConstQualifiedEnd); + } + { + using TransformView = std::ranges::transform_view; + static_assert(std::ranges::common_range); + TransformView tv; + auto end = tv.end(); + ASSERT_SAME_TYPE(decltype(end.base()), std::ranges::sentinel_t); + assert(end.base() == globalBuff + 8); + auto cend = std::as_const(tv).end(); + ASSERT_SAME_TYPE(decltype(cend.base()), std::ranges::sentinel_t); + assert(cend.base() == globalBuff + 8); } - - static_assert(!EndInvocable>); - static_assert( EndInvocable< std::ranges::transform_view>); - static_assert( EndInvocable>); - static_assert(!EndInvocable>); - static_assert( EndInvocable< std::ranges::transform_view>); - static_assert( EndInvocable>); - - static_assert(!EndIsIter>); - static_assert(!EndIsIter< std::ranges::transform_view>); - static_assert( EndIsIter>); - static_assert( EndIsIter< std::ranges::transform_view>); - return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/base.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/base.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/iterator/base.pass.cpp @@ -17,30 +17,29 @@ #include "test_macros.h" #include "../types.h" -template -concept BaseInvocable = requires(std::ranges::iterator_t> iter) { - iter.base(); +template +concept BaseInvocable = requires(It it) { + it.base(); }; constexpr bool test() { { - std::ranges::transform_view transformView; - auto iter = std::move(transformView).begin(); - ASSERT_SAME_TYPE(int*, decltype(iter.base())); - assert(iter.base() == globalBuff); - ASSERT_SAME_TYPE(int*, decltype(std::move(iter).base())); - assert(std::move(iter).base() == globalBuff); + using TransformView = std::ranges::transform_view; + TransformView tv; + auto begin = tv.begin(); + ASSERT_SAME_TYPE(decltype(begin.base()), int*); + assert(begin.base() == globalBuff); + ASSERT_SAME_TYPE(decltype(std::move(begin).base()), int*); + assert(std::move(begin).base() == globalBuff); } - { - std::ranges::transform_view transformView; - auto iter = transformView.begin(); - assert(std::move(iter).base() == globalBuff); - ASSERT_SAME_TYPE(cpp20_input_iterator, decltype(std::move(iter).base())); + using TransformView = std::ranges::transform_view; + TransformView tv; + auto begin = tv.begin(); + static_assert(!BaseInvocable); + std::same_as> auto it = std::move(begin).base(); + assert(base(it) == globalBuff); } - - static_assert(!BaseInvocable); - return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/types.h b/libcxx/test/std/ranges/range.adaptors/range.transform/types.h --- a/libcxx/test/std/ranges/range.adaptors/range.transform/types.h +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/types.h @@ -85,12 +85,11 @@ struct InputView : std::ranges::view_base { int *ptr_; constexpr explicit InputView(int* ptr = globalBuff) : ptr_(ptr) {} - constexpr cpp20_input_iterator begin() const { return cpp20_input_iterator(ptr_); } - constexpr int *end() const { return ptr_ + 8; } + constexpr auto begin() const { return cpp20_input_iterator(ptr_); } + constexpr auto end() const { return sentinel_wrapper>(cpp20_input_iterator(ptr_ + 8)); } }; -// TODO: remove these bogus operators -constexpr bool operator==(const cpp20_input_iterator &lhs, int* rhs) { return lhs.base() == rhs; } -constexpr bool operator==(int* lhs, const cpp20_input_iterator &rhs) { return rhs.base() == lhs; } +static_assert( std::ranges::view); +static_assert(!std::ranges::sized_range); struct SizedSentinelView : std::ranges::view_base { int count_; diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -845,62 +845,30 @@ requires std::equality_comparable_with; }; -template +template class sentinel_wrapper { public: sentinel_wrapper() = default; - constexpr explicit sentinel_wrapper(I base) : base_(std::move(base)) {} - - constexpr bool operator==(const I& other) const requires std::equality_comparable { - return base_ == other; - } - - constexpr const I& base() const& { return base_; } - constexpr I base() && { return std::move(base_); } - - template - requires sentinel_for_base - constexpr bool operator==(const I2& other) const { - return base_ == other.base(); - } - + constexpr explicit sentinel_wrapper(const It& it) : base_(base(it)) {} + constexpr bool operator==(const It& other) const { return base_ == base(other); } + friend constexpr auto base(const sentinel_wrapper& s) { return It(s.base_); } private: - I base_ = I(); + decltype(base(std::declval())) base_; }; -template +template class sized_sentinel { public: - sized_sentinel() = default; - constexpr explicit sized_sentinel(I base) : base_(std::move(base)) {} - - constexpr bool operator==(const I& other) const requires std::equality_comparable { - return base_ == other; - } - - constexpr const I& base() const& { return base_; } - constexpr I base() && { return std::move(base_); } - - template - requires sentinel_for_base - constexpr bool operator==(const I2& other) const { - return base_ == other.base(); - } - + explicit sized_sentinel() = default; + constexpr explicit sized_sentinel(const It& it) : base_(base(it)) {} + constexpr bool operator==(const It& other) const { return base_ == base(other); } + friend constexpr auto operator-(const sized_sentinel& s, const It& i) { return s.base_ - base(i); } + friend constexpr auto operator-(const It& i, const sized_sentinel& s) { return base(i) - s.base_; } + friend constexpr auto base(const sized_sentinel& s) { return It(s.base_); } private: - I base_ = I(); + decltype(base(std::declval())) base_; }; -template -constexpr auto operator-(sized_sentinel sent, std::input_or_output_iterator auto iter) { - return sent.base() - iter; -} - -template -constexpr auto operator-(std::input_or_output_iterator auto iter, sized_sentinel sent) { - return iter - sent.base(); -} - template class three_way_contiguous_iterator {