diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -184,6 +184,7 @@ __random/uniform_int_distribution.h __ranges/access.h __ranges/all.h + __ranges/common_view.h __ranges/concepts.h __ranges/copyable_box.h __ranges/data.h diff --git a/libcxx/include/__ranges/common_view.h b/libcxx/include/__ranges/common_view.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/common_view.h @@ -0,0 +1,98 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#ifndef _LIBCPP___RANGES_COMMON_VIEW_H +#define _LIBCPP___RANGES_COMMON_VIEW_H + +#include <__config> +#include <__iterator/common_iterator.h> +#include <__ranges/concepts.h> +#include <__ranges/view_interface.h> +#include +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +namespace ranges { + +template + requires (!common_range<_View> && copyable>) +class common_view : public view_interface> { + _View __base_ = _View(); + +public: + common_view() requires default_initializable<_View> = default; + + constexpr explicit common_view(_View __v) : __base_(_VSTD::move(__v)) { } + + constexpr _View base() const& requires copy_constructible<_View> { return __base_; } + constexpr _View base() && { return _VSTD::move(__base_); } + + constexpr auto begin() { + if constexpr (random_access_range<_View> && sized_range<_View>) + return ranges::begin(__base_); + else + return common_iterator, sentinel_t<_View>>(ranges::begin(__base_)); + } + + constexpr auto begin() const requires range { + if constexpr (random_access_range && sized_range) + return ranges::begin(__base_); + else + return common_iterator, sentinel_t>(ranges::begin(__base_)); + } + + constexpr auto end() { + if constexpr (random_access_range<_View> && sized_range<_View>) + return ranges::begin(__base_) + ranges::size(__base_); + else + return common_iterator, sentinel_t<_View>>(ranges::end(__base_)); + } + + constexpr auto end() const requires range { + if constexpr (random_access_range && sized_range) + return ranges::begin(__base_) + ranges::size(__base_); + else + return common_iterator, sentinel_t>(ranges::end(__base_)); + } + + constexpr auto size() requires sized_range<_View> { + return ranges::size(__base_); + } + + constexpr auto size() const requires sized_range { + return ranges::size(__base_); + } +}; + +// TODO: use all_t here when it's implemented. +template +common_view(_Range&&) + -> common_view()))>; + +template +inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_View>; + +} // namespace ranges + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___RANGES_COMMON_VIEW_H diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -599,6 +599,7 @@ module __ranges { module access { header "__ranges/access.h" } module all { header "__ranges/all.h" } + module common_view { header "__ranges/common_view.h" } module concepts { header "__ranges/concepts.h" } module copyable_box { header "__ranges/copyable_box.h" } module data { header "__ranges/data.h" } diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -109,6 +109,13 @@ can-reference>> class transform_view; + // [range.common], common view + template + requires (!common_range && copyable>) + class common_view; + + template + inline constexpr bool enable_borrowed_range> = enable_borrowed_range; } */ @@ -116,6 +123,7 @@ #include <__config> #include <__ranges/access.h> #include <__ranges/all.h> +#include <__ranges/common_view.h> #include <__ranges/concepts.h> #include <__ranges/data.h> #include <__ranges/drop_view.h> diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/base.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/base.pass.cpp @@ -0,0 +1,86 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// constexpr V base() const& requires copy_constructible; +// constexpr V base() &&; + +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "test_range.h" + +struct ContiguousView : std::ranges::view_base { + int *ptr_; + constexpr ContiguousView(int* ptr) : ptr_(ptr) {} + constexpr ContiguousView(ContiguousView&&) = default; + constexpr ContiguousView& operator=(ContiguousView&&) = default; + constexpr friend int* begin(ContiguousView& view) { return view.ptr_; } + constexpr friend int* begin(ContiguousView const& view) { return view.ptr_; } + constexpr friend sentinel_wrapper end(ContiguousView& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } + constexpr friend sentinel_wrapper end(ContiguousView const& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } +}; + +struct CopyableView : std::ranges::view_base { + int *ptr_; + constexpr CopyableView(int* ptr) : ptr_(ptr) {} + constexpr friend int* begin(CopyableView& view) { return view.ptr_; } + constexpr friend int* begin(CopyableView const& view) { return view.ptr_; } + constexpr friend sentinel_wrapper end(CopyableView& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } + constexpr friend sentinel_wrapper end(CopyableView const& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } +}; + +constexpr bool hasLValueQualifiedBase(auto&& view) { + return requires { view.base(); }; +} + +constexpr bool test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + std::ranges::common_view common(CopyableView{buffer}); + assert(common.base().ptr_ == buffer); + assert(std::move(common).base().ptr_ == buffer); + static_assert(hasLValueQualifiedBase(common)); + } + + { + std::ranges::common_view common(ContiguousView{buffer}); + assert(std::move(common).base().ptr_ == buffer); + static_assert(!hasLValueQualifiedBase(common)); + } + + { + const std::ranges::common_view common(CopyableView{buffer}); + assert(common.base().ptr_ == buffer); + assert(std::move(common).base().ptr_ == buffer); + static_assert(hasLValueQualifiedBase(common)); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} 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 new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/begin.pass.cpp @@ -0,0 +1,163 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// constexpr auto begin(); +// constexpr auto begin() const requires range; + +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "test_range.h" + +struct ContiguousView : std::ranges::view_base { + int *ptr_; + constexpr ContiguousView(int* ptr) : ptr_(ptr) {} + constexpr ContiguousView(ContiguousView&&) = default; + constexpr ContiguousView& operator=(ContiguousView&&) = default; + constexpr friend int* begin(ContiguousView& view) { return view.ptr_; } + constexpr friend int* begin(ContiguousView const& view) { return view.ptr_; } + constexpr friend sentinel_wrapper end(ContiguousView& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } + constexpr friend sentinel_wrapper end(ContiguousView const& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } +}; + +struct CopyableView : std::ranges::view_base { + int *ptr_; + constexpr CopyableView(int* ptr) : ptr_(ptr) {} + constexpr friend int* begin(CopyableView& view) { return view.ptr_; } + constexpr friend int* begin(CopyableView const& view) { return view.ptr_; } + constexpr friend sentinel_wrapper end(CopyableView& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } + constexpr friend sentinel_wrapper end(CopyableView const& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } +}; + +struct MutableView : std::ranges::view_base { + int *ptr_; + constexpr MutableView(int* ptr) : ptr_(ptr) {} + constexpr int* begin() { return ptr_; } + constexpr sentinel_wrapper end() { return sentinel_wrapper{ptr_ + 8}; } +}; + +using ForwardIter = forward_iterator; +struct SizedForwardView : std::ranges::view_base { + int *ptr_; + constexpr SizedForwardView(int* ptr) : ptr_(ptr) {} + constexpr friend ForwardIter begin(SizedForwardView& view) { return ForwardIter(view.ptr_); } + constexpr friend ForwardIter begin(SizedForwardView const& view) { return ForwardIter(view.ptr_); } + constexpr friend sentinel_wrapper end(SizedForwardView& view) { + return sentinel_wrapper{ForwardIter(view.ptr_ + 8)}; + } + constexpr friend sentinel_wrapper end(SizedForwardView const& view) { + return sentinel_wrapper{ForwardIter(view.ptr_ + 8)}; + } +}; + +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(); +} + +using RandomAccessIter = random_access_iterator; +struct SizedRandomAccessView : std::ranges::view_base { + int *ptr_; + constexpr SizedRandomAccessView(int* ptr) : ptr_(ptr) {} + constexpr friend RandomAccessIter begin(SizedRandomAccessView& view) { return RandomAccessIter(view.ptr_); } + constexpr friend RandomAccessIter begin(SizedRandomAccessView const& view) { return RandomAccessIter(view.ptr_); } + constexpr friend sentinel_wrapper end(SizedRandomAccessView& view) { + return sentinel_wrapper{RandomAccessIter(view.ptr_ + 8)}; + } + constexpr friend sentinel_wrapper end(SizedRandomAccessView const& view) { + return sentinel_wrapper{RandomAccessIter(view.ptr_ + 8)}; + } +}; + +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(); +} + +template +concept BeginEnabled = requires(const std::ranges::common_view& comm) { + comm.begin(); +}; + +constexpr bool test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + static_assert( BeginEnabled); + static_assert(!BeginEnabled); + } + + { + std::ranges::common_view comm(SizedForwardView{buffer}); + if (!std::is_constant_evaluated()) + assert(*comm.begin() == 1); + ASSERT_SAME_TYPE(decltype(comm.begin()), std::common_iterator>); + } + + { + std::ranges::common_view comm(ContiguousView{buffer}); + if (!std::is_constant_evaluated()) + assert(*comm.begin() == 1); + ASSERT_SAME_TYPE(decltype(comm.begin()), std::common_iterator>); + } + + { + std::ranges::common_view comm(SizedRandomAccessView{buffer}); + if (!std::is_constant_evaluated()) + assert(*comm.begin() == 1); + ASSERT_SAME_TYPE(decltype(comm.begin()), RandomAccessIter); + } + + { + const std::ranges::common_view comm(SizedForwardView{buffer}); + if (!std::is_constant_evaluated()) + assert(*comm.begin() == 1); + ASSERT_SAME_TYPE(decltype(comm.begin()), std::common_iterator>); + } + + { + const std::ranges::common_view comm(CopyableView{buffer}); + if (!std::is_constant_evaluated()) + assert(*comm.begin() == 1); + ASSERT_SAME_TYPE(decltype(comm.begin()), std::common_iterator>); + } + + { + const std::ranges::common_view comm(SizedRandomAccessView{buffer}); + if (!std::is_constant_evaluated()) + assert(*comm.begin() == 1); + ASSERT_SAME_TYPE(decltype(comm.begin()), RandomAccessIter); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/borrowing.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/borrowing.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/borrowing.compile.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// template +// inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" + +struct View : std::ranges::view_base { + friend int* begin(View&); + friend int* begin(View const&); + friend sentinel_wrapper end(View&); + friend sentinel_wrapper end(View const&); +}; + +struct BorrowableView : std::ranges::view_base { + friend int* begin(BorrowableView&); + friend int* begin(BorrowableView const&); + friend sentinel_wrapper end(BorrowableView&); + friend sentinel_wrapper end(BorrowableView const&); +}; + +template<> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +static_assert(!std::ranges::enable_borrowed_range>); +static_assert( std::ranges::enable_borrowed_range>); diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/ctad.compile.pass.cpp @@ -0,0 +1,67 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// template +// common_view(R&&) -> common_view>; + +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" + +struct View : std::ranges::view_base { + friend int* begin(View&); + friend int* begin(View const&); + friend sentinel_wrapper end(View&); + friend sentinel_wrapper end(View const&); +}; + +struct Range { + friend int* begin(Range&); + friend int* begin(Range const&); + friend sentinel_wrapper end(Range&); + friend sentinel_wrapper end(Range const&); +}; + +struct BorrowedRange { + friend int* begin(BorrowableRange&); + friend int* begin(BorrowableRange const&); + friend sentinel_wrapper end(BorrowableRange&); + friend sentinel_wrapper end(BorrowableRange const&); +}; + +template<> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +void testCTAD() { + View v; + Range r; + BorrowedRange br; + static_assert(std::same_as< + decltype(std::ranges::common_view(v)), + std::ranges::common_view + >); + static_assert(std::same_as< + decltype(std::ranges::common_view(r)), + std::ranges::common_view> + >); + // std::ranges::common_view(std::move(r)) is ill-formed + static_assert(std::same_as< + decltype(std::ranges::common_view(br)), + std::ranges::common_view> + >); + static_assert(std::same_as< + decltype(std::ranges::common_view(std::move(br))), + std::ranges::common_view> + >); +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/ctor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/ctor.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// common_view() requires default_initializable = default; +// constexpr explicit common_view(V r); + +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "test_range.h" + +struct ContiguousView : std::ranges::view_base { + int *ptr_; + constexpr ContiguousView(int* ptr) : ptr_(ptr) {} + constexpr ContiguousView(ContiguousView&&) = default; + constexpr ContiguousView& operator=(ContiguousView&&) = default; + constexpr friend int* begin(ContiguousView& view) { return view.ptr_; } + constexpr friend int* begin(ContiguousView const& view) { return view.ptr_; } + constexpr friend sentinel_wrapper end(ContiguousView& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } + constexpr friend sentinel_wrapper end(ContiguousView const& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } +}; + +struct CopyableView : std::ranges::view_base { + int *ptr_; + constexpr CopyableView(int* ptr) : ptr_(ptr) {} + constexpr friend int* begin(CopyableView& view) { return view.ptr_; } + constexpr friend int* begin(CopyableView const& view) { return view.ptr_; } + constexpr friend sentinel_wrapper end(CopyableView& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } + constexpr friend sentinel_wrapper end(CopyableView const& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } +}; + +struct DefaultConstructibleView : std::ranges::view_base { + DefaultConstructibleView(); + friend int* begin(DefaultConstructibleView& view); + friend int* begin(DefaultConstructibleView const& view); + friend sentinel_wrapper end(DefaultConstructibleView& view); + friend sentinel_wrapper end(DefaultConstructibleView const& view); +}; + +constexpr bool test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + static_assert(!std::default_initializable>); + static_assert( std::default_initializable>); + } + + { + std::ranges::common_view common(ContiguousView{buffer}); + if (!std::is_constant_evaluated()) + assert(*common.begin() == 1); + } + + { + ContiguousView v{buffer}; + std::ranges::common_view common(std::move(v)); + if (!std::is_constant_evaluated()) + assert(*common.begin() == 1); + } + + { + const std::ranges::common_view common(ContiguousView{buffer}); + if (!std::is_constant_evaluated()) + assert(*common.begin() == 1); + } + + { + const CopyableView v{buffer}; + const std::ranges::common_view common(v); + if (!std::is_constant_evaluated()) + assert(*common.begin() == 1); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} 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 new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/end.pass.cpp @@ -0,0 +1,134 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// constexpr auto end(); +// constexpr auto end() const requires range; + +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "test_range.h" + +struct CopyableView : std::ranges::view_base { + int *ptr_; + constexpr CopyableView(int* ptr) : ptr_(ptr) {} + constexpr friend int* begin(CopyableView& view) { return view.ptr_; } + constexpr friend int* begin(CopyableView const& view) { return view.ptr_; } + constexpr friend sentinel_wrapper end(CopyableView& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } + constexpr friend sentinel_wrapper end(CopyableView const& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } +}; + +using ForwardIter = forward_iterator; +struct SizedForwardView : std::ranges::view_base { + int *ptr_; + constexpr SizedForwardView(int* ptr) : ptr_(ptr) {} + constexpr friend ForwardIter begin(SizedForwardView& view) { return ForwardIter(view.ptr_); } + constexpr friend ForwardIter begin(SizedForwardView const& view) { return ForwardIter(view.ptr_); } + constexpr friend sentinel_wrapper end(SizedForwardView& view) { + return sentinel_wrapper{ForwardIter(view.ptr_ + 8)}; + } + constexpr friend sentinel_wrapper end(SizedForwardView const& view) { + return sentinel_wrapper{ForwardIter(view.ptr_ + 8)}; + } +}; + +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(); +} + +using RandomAccessIter = random_access_iterator; +struct SizedRandomcAccessView : std::ranges::view_base { + int *ptr_; + constexpr SizedRandomcAccessView(int* ptr) : ptr_(ptr) {} + constexpr friend RandomAccessIter begin(SizedRandomcAccessView& view) { return RandomAccessIter(view.ptr_); } + constexpr friend RandomAccessIter begin(SizedRandomcAccessView const& view) { return RandomAccessIter(view.ptr_); } + constexpr friend sentinel_wrapper end(SizedRandomcAccessView& view) { + return sentinel_wrapper{RandomAccessIter(view.ptr_ + 8)}; + } + constexpr friend sentinel_wrapper end(SizedRandomcAccessView const& view) { + return sentinel_wrapper{RandomAccessIter(view.ptr_ + 8)}; + } +}; + +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(); +} + +constexpr bool test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + using CommonForwardIter = std::common_iterator>; + using CommonIntIter = std::common_iterator>; + + { + std::ranges::common_view comm(SizedRandomcAccessView{buffer}); + assert(comm.end().base() == buffer + 8); + // Note this should NOT be the sentinel type. + ASSERT_SAME_TYPE(decltype(comm.end()), RandomAccessIter); + } + + { + std::ranges::common_view comm(SizedForwardView{buffer}); + if (!std::is_constant_evaluated()) + assert(comm.end() == CommonForwardIter(sentinel_wrapper(ForwardIter(buffer + 8)))); + ASSERT_SAME_TYPE(decltype(comm.end()), CommonForwardIter); + } + + { + std::ranges::common_view comm(CopyableView{buffer}); + if (!std::is_constant_evaluated()) + assert(comm.end() == CommonIntIter(sentinel_wrapper(buffer + 8))); + ASSERT_SAME_TYPE(decltype(comm.end()), CommonIntIter); + } + + { + const std::ranges::common_view comm(SizedRandomcAccessView{buffer}); + assert(comm.end().base() == buffer + 8); + // Note this should NOT be the sentinel type. + ASSERT_SAME_TYPE(decltype(comm.end()), RandomAccessIter); + } + + { + const std::ranges::common_view comm(SizedForwardView{buffer}); + if (!std::is_constant_evaluated()) + assert(comm.end() == CommonForwardIter(sentinel_wrapper(ForwardIter(buffer + 8)))); + ASSERT_SAME_TYPE(decltype(comm.end()), CommonForwardIter); + } + + { + const std::ranges::common_view comm(CopyableView{buffer}); + if (!std::is_constant_evaluated()) + assert(comm.end() == CommonIntIter(sentinel_wrapper(buffer + 8))); + ASSERT_SAME_TYPE(decltype(comm.end()), CommonIntIter); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/size.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/size.pass.cpp @@ -0,0 +1,88 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 + +// constexpr auto size() requires sized_range +// constexpr auto size() const requires sized_range + +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" +#include "test_range.h" + +struct CopyableView : std::ranges::view_base { + int *ptr_; + constexpr CopyableView(int* ptr) : ptr_(ptr) {} + constexpr friend int* begin(CopyableView& view) { return view.ptr_; } + constexpr friend int* begin(CopyableView const& view) { return view.ptr_; } + constexpr friend sentinel_wrapper end(CopyableView& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } + constexpr friend sentinel_wrapper end(CopyableView const& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } +}; + +using ForwardIter = forward_iterator; +struct SizedForwardView : std::ranges::view_base { + int *ptr_; + constexpr SizedForwardView(int* ptr) : ptr_(ptr) {} + constexpr friend ForwardIter begin(SizedForwardView& view) { return ForwardIter(view.ptr_); } + constexpr friend ForwardIter begin(SizedForwardView const& view) { return ForwardIter(view.ptr_); } + constexpr friend sentinel_wrapper end(SizedForwardView& view) { + return sentinel_wrapper{ForwardIter(view.ptr_ + 8)}; + } + constexpr friend sentinel_wrapper end(SizedForwardView const& view) { + return sentinel_wrapper{ForwardIter(view.ptr_ + 8)}; + } +}; + +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(); +} + +template +concept SizeEnabled = requires(const std::ranges::common_view& comm) { + comm.size(); +}; + +constexpr bool test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + static_assert( SizeEnabled); + static_assert(!SizeEnabled); + } + + { + std::ranges::common_view common(SizedForwardView{buffer}); + assert(common.size() == 8); + } + + { + const std::ranges::common_view common(SizedForwardView{buffer}); + assert(common.size() == 8); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} 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 @@ -924,6 +924,8 @@ return base_ == other; } + constexpr I base() const { return base_; } + private: I base_ = I(); };