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/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp --- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp +++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_count_sentinel.pass.cpp @@ -31,12 +31,12 @@ return false; } - constexpr friend std::ptrdiff_t operator-(std::input_or_output_iterator auto const&, + friend constexpr std::ptrdiff_t operator-(std::input_or_output_iterator auto const&, distance_apriori_sentinel const y) { return -y.count_; } - constexpr friend std::ptrdiff_t operator-(distance_apriori_sentinel const x, + friend constexpr std::ptrdiff_t operator-(distance_apriori_sentinel const x, std::input_or_output_iterator auto const&) { return x.count_; } diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp --- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp +++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.advance/iterator_sentinel.pass.cpp @@ -31,12 +31,12 @@ return false; } - constexpr friend std::ptrdiff_t operator-(std::input_or_output_iterator auto const&, + friend constexpr std::ptrdiff_t operator-(std::input_or_output_iterator auto const&, distance_apriori_sentinel const y) { return -y.count_; } - constexpr friend std::ptrdiff_t operator-(distance_apriori_sentinel const x, + friend constexpr std::ptrdiff_t operator-(distance_apriori_sentinel const x, std::input_or_output_iterator auto const&) { return x.count_; } diff --git a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_sentinel.pass.cpp b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_sentinel.pass.cpp --- a/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_sentinel.pass.cpp +++ b/libcxx/test/std/iterators/iterator.primitives/range.iter.ops/range.iter.ops.next/iterator_sentinel.pass.cpp @@ -32,12 +32,12 @@ return false; } - constexpr friend std::ptrdiff_t operator-(std::input_or_output_iterator auto const&, + friend constexpr std::ptrdiff_t operator-(std::input_or_output_iterator auto const&, distance_apriori_sentinel const y) { return -y.count_; } - constexpr friend std::ptrdiff_t operator-(distance_apriori_sentinel const x, + friend constexpr std::ptrdiff_t operator-(distance_apriori_sentinel const x, std::input_or_output_iterator auto const&) { return x.count_; } diff --git a/libcxx/test/std/ranges/range.access/range.prim/data.pass.cpp b/libcxx/test/std/ranges/range.access/range.prim/data.pass.cpp --- a/libcxx/test/std/ranges/range.access/range.prim/data.pass.cpp +++ b/libcxx/test/std/ranges/range.access/range.prim/data.pass.cpp @@ -123,7 +123,7 @@ struct BeginFriendContiguousIterator { int buff[8]; - constexpr friend ContiguousIter begin(const BeginFriendContiguousIterator &iter) { + friend constexpr ContiguousIter begin(const BeginFriendContiguousIterator &iter) { return ContiguousIter(iter.buff); } }; diff --git a/libcxx/test/std/ranges/range.adaptors/range.all.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.all.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.all.pass.cpp @@ -27,10 +27,10 @@ constexpr explicit View(int start) : start_(start) {} View(View&&) noexcept(IsNoexcept) = default; View& operator=(View&&) noexcept(IsNoexcept) = default; - constexpr friend int* begin(View& view) { return globalBuff + view.start_; } - constexpr friend int* begin(View const& view) { return globalBuff + view.start_; } - constexpr friend int* end(View&) { return globalBuff + 8; } - constexpr friend int* end(View const&) { return globalBuff + 8; } + friend constexpr int* begin(View& view) { return globalBuff + view.start_; } + friend constexpr int* begin(View const& view) { return globalBuff + view.start_; } + friend constexpr int* end(View&) { return globalBuff + 8; } + friend constexpr int* end(View const&) { return globalBuff + 8; } }; static_assert(std::ranges::view>); static_assert(std::ranges::view>); @@ -42,10 +42,10 @@ CopyableView(CopyableView const&) noexcept(IsNoexcept) = default; CopyableView& operator=(CopyableView const&) noexcept(IsNoexcept) = default; constexpr explicit CopyableView(int start) noexcept : start_(start) {} - constexpr friend int* begin(CopyableView& view) { return globalBuff + view.start_; } - constexpr friend int* begin(CopyableView const& view) { return globalBuff + view.start_; } - constexpr friend int* end(CopyableView&) { return globalBuff + 8; } - constexpr friend int* end(CopyableView const&) { return globalBuff + 8; } + friend constexpr int* begin(CopyableView& view) { return globalBuff + view.start_; } + friend constexpr int* begin(CopyableView const& view) { return globalBuff + view.start_; } + friend constexpr int* end(CopyableView&) { return globalBuff + 8; } + friend constexpr int* end(CopyableView const&) { return globalBuff + 8; } }; static_assert(std::ranges::view>); static_assert(std::ranges::view>); @@ -53,19 +53,19 @@ struct Range { int start_; constexpr explicit Range(int start) noexcept : start_(start) {} - constexpr friend int* begin(Range const& range) { return globalBuff + range.start_; } - constexpr friend int* begin(Range& range) { return globalBuff + range.start_; } - constexpr friend int* end(Range const&) { return globalBuff + 8; } - constexpr friend int* end(Range&) { return globalBuff + 8; } + friend constexpr int* begin(Range const& range) { return globalBuff + range.start_; } + friend constexpr int* begin(Range& range) { return globalBuff + range.start_; } + friend constexpr int* end(Range const&) { return globalBuff + 8; } + friend constexpr int* end(Range&) { return globalBuff + 8; } }; struct BorrowableRange { int start_; constexpr explicit BorrowableRange(int start) noexcept : start_(start) {} - constexpr friend int* begin(BorrowableRange const& range) { return globalBuff + range.start_; } - constexpr friend int* begin(BorrowableRange& range) { return globalBuff + range.start_; } - constexpr friend int* end(BorrowableRange const&) { return globalBuff + 8; } - constexpr friend int* end(BorrowableRange&) { return globalBuff + 8; } + friend constexpr int* begin(BorrowableRange const& range) { return globalBuff + range.start_; } + friend constexpr int* begin(BorrowableRange& range) { return globalBuff + range.start_; } + friend constexpr int* end(BorrowableRange const&) { return globalBuff + 8; } + friend constexpr int* end(BorrowableRange&) { return globalBuff + 8; } }; template<> inline constexpr bool std::ranges::enable_borrowed_range = true; 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; + 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 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; + 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}; + } +}; + +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) {} + 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)}; + } +}; +// 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) {} + friend constexpr RandomAccessIter begin(SizedRandomAccessView& view) { return RandomAccessIter(view.ptr_); } + friend constexpr RandomAccessIter begin(SizedRandomAccessView const& view) { return RandomAccessIter(view.ptr_); } + friend constexpr sentinel_wrapper end(SizedRandomAccessView& view) { + return sentinel_wrapper{RandomAccessIter(view.ptr_ + 8)}; + } + friend constexpr 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; + 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 = globalBuffer) : 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_ + 4}; + } + friend constexpr 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,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 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}); + 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) {} + 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}; + + 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,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) {} + 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(); +} + +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/std/ranges/range.adaptors/range.drop/types.h b/libcxx/test/std/ranges/range.adaptors/range.drop/types.h --- a/libcxx/test/std/ranges/range.adaptors/range.drop/types.h +++ b/libcxx/test/std/ranges/range.adaptors/range.drop/types.h @@ -19,10 +19,10 @@ constexpr ContiguousView(int start = 0) : start_(start) {} constexpr ContiguousView(ContiguousView&&) = default; constexpr ContiguousView& operator=(ContiguousView&&) = default; - constexpr friend int* begin(ContiguousView& view) { return globalBuff + view.start_; } - constexpr friend int* begin(ContiguousView const& view) { return globalBuff + view.start_; } - constexpr friend int* end(ContiguousView&) { return globalBuff + 8; } - constexpr friend int* end(ContiguousView const&) { return globalBuff + 8; } + friend constexpr int* begin(ContiguousView& view) { return globalBuff + view.start_; } + friend constexpr int* begin(ContiguousView const& view) { return globalBuff + view.start_; } + friend constexpr int* end(ContiguousView&) { return globalBuff + 8; } + friend constexpr int* end(ContiguousView const&) { return globalBuff + 8; } }; struct CopyableView : std::ranges::view_base { @@ -30,10 +30,10 @@ constexpr CopyableView(int start = 0) : start_(start) {} constexpr CopyableView(CopyableView const&) = default; constexpr CopyableView& operator=(CopyableView const&) = default; - constexpr friend int* begin(CopyableView& view) { return globalBuff + view.start_; } - constexpr friend int* begin(CopyableView const& view) { return globalBuff + view.start_; } - constexpr friend int* end(CopyableView&) { return globalBuff + 8; } - constexpr friend int* end(CopyableView const&) { return globalBuff + 8; } + friend constexpr int* begin(CopyableView& view) { return globalBuff + view.start_; } + friend constexpr int* begin(CopyableView const& view) { return globalBuff + view.start_; } + friend constexpr int* end(CopyableView&) { return globalBuff + 8; } + friend constexpr int* end(CopyableView const&) { return globalBuff + 8; } }; using ForwardIter = forward_iterator; @@ -41,10 +41,10 @@ constexpr ForwardView() = default; constexpr ForwardView(ForwardView&&) = default; constexpr ForwardView& operator=(ForwardView&&) = default; - constexpr friend ForwardIter begin(ForwardView&) { return ForwardIter(globalBuff); } - constexpr friend ForwardIter begin(ForwardView const&) { return ForwardIter(globalBuff); } - constexpr friend ForwardIter end(ForwardView&) { return ForwardIter(globalBuff + 8); } - constexpr friend ForwardIter end(ForwardView const&) { return ForwardIter(globalBuff + 8); } + friend constexpr ForwardIter begin(ForwardView&) { return ForwardIter(globalBuff); } + friend constexpr ForwardIter begin(ForwardView const&) { return ForwardIter(globalBuff); } + friend constexpr ForwardIter end(ForwardView&) { return ForwardIter(globalBuff + 8); } + friend constexpr ForwardIter end(ForwardView const&) { return ForwardIter(globalBuff + 8); } }; struct ForwardRange { 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 @@ -16,10 +16,10 @@ constexpr ContiguousView(int* ptr = globalBuff, int start = 0) : start_(start), ptr_(ptr) {} constexpr ContiguousView(ContiguousView&&) = default; constexpr ContiguousView& operator=(ContiguousView&&) = default; - constexpr friend int* begin(ContiguousView& view) { return view.ptr_ + view.start_; } - constexpr friend int* begin(ContiguousView const& view) { return view.ptr_ + view.start_; } - constexpr friend int* end(ContiguousView& view) { return view.ptr_ + 8; } - constexpr friend int* end(ContiguousView const& view) { return view.ptr_ + 8; } + friend constexpr int* begin(ContiguousView& view) { return view.ptr_ + view.start_; } + friend constexpr int* begin(ContiguousView const& view) { return view.ptr_ + view.start_; } + friend constexpr int* end(ContiguousView& view) { return view.ptr_ + 8; } + friend constexpr int* end(ContiguousView const& view) { return view.ptr_ + 8; } }; struct CopyableView : std::ranges::view_base { @@ -27,10 +27,10 @@ constexpr CopyableView(int start = 0) : start_(start) {} constexpr CopyableView(CopyableView const&) = default; constexpr CopyableView& operator=(CopyableView const&) = default; - constexpr friend int* begin(CopyableView& view) { return globalBuff + view.start_; } - constexpr friend int* begin(CopyableView const& view) { return globalBuff + view.start_; } - constexpr friend int* end(CopyableView&) { return globalBuff + 8; } - constexpr friend int* end(CopyableView const&) { return globalBuff + 8; } + friend constexpr int* begin(CopyableView& view) { return globalBuff + view.start_; } + friend constexpr int* begin(CopyableView const& view) { return globalBuff + view.start_; } + friend constexpr int* end(CopyableView&) { return globalBuff + 8; } + friend constexpr int* end(CopyableView const&) { return globalBuff + 8; } }; using ForwardIter = forward_iterator; @@ -39,10 +39,10 @@ constexpr ForwardView(int* ptr = globalBuff) : ptr_(ptr) {} constexpr ForwardView(ForwardView&&) = default; constexpr ForwardView& operator=(ForwardView&&) = default; - constexpr friend ForwardIter begin(ForwardView& view) { return ForwardIter(view.ptr_); } - constexpr friend ForwardIter begin(ForwardView const& view) { return ForwardIter(view.ptr_); } - constexpr friend ForwardIter end(ForwardView& view) { return ForwardIter(view.ptr_ + 8); } - constexpr friend ForwardIter end(ForwardView const& view) { return ForwardIter(view.ptr_ + 8); } + friend constexpr ForwardIter begin(ForwardView& view) { return ForwardIter(view.ptr_); } + friend constexpr ForwardIter begin(ForwardView const& view) { return ForwardIter(view.ptr_); } + friend constexpr ForwardIter end(ForwardView& view) { return ForwardIter(view.ptr_ + 8); } + friend constexpr ForwardIter end(ForwardView const& view) { return ForwardIter(view.ptr_ + 8); } }; using ForwardRange = test_common_range; diff --git a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp --- a/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp +++ b/libcxx/test/std/utilities/optional/optional.object/optional.object.assign/emplace.pass.cpp @@ -31,7 +31,7 @@ constexpr X(int i) : i_(i) {} constexpr X(int i, int j) : i_(i), j_(j) {} - constexpr friend bool operator==(const X& x, const X& y) + friend constexpr bool operator==(const X& x, const X& y) {return x.i_ == y.i_ && x.j_ == y.j_;} }; 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 @@ -848,25 +848,25 @@ return *this; } - constexpr friend stride_counting_iterator operator+(stride_counting_iterator i, difference_type const n) + friend constexpr stride_counting_iterator operator+(stride_counting_iterator i, difference_type const n) requires std::random_access_iterator { return i += n; } - constexpr friend stride_counting_iterator operator+(difference_type const n, stride_counting_iterator i) + friend constexpr stride_counting_iterator operator+(difference_type const n, stride_counting_iterator i) requires std::random_access_iterator { return i += n; } - constexpr friend stride_counting_iterator operator-(stride_counting_iterator i, difference_type const n) + friend constexpr stride_counting_iterator operator-(stride_counting_iterator i, difference_type const n) requires std::random_access_iterator { return i -= n; } - constexpr friend difference_type operator-(stride_counting_iterator const& x, stride_counting_iterator const& y) + friend constexpr difference_type operator-(stride_counting_iterator const& x, stride_counting_iterator const& y) requires std::sized_sentinel_for { return x.base() - y.base(); @@ -884,25 +884,25 @@ return base_ == last; } - constexpr friend bool operator<(stride_counting_iterator const& x, stride_counting_iterator const& y) + friend constexpr bool operator<(stride_counting_iterator const& x, stride_counting_iterator const& y) requires std::random_access_iterator { return x.base_ < y.base_; } - constexpr friend bool operator>(stride_counting_iterator const& x, stride_counting_iterator const& y) + friend constexpr bool operator>(stride_counting_iterator const& x, stride_counting_iterator const& y) requires std::random_access_iterator { return y < x; } - constexpr friend bool operator<=(stride_counting_iterator const& x, stride_counting_iterator const& y) + friend constexpr bool operator<=(stride_counting_iterator const& x, stride_counting_iterator const& y) requires std::random_access_iterator { return !(y < x); } - constexpr friend bool operator>=(stride_counting_iterator const& x, stride_counting_iterator const& y) + friend constexpr bool operator>=(stride_counting_iterator const& x, stride_counting_iterator const& y) requires std::random_access_iterator { return !(x < y); @@ -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(); }; diff --git a/libcxx/test/support/type_classification/swappable.h b/libcxx/test/support/type_classification/swappable.h --- a/libcxx/test/support/type_classification/swappable.h +++ b/libcxx/test/support/type_classification/swappable.h @@ -34,7 +34,7 @@ return *this; } - constexpr friend void swap(lvalue_adl_swappable& x, + friend constexpr void swap(lvalue_adl_swappable& x, lvalue_adl_swappable& y) noexcept { std::ranges::swap(x.value_, y.value_); } @@ -70,7 +70,7 @@ return *this; } - constexpr friend void swap(lvalue_rvalue_adl_swappable& x, + friend constexpr void swap(lvalue_rvalue_adl_swappable& x, lvalue_rvalue_adl_swappable&& y) noexcept { std::ranges::swap(x.value_, y.value_); } @@ -107,7 +107,7 @@ return *this; } - constexpr friend void swap(rvalue_lvalue_adl_swappable&& x, + friend constexpr void swap(rvalue_lvalue_adl_swappable&& x, rvalue_lvalue_adl_swappable& y) noexcept { std::ranges::swap(x.value_, y.value_); } @@ -142,7 +142,7 @@ return *this; } - constexpr friend void swap(rvalue_adl_swappable&& x, + friend constexpr void swap(rvalue_adl_swappable&& x, rvalue_adl_swappable&& y) noexcept { std::ranges::swap(x.value_, y.value_); } @@ -179,7 +179,7 @@ return *this; } - constexpr friend void swap(non_move_constructible_adl_swappable& x, + friend constexpr void swap(non_move_constructible_adl_swappable& x, non_move_constructible_adl_swappable& y) noexcept { std::ranges::swap(x.value_, y.value_); } @@ -212,7 +212,7 @@ constexpr non_move_assignable_adl_swappable& operator=(non_move_assignable_adl_swappable&& other) noexcept = delete; - constexpr friend void swap(non_move_assignable_adl_swappable& x, + friend constexpr void swap(non_move_assignable_adl_swappable& x, non_move_assignable_adl_swappable& y) noexcept { std::ranges::swap(x.value_, y.value_); } @@ -248,7 +248,7 @@ return *this; } - constexpr friend void swap(throwable_adl_swappable& X, + friend constexpr void swap(throwable_adl_swappable& X, throwable_adl_swappable& Y) noexcept(false) { std::ranges::swap(X.value_, Y.value_); }