diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h --- a/libcxx/include/__ranges/concepts.h +++ b/libcxx/include/__ranges/concepts.h @@ -83,11 +83,11 @@ movable<_Tp> && enable_view<_Tp>; - template + template concept __simple_view = view<_Range> && range && same_as, iterator_t> && - same_as, iterator_t>; + same_as, sentinel_t>; // [range.refinements], other range refinements template diff --git a/libcxx/test/libcxx/ranges/range.utility.helpers/simple_view.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.utility.helpers/simple_view.compile.pass.cpp --- a/libcxx/test/libcxx/ranges/range.utility.helpers/simple_view.compile.pass.cpp +++ b/libcxx/test/libcxx/ranges/range.utility.helpers/simple_view.compile.pass.cpp @@ -39,7 +39,14 @@ sentinel_wrapper end() const; }; +struct WrongConstSentinel : std::ranges::view_base { + int *begin() const; + sentinel_wrapper end(); + sentinel_wrapper end() const; +}; + static_assert( std::ranges::__simple_view); static_assert(!std::ranges::__simple_view); static_assert(!std::ranges::__simple_view); -static_assert(!std::ranges::__simple_view); +static_assert( std::ranges::__simple_view); +static_assert(!std::ranges::__simple_view); diff --git a/libcxx/test/std/ranges/range.adaptors/range.drop/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.drop/begin.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.drop/begin.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.drop/begin.pass.cpp @@ -19,11 +19,32 @@ #include #include "test_macros.h" +#include "test_iterators.h" #include "types.h" template concept BeginInvocable = requires(std::ranges::drop_view t) { t.begin(); }; +template +struct MaybeSimpleView : std::ranges::view_base { + int* num_of_non_const_begin_calls; + int* num_of_const_begin_calls; + + constexpr int* begin() { + ++(*num_of_non_const_begin_calls); + return nullptr; + } + constexpr std::conditional_t begin() const { + ++(*num_of_const_begin_calls); + return nullptr; + } + constexpr int* end() const { return nullptr; } + constexpr size_t size() const { return 0; } +}; + +using SimpleView = MaybeSimpleView; +using NonSimpleView = MaybeSimpleView; + constexpr bool test() { // random_access_range && sized_range std::ranges::drop_view dropView1(MoveOnlyView(), 4); @@ -62,6 +83,36 @@ static_assert(!BeginInvocable); + { + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::sized_range); + LIBCPP_STATIC_ASSERT(std::ranges::__simple_view); + int non_const_calls = 0; + int const_calls = 0; + std::ranges::drop_view dropView(SimpleView{{}, &non_const_calls, &const_calls}, 4); + assert(dropView.begin() == nullptr); + assert(non_const_calls == 0); + assert(const_calls == 1); + assert(std::as_const(dropView).begin() == nullptr); + assert(non_const_calls == 0); + assert(const_calls == 2); + } + + { + static_assert(std::ranges::random_access_range); + static_assert(std::ranges::sized_range); + LIBCPP_STATIC_ASSERT(!std::ranges::__simple_view); + int non_const_calls = 0; + int const_calls = 0; + std::ranges::drop_view dropView(NonSimpleView{{}, &non_const_calls, &const_calls}, 4); + assert(dropView.begin() == nullptr); + assert(non_const_calls == 1); + assert(const_calls == 0); + assert(std::as_const(dropView).begin() == nullptr); + assert(non_const_calls == 1); + assert(const_calls == 1); + } + return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join.view/begin.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/begin.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join.view/begin.pass.cpp @@ -19,6 +19,17 @@ #include "test_macros.h" #include "types.h" +struct NonSimpleParentView : std::ranges::view_base { + ChildView* begin() { return nullptr; } + const ChildView* begin() const; + const ChildView* end() const; +}; + +struct SimpleParentView : std::ranges::view_base { + const ChildView* begin() const; + const ChildView* end() const; +}; + constexpr bool test() { int buffer[4][4] = {{1111, 2222, 3333, 4444}, {555, 666, 777, 888}, {99, 1010, 1111, 1212}, {13, 14, 15, 16}}; @@ -86,6 +97,20 @@ assert(*jv.begin() == 1111); } + // !simple-view + { + std::ranges::join_view jv; + static_assert(!std::same_as); + } + + // simple-view && is_reference_v>; + { + std::ranges::join_view jv; + static_assert(std::same_as); + } + return true; } diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/begin.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.take/begin.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take/begin.pass.cpp @@ -21,6 +21,14 @@ #include "test_range.h" #include "types.h" +struct NonCommonSimpleView : std::ranges::view_base { + int* begin() const; + sentinel_wrapper end() const; + size_t size() { return 0; } // deliberately non-const +}; +static_assert(std::ranges::sized_range); +static_assert(!std::ranges::sized_range); + constexpr bool test() { int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; @@ -63,6 +71,13 @@ ASSERT_SAME_TYPE(decltype(tv.begin()), std::counted_iterator); } + // __simple_view && sized_range && !size_range + { + std::ranges::take_view tv{}; + ASSERT_SAME_TYPE(decltype(tv.begin()), std::counted_iterator); + ASSERT_SAME_TYPE(decltype(std::as_const(tv).begin()), std::counted_iterator); + } + return true; }