diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -145,5 +145,5 @@ `[range.single] `_,single_view,[view.interface],Zoe Carver,In Progress `[range.split] `_,split_view,[range.all],Unassigned,Not started `[range.counted] `_,view::counted,[range.subrange],Zoe Carver,Not started -`[range.common] `_,common_view,[range.all],Zoe Carver,In Progress +`[range.common] `_,common_view,[range.all],Zoe Carver,✅ `[range.reverse] `_,reverse_view,[range.all],Unassigned,Not started 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/dangling.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,113 @@ +// -*- 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 <__iterator/iterator_traits.h> +#include <__ranges/access.h> +#include <__ranges/all.h> +#include <__ranges/concepts.h> +#include <__ranges/enable_borrowed_range.h> +#include <__ranges/size.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: + _LIBCPP_HIDE_FROM_ABI + common_view() requires default_initializable<_View> = default; + + _LIBCPP_HIDE_FROM_ABI + constexpr explicit common_view(_View __v) : __base_(_VSTD::move(__v)) { } + + _LIBCPP_HIDE_FROM_ABI + constexpr _View base() const& requires copy_constructible<_View> { return __base_; } + + _LIBCPP_HIDE_FROM_ABI + constexpr _View base() && { return _VSTD::move(__base_); } + + _LIBCPP_HIDE_FROM_ABI + 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_)); + } + + _LIBCPP_HIDE_FROM_ABI + 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_)); + } + + _LIBCPP_HIDE_FROM_ABI + 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_)); + } + + _LIBCPP_HIDE_FROM_ABI + 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_)); + } + + _LIBCPP_HIDE_FROM_ABI + constexpr auto size() requires sized_range<_View> { + return ranges::size(__base_); + } + + _LIBCPP_HIDE_FROM_ABI + constexpr auto size() const requires sized_range { + return ranges::size(__base_); + } +}; + +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 @@ -613,6 +613,7 @@ module __ranges { module access { private header "__ranges/access.h" } module all { private header "__ranges/all.h" } + module common_view { private header "__ranges/common_view.h" } module concepts { private header "__ranges/concepts.h" } module copyable_box { private header "__ranges/copyable_box.h" } module dangling { private header "__ranges/dangling.h" } diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -146,6 +146,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; } */ @@ -153,6 +160,7 @@ #include <__config> #include <__ranges/access.h> #include <__ranges/all.h> +#include <__ranges/common_view.h> #include <__ranges/concepts.h> #include <__ranges/dangling.h> #include <__ranges/data.h> diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/ranges/common_view.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/common_view.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/common_view.module.verify.cpp @@ -0,0 +1,16 @@ +// -*- 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 +// +//===----------------------------------------------------------------------===// + +// REQUIRES: modules-build + +// WARNING: This test was generated by 'generate_private_header_tests.py' +// and should not be edited manually. + +// expected-error@*:* {{use of private header from outside its module: '__ranges/common_view.h'}} +#include <__ranges/common_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,94 @@ +//===----------------------------------------------------------------------===// +// +// 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); + + ASSERT_SAME_TYPE(decltype(common.base()), CopyableView); + ASSERT_SAME_TYPE(decltype(std::move(common).base()), CopyableView); + static_assert(hasLValueQualifiedBase(common)); + } + + { + std::ranges::common_view common(ContiguousView{buffer}); + assert(std::move(common).base().ptr_ == buffer); + + ASSERT_SAME_TYPE(decltype(std::move(common).base()), ContiguousView); + static_assert(!hasLValueQualifiedBase(common)); + } + + { + const std::ranges::common_view common(CopyableView{buffer}); + assert(common.base().ptr_ == buffer); + assert(std::move(common).base().ptr_ == buffer); + + ASSERT_SAME_TYPE(decltype(common.base()), CopyableView); + ASSERT_SAME_TYPE(decltype(std::move(common).base()), CopyableView); + 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,160 @@ +//===----------------------------------------------------------------------===// +// +// 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)}; + } +}; +// 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(); +} + +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)}; + } +}; +// 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(); +} + +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(SizedRandomAccessView{buffer}); + assert(comm.begin() == begin(SizedRandomAccessView(buffer))); + ASSERT_SAME_TYPE(decltype(comm.begin()), RandomAccessIter); + } + + { + const std::ranges::common_view comm(SizedRandomAccessView{buffer}); + assert(comm.begin() == begin(SizedRandomAccessView(buffer))); + ASSERT_SAME_TYPE(decltype(comm.begin()), RandomAccessIter); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + // The non-constexpr tests: + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + std::ranges::common_view comm(SizedForwardView{buffer}); + assert(comm.begin() == begin(SizedForwardView(buffer))); + ASSERT_SAME_TYPE(decltype(comm.begin()), std::common_iterator>); + } + + { + std::ranges::common_view comm(ContiguousView{buffer}); + assert(comm.begin() == begin(ContiguousView(buffer))); + ASSERT_SAME_TYPE(decltype(comm.begin()), std::common_iterator>); + } + + { + const std::ranges::common_view comm(SizedForwardView{buffer}); + assert(comm.begin() == begin(SizedForwardView(buffer))); + ASSERT_SAME_TYPE(decltype(comm.begin()), std::common_iterator>); + } + + { + const std::ranges::common_view comm(CopyableView{buffer}); + assert(comm.begin() == begin(CopyableView(buffer))); + ASSERT_SAME_TYPE(decltype(comm.begin()), std::common_iterator>); + } + + 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,39 @@ +//===----------------------------------------------------------------------===// +// +// 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_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_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(BorrowedRange&); + friend int* begin(BorrowedRange const&); + friend sentinel_wrapper end(BorrowedRange&); + friend sentinel_wrapper end(BorrowedRange 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)) invalid. RValue range must be borrowed. + 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, std::ranges::subrange_kind::unsized>> + >); +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/ctor.default.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/ctor.default.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/ctor.default.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 + +// common_view() requires default_initializable = default; + +#include +#include + +#include "test_iterators.h" +#include "test_range.h" + +int globalBuffer[4] = {1,2,3,4}; + +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 = globalBuffer) : 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_ + 4}; + } + constexpr friend sentinel_wrapper end(CopyableView const& view) { + return sentinel_wrapper{view.ptr_ + 4}; + } +}; + +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); +}; + +int main(int, char**) { + static_assert(!std::default_initializable>); + static_assert( std::default_initializable>); + + std::ranges::common_view common; + assert(*common.begin() == 1); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.common.view/ctor.view.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.common.view/ctor.view.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.common.view/ctor.view.pass.cpp @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// 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 explicit common_view(V r); + +#include +#include + +#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; + friend constexpr int* begin(ContiguousView& view) { return view.ptr_; } + friend constexpr int* begin(ContiguousView const& view) { return view.ptr_; } + friend constexpr sentinel_wrapper end(ContiguousView& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } + friend constexpr 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) {} + friend constexpr int* begin(CopyableView& view) { return view.ptr_; } + friend constexpr int* begin(CopyableView const& view) { return view.ptr_; } + friend constexpr sentinel_wrapper end(CopyableView& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } + friend constexpr sentinel_wrapper end(CopyableView const& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } +}; + +constexpr bool test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + std::ranges::common_view common(ContiguousView{buffer}); + assert(std::move(common).base().ptr_ == buffer); + } + + { + ContiguousView v{buffer}; + std::ranges::common_view common(std::move(v)); + assert(std::move(common).base().ptr_ == buffer); + } + + { + const CopyableView v{buffer}; + const std::ranges::common_view common(v); + assert(common.base().ptr_ == buffer); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + const std::ranges::common_view common(ContiguousView{buffer}); + assert(common.begin() == buffer); + + 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,132 @@ +//===----------------------------------------------------------------------===// +// +// 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) {} + friend constexpr int* begin(CopyableView& view) { return view.ptr_; } + friend constexpr int* begin(CopyableView const& view) { return view.ptr_; } + friend constexpr sentinel_wrapper end(CopyableView& view) { + return sentinel_wrapper{view.ptr_ + 8}; + } + friend constexpr 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) {} + friend constexpr ForwardIter begin(SizedForwardView& view) { return ForwardIter(view.ptr_); } + friend constexpr ForwardIter begin(SizedForwardView const& view) { return ForwardIter(view.ptr_); } + friend constexpr sentinel_wrapper end(SizedForwardView& view) { + return sentinel_wrapper{ForwardIter(view.ptr_ + 8)}; + } + friend constexpr 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) {} + friend constexpr RandomAccessIter begin(SizedRandomcAccessView& view) { return RandomAccessIter(view.ptr_); } + friend constexpr RandomAccessIter begin(SizedRandomcAccessView const& view) { return RandomAccessIter(view.ptr_); } + friend constexpr sentinel_wrapper end(SizedRandomcAccessView& view) { + return sentinel_wrapper{RandomAccessIter(view.ptr_ + 8)}; + } + friend constexpr 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}; + + { + 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(SizedRandomcAccessView{buffer}); + assert(comm.end().base() == buffer + 8); + // Note this should NOT be the sentinel type. + ASSERT_SAME_TYPE(decltype(comm.end()), RandomAccessIter); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(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(SizedForwardView{buffer}); + assert(comm.end() == CommonForwardIter(sentinel_wrapper(ForwardIter(buffer + 8)))); + ASSERT_SAME_TYPE(decltype(comm.end()), CommonForwardIter); + } + + { + std::ranges::common_view comm(CopyableView{buffer}); + assert(comm.end() == CommonIntIter(sentinel_wrapper(buffer + 8))); + ASSERT_SAME_TYPE(decltype(comm.end()), CommonIntIter); + } + + { + const std::ranges::common_view comm(SizedForwardView{buffer}); + assert(comm.end() == CommonForwardIter(sentinel_wrapper(ForwardIter(buffer + 8)))); + ASSERT_SAME_TYPE(decltype(comm.end()), CommonForwardIter); + } + + { + const std::ranges::common_view comm(CopyableView{buffer}); + assert(comm.end() == CommonIntIter(sentinel_wrapper(buffer + 8))); + ASSERT_SAME_TYPE(decltype(comm.end()), CommonIntIter); + } + + 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,87 @@ +//===----------------------------------------------------------------------===// +// +// 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_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,9 @@ return base_ == other; } + constexpr const I& base() const& { return base_; } + constexpr I base() && { return std::move(base_); } + private: I base_ = I(); };