diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -202,6 +202,6 @@ "`P2367R0 `__","LWG",Remove misuses of list-initialization from Clause 24,"June 2021","","" "","","","","","" "`P2372R3 `__","LWG","Fixing locale handling in chrono formatters","October 2021","","" -"`P2415R2 `__","LWG","What is a ``view``","October 2021","","" +"`P2415R2 `__","LWG","What is a ``view``","October 2021","|Complete|","14.0" "`P2418R2 `__","LWG","Add support for ``std::generator``-like types to ``std::format``","October 2021","","" "`P2432R1 `__","LWG","Fix ``istream_view``","October 2021","","" diff --git a/libcxx/docs/Status/RangesIssues.csv b/libcxx/docs/Status/RangesIssues.csv --- a/libcxx/docs/Status/RangesIssues.csv +++ b/libcxx/docs/Status/RangesIssues.csv @@ -29,5 +29,5 @@ `P2281R1 `__,Clarifying range adaptor objects,, `P2367R0 `__,Remove misuses of list-initialization from Clause 24,, -`P2415 `__,"What is a ``view``",, +`P2415 `__,"What is a ``view``",|Complete|,14.0 `P2432 `__,"Fix ``istream_view``",, diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -325,6 +325,7 @@ __ranges/iota_view.h __ranges/join_view.h __ranges/non_propagating_cache.h + __ranges/owning_view.h __ranges/range_adaptor.h __ranges/ref_view.h __ranges/reverse_view.h diff --git a/libcxx/include/__ranges/all.h b/libcxx/include/__ranges/all.h --- a/libcxx/include/__ranges/all.h +++ b/libcxx/include/__ranges/all.h @@ -14,9 +14,9 @@ #include <__iterator/iterator_traits.h> #include <__ranges/access.h> #include <__ranges/concepts.h> +#include <__ranges/owning_view.h> #include <__ranges/range_adaptor.h> #include <__ranges/ref_view.h> -#include <__ranges/subrange.h> #include <__utility/auto_cast.h> #include <__utility/declval.h> #include <__utility/forward.h> @@ -56,12 +56,12 @@ template requires (!ranges::view> && !requires (_Tp&& __t) { ranges::ref_view{_VSTD::forward<_Tp>(__t)}; } && - requires (_Tp&& __t) { ranges::subrange{_VSTD::forward<_Tp>(__t)}; }) + requires (_Tp&& __t) { ranges::owning_view{_VSTD::forward<_Tp>(__t)}; }) [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Tp&& __t) const - noexcept(noexcept(ranges::subrange{_VSTD::forward<_Tp>(__t)})) + noexcept(noexcept(ranges::owning_view{_VSTD::forward<_Tp>(__t)})) { - return ranges::subrange{_VSTD::forward<_Tp>(__t)}; + return ranges::owning_view{_VSTD::forward<_Tp>(__t)}; } }; } diff --git a/libcxx/include/__ranges/concepts.h b/libcxx/include/__ranges/concepts.h --- a/libcxx/include/__ranges/concepts.h +++ b/libcxx/include/__ranges/concepts.h @@ -9,6 +9,9 @@ #ifndef _LIBCPP___RANGES_CONCEPTS_H #define _LIBCPP___RANGES_CONCEPTS_H +#include <__concepts/constructible.h> +#include <__concepts/movable.h> +#include <__concepts/same_as.h> #include <__config> #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> @@ -20,7 +23,7 @@ #include <__ranges/enable_borrowed_range.h> #include <__ranges/enable_view.h> #include <__ranges/size.h> -#include +#include #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -114,12 +117,20 @@ template concept common_range = range<_Tp> && same_as, sentinel_t<_Tp>>; - template + template + inline constexpr bool __is_std_initializer_list = false; + + template + inline constexpr bool __is_std_initializer_list> = true; + + template concept viewable_range = - range<_Tp> && ( - (view> && constructible_from, _Tp>) || - (!view> && borrowed_range<_Tp>) - ); + range<_Tp> && + ((view> && constructible_from, _Tp>) || + (!view> && + (is_lvalue_reference_v<_Tp> || + (movable> && !__is_std_initializer_list>)))); + } // namespace ranges #endif // !defined(_LIBCPP_HAS_NO_RANGES) diff --git a/libcxx/include/__ranges/owning_view.h b/libcxx/include/__ranges/owning_view.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/owning_view.h @@ -0,0 +1,81 @@ +// -*- 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_OWNING_VIEW_H +#define _LIBCPP___RANGES_OWNING_VIEW_H + +#include <__concepts/constructible.h> +#include <__concepts/movable.h> +#include <__config> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/data.h> +#include <__ranges/empty.h> +#include <__ranges/enable_borrowed_range.h> +#include <__ranges/size.h> +#include <__ranges/view_interface.h> +#include <__utility/move.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +namespace ranges { + template + requires movable<_Rp> && (!__is_std_initializer_list>) + class owning_view : public view_interface> { + _Rp __r_ = _Rp(); + +public: + owning_view() requires default_initializable<_Rp> = default; + _LIBCPP_HIDE_FROM_ABI constexpr owning_view(_Rp&& __r) : __r_(_VSTD::move(__r)) {} + + owning_view(owning_view&&) = default; + owning_view& operator=(owning_view&&) = default; + + _LIBCPP_HIDE_FROM_ABI constexpr _Rp& base() & noexcept { return __r_; } + _LIBCPP_HIDE_FROM_ABI constexpr const _Rp& base() const& noexcept { return __r_; } + _LIBCPP_HIDE_FROM_ABI constexpr _Rp&& base() && noexcept { return _VSTD::move(__r_); } + _LIBCPP_HIDE_FROM_ABI constexpr const _Rp&& base() const&& noexcept { return _VSTD::move(__r_); } + + _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_Rp> begin() { return ranges::begin(__r_); } + _LIBCPP_HIDE_FROM_ABI constexpr sentinel_t<_Rp> end() { return ranges::end(__r_); } + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const requires range { return ranges::begin(__r_); } + _LIBCPP_HIDE_FROM_ABI constexpr auto end() const requires range { return ranges::end(__r_); } + + _LIBCPP_HIDE_FROM_ABI constexpr bool empty() requires requires { ranges::empty(__r_); } + { return ranges::empty(__r_); } + _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const requires requires { ranges::empty(__r_); } + { return ranges::empty(__r_); } + + _LIBCPP_HIDE_FROM_ABI constexpr auto size() requires sized_range<_Rp> + { return ranges::size(__r_); } + _LIBCPP_HIDE_FROM_ABI constexpr auto size() const requires sized_range + { return ranges::size(__r_); } + + _LIBCPP_HIDE_FROM_ABI constexpr auto data() requires contiguous_range<_Rp> + { return ranges::data(__r_); } + _LIBCPP_HIDE_FROM_ABI constexpr auto data() const requires contiguous_range + { return ranges::data(__r_); } + }; + + template + inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Tp>; + +} // namespace ranges + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___RANGES_OWNING_VIEW_H diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -795,6 +795,7 @@ module iota_view { private header "__ranges/iota_view.h" } module join_view { private header "__ranges/join_view.h" } module non_propagating_cache { private header "__ranges/non_propagating_cache.h" } + module owning_view { private header "__ranges/owning_view.h" } module range_adaptor { private header "__ranges/range_adaptor.h" } module ref_view { private header "__ranges/ref_view.h" } module reverse_view { private header "__ranges/reverse_view.h" } diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -135,6 +135,13 @@ template inline constexpr bool enable_borrowed_range> = true; + template + requires see below + class owning_view; + + template + inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + // [range.drop], drop view template class drop_view; diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/ranges/owning_view.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/owning_view.module.verify.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/owning_view.module.verify.cpp @@ -0,0 +1,15 @@ +//===----------------------------------------------------------------------===// +// +// 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/owning_view.h'}} +#include <__ranges/owning_view.h> diff --git a/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/associative/map/range_concept_conformance.compile.pass.cpp @@ -27,7 +27,7 @@ static_assert(!std::ranges::random_access_range); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/associative/multimap/range_concept_conformance.compile.pass.cpp @@ -27,7 +27,7 @@ static_assert(!std::ranges::random_access_range); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/associative/multiset/range_concept_conformance.compile.pass.cpp @@ -26,7 +26,7 @@ static_assert(!std::ranges::random_access_range); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/associative/set/range_concept_conformance.compile.pass.cpp @@ -28,7 +28,7 @@ static_assert(!std::ranges::view); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::bidirectional_range); diff --git a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/array/range_concept_conformance.compile.pass.cpp @@ -27,7 +27,7 @@ static_assert(std::ranges::contiguous_range); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(!std::ranges::view); static_assert(std::same_as, range::const_iterator>); diff --git a/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/deque/range_concept_conformance.compile.pass.cpp @@ -27,7 +27,7 @@ static_assert(!std::ranges::view); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/forwardlist/range_concept_conformance.compile.pass.cpp @@ -27,7 +27,7 @@ static_assert(!std::ranges::view); static_assert(!std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/list/range_concept_conformance.compile.pass.cpp @@ -27,7 +27,7 @@ static_assert(!std::ranges::random_access_range); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector.bool/range_concept_conformance.compile.pass.cpp @@ -27,7 +27,7 @@ static_assert(!std::ranges::view); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/range_concept_conformance.compile.pass.cpp @@ -27,7 +27,7 @@ static_assert(!std::ranges::view); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/unord/unord.map/range_concept_conformance.compile.pass.cpp @@ -27,7 +27,7 @@ static_assert(!std::ranges::view); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/unord/unord.multimap/range_concept_conformance.compile.pass.cpp @@ -27,7 +27,7 @@ static_assert(!std::ranges::view); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/unord/unord.multiset/range_concept_conformance.compile.pass.cpp @@ -27,7 +27,7 @@ static_assert(!std::ranges::view); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/unord/unord.set/range_concept_conformance.compile.pass.cpp @@ -27,7 +27,7 @@ static_assert(!std::ranges::view); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.path/range_concept_conformance.compile.pass.cpp @@ -26,7 +26,7 @@ static_assert(!std::ranges::random_access_range); static_assert(!std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, fs::path::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp @@ -67,13 +67,8 @@ inline constexpr bool std::ranges::enable_borrowed_range = true; struct RandomAccessRange { - struct sentinel { - friend constexpr bool operator==(sentinel, const random_access_iterator rai) { return rai.base() == globalBuff + 8; } - friend constexpr std::ptrdiff_t operator-(sentinel, random_access_iterator) { return -8; } - friend constexpr std::ptrdiff_t operator-(random_access_iterator, sentinel) { return 8; } - }; - constexpr random_access_iterator begin() { return random_access_iterator{globalBuff}; } - constexpr sentinel end() { return {}; } + constexpr auto begin() { return random_access_iterator(globalBuff); } + constexpr auto end() { return sized_sentinel(random_access_iterator(globalBuff + 8)); } }; template<> inline constexpr bool std::ranges::enable_borrowed_range = true; @@ -114,32 +109,31 @@ assert(std::ranges::begin(ref) == globalBuff + 2); assert(std::ranges::end(ref) == globalBuff + 8); - static_assert(!std::is_invocable_v); - } + auto own = std::views::all(std::move(range)); + ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view); + assert(std::ranges::begin(own) == globalBuff + 2); + assert(std::ranges::end(own) == globalBuff + 8); - { - const Range range(2); - auto ref = std::views::all(range); - static_assert(!noexcept(std::views::all(range))); - ASSERT_SAME_TYPE(decltype(ref), std::ranges::ref_view); - assert(std::ranges::begin(ref) == globalBuff + 2); - assert(std::ranges::end(ref) == globalBuff + 8); + auto cref = std::views::all(std::as_const(range)); + ASSERT_SAME_TYPE(decltype(cref), std::ranges::ref_view); + assert(std::ranges::begin(cref) == globalBuff + 2); + assert(std::ranges::end(cref) == globalBuff + 8); + + static_assert(!std::is_invocable_v); } { - auto subrange = std::views::all(BorrowableRange(2)); - static_assert(!noexcept(std::views::all(BorrowableRange(2)))); - ASSERT_SAME_TYPE(decltype(subrange), std::ranges::subrange); - assert(std::ranges::begin(subrange) == globalBuff + 2); - assert(std::ranges::end(subrange) == globalBuff + 8); + auto own = std::views::all(BorrowableRange(2)); + ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view); + assert(std::ranges::begin(own) == globalBuff + 2); + assert(std::ranges::end(own) == globalBuff + 8); } { - auto subrange = std::views::all(RandomAccessRange()); - ASSERT_SAME_TYPE(decltype(subrange), - std::ranges::subrange, RandomAccessRange::sentinel>); - assert(std::ranges::begin(subrange).base() == globalBuff); - assert(std::ranges::end(subrange) == std::ranges::begin(subrange) + 8); + auto own = std::views::all(RandomAccessRange()); + ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view); + assert(base(std::ranges::begin(own)) == globalBuff); + assert(base(base(std::ranges::end(own))) == globalBuff + 8); } // Check SFINAE friendliness of the call operator diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp @@ -16,26 +16,49 @@ #include #include "test_iterators.h" -#include "test_range.h" -struct View : test_range, std::ranges::view_base { }; -struct Range : test_range { }; -struct BorrowableRange : test_range { }; +struct View : std::ranges::view_base { + int *begin() const; + int *end() const; +}; + +struct Range { + int *begin() const; + int *end() const; +}; + +struct BorrowableRange { + int *begin() const; + int *end() const; +}; template<> inline constexpr bool std::ranges::enable_borrowed_range = true; +template +concept HasAllT = requires { + typename std::views::all_t; +}; + // When T is a view, returns decay-copy(T) ASSERT_SAME_TYPE(std::views::all_t, View); ASSERT_SAME_TYPE(std::views::all_t, View); -ASSERT_SAME_TYPE(std::views::all_t, View); -ASSERT_SAME_TYPE(std::views::all_t, View); +ASSERT_SAME_TYPE(std::views::all_t, View); +ASSERT_SAME_TYPE(std::views::all_t, View); +ASSERT_SAME_TYPE(std::views::all_t, View); +ASSERT_SAME_TYPE(std::views::all_t, View); // Otherwise, when T is a reference to a range, returns ref_view ASSERT_SAME_TYPE(std::views::all_t, std::ranges::ref_view); -ASSERT_SAME_TYPE(std::views::all_t, std::ranges::ref_view); +ASSERT_SAME_TYPE(std::views::all_t, std::ranges::ref_view); ASSERT_SAME_TYPE(std::views::all_t, std::ranges::ref_view); -ASSERT_SAME_TYPE(std::views::all_t, std::ranges::ref_view); +ASSERT_SAME_TYPE(std::views::all_t, std::ranges::ref_view); -// Otherwise, returns subrange, sentinel_t> -ASSERT_SAME_TYPE(std::views::all_t, std::ranges::subrange, sentinel>); -ASSERT_SAME_TYPE(std::views::all_t, std::ranges::subrange, sentinel>); +// Otherwise, returns owning_view +ASSERT_SAME_TYPE(std::views::all_t, std::ranges::owning_view); +ASSERT_SAME_TYPE(std::views::all_t, std::ranges::owning_view); +static_assert(!HasAllT); +static_assert(!HasAllT); +ASSERT_SAME_TYPE(std::views::all_t, std::ranges::owning_view); +ASSERT_SAME_TYPE(std::views::all_t, std::ranges::owning_view); +static_assert(!HasAllT); +static_assert(!HasAllT); diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/base.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/base.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/base.pass.cpp @@ -0,0 +1,56 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// constexpr R& base() & noexcept { return r_; } +// constexpr const R& base() const& noexcept { return r_; } +// constexpr R&& base() && noexcept { return std::move(r_); } +// constexpr const R&& base() const&& noexcept { return std::move(r_); } + +#include + +#include +#include + +#include "test_macros.h" + +struct Base { + int *begin() const; + int *end() const; +}; + +constexpr bool test() +{ + using OwningView = std::ranges::owning_view; + OwningView ov; + std::same_as decltype(auto) b1 = static_cast(ov).base(); + std::same_as decltype(auto) b2 = static_cast(ov).base(); + std::same_as decltype(auto) b3 = static_cast(ov).base(); + std::same_as decltype(auto) b4 = static_cast(ov).base(); + + assert(&b1 == &b2); + assert(&b1 == &b3); + assert(&b1 == &b4); + + ASSERT_NOEXCEPT(static_cast(ov).base()); + ASSERT_NOEXCEPT(static_cast(ov).base()); + ASSERT_NOEXCEPT(static_cast(ov).base()); + ASSERT_NOEXCEPT(static_cast(ov).base()); + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/begin_end.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/begin_end.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/begin_end.pass.cpp @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + + +// constexpr iterator_t begin(); +// constexpr sentinel_t end(); +// constexpr auto begin() const requires range; +// constexpr auto end() const requires range; + +#include + +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" + +struct Base { + constexpr int *begin() { return nullptr; } + constexpr auto end() { return sentinel_wrapper(nullptr); } + constexpr char *begin() const { return nullptr; } + constexpr auto end() const { return sentinel_wrapper(nullptr); } +}; +static_assert(std::same_as, int*>); +static_assert(std::same_as, sentinel_wrapper>); +static_assert(std::same_as, char*>); +static_assert(std::same_as, sentinel_wrapper>); + +struct NoConst { + int* begin(); + sentinel_wrapper end(); +}; + +struct DecayChecker { + int*& begin() const; + int*& end() const; +}; + +template +concept HasBegin = requires (T t) { + t.begin(); +}; + +template +concept HasEnd = requires (T t) { + t.end(); +}; + +constexpr bool test() +{ + { + using OwningView = std::ranges::owning_view; + OwningView ov; + std::same_as decltype(auto) b1 = static_cast(ov).begin(); + std::same_as decltype(auto) b2 = static_cast(ov).begin(); + std::same_as decltype(auto) b3 = static_cast(ov).begin(); + std::same_as decltype(auto) b4 = static_cast(ov).begin(); + + std::same_as> decltype(auto) e1 = static_cast(ov).end(); + std::same_as> decltype(auto) e2 = static_cast(ov).end(); + std::same_as> decltype(auto) e3 = static_cast(ov).end(); + std::same_as> decltype(auto) e4 = static_cast(ov).end(); + + assert(b1 == e1); + assert(b2 == e2); + assert(b3 == e3); + assert(b4 == e4); + } + { + // NoConst has non-const begin() and end(); so does the owning_view. + using OwningView = std::ranges::owning_view; + static_assert(HasBegin); + static_assert(HasBegin); + static_assert(!HasBegin); + static_assert(!HasBegin); + static_assert(HasEnd); + static_assert(HasEnd); + static_assert(!HasEnd); + static_assert(!HasEnd); + } + { + // DecayChecker's begin() and end() return references; make sure the owning_view decays them. + using OwningView = std::ranges::owning_view; + OwningView ov; + ASSERT_SAME_TYPE(decltype(ov.begin()), int*); + ASSERT_SAME_TYPE(decltype(ov.end()), int*); + } + { + // Test an empty view. + int a[] = {1}; + auto ov = std::ranges::owning_view(std::ranges::subrange(a, a)); + assert(ov.begin() == a); + assert(std::as_const(ov).begin() == a); + assert(ov.end() == a); + assert(std::as_const(ov).end() == a); + } + { + // Test a non-empty view. + int a[] = {1}; + auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1)); + assert(ov.begin() == a); + assert(std::as_const(ov).begin() == a); + assert(ov.end() == a+1); + assert(std::as_const(ov).end() == a+1); + } + { + // Test a non-view. + std::array a = {1, 2}; + auto ov = std::ranges::owning_view(std::move(a)); + assert(ov.begin() != a.begin()); // because it points into the copy + assert(std::as_const(ov).begin() != a.begin()); + assert(ov.end() != a.end()); + assert(std::as_const(ov).end() != a.end()); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/borrowing.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/borrowing.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/borrowing.compile.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// template +// inline constexpr bool enable_borrowed_range> = enable_borrowed_range; + +#include +#include + +struct Range { + int *begin() const; + int *end() const; +}; + +struct BorrowableRange { + int *begin() const; + int *end() 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.all/range.owning.view/constructor.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/constructor.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/constructor.pass.cpp @@ -0,0 +1,140 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// owning_view() requires default_initializable = default; +// constexpr owning_view(R&& t); + +#include + +#include +#include +#include +#include + +#include "test_macros.h" + +struct DefaultConstructible { + int i; + constexpr explicit DefaultConstructible(int j = 42) : i(j) {} + int *begin() const; + int *end() const; +}; + +struct NotDefaultConstructible { + int i; + constexpr explicit NotDefaultConstructible(int j) : i(j) {} + int *begin() const; + int *end() const; +}; + +struct MoveChecker { + int i; + constexpr explicit MoveChecker(int j) : i(j) {} + constexpr MoveChecker(MoveChecker&& v) : i(std::exchange(v.i, -1)) {} + MoveChecker& operator=(MoveChecker&&); + int *begin() const; + int *end() const; +}; + +struct NoexceptChecker { + int *begin() const; + int *end() const; +}; + +constexpr bool test() +{ + { + using OwningView = std::ranges::owning_view; + static_assert(std::is_constructible_v); + static_assert(std::default_initializable); + static_assert(std::movable); + static_assert(std::is_trivially_move_constructible_v); + static_assert(std::is_trivially_move_assignable_v); + static_assert(!std::is_copy_constructible_v); + static_assert(!std::is_copy_assignable_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_convertible_v); + static_assert(std::is_convertible_v); + { + OwningView ov; + assert(ov.base().i == 42); + } + { + OwningView ov = OwningView(DefaultConstructible(1)); + assert(ov.base().i == 1); + } + } + { + using OwningView = std::ranges::owning_view; + static_assert(!std::is_constructible_v); + static_assert(!std::default_initializable); + static_assert(std::movable); + static_assert(std::is_trivially_move_constructible_v); + static_assert(std::is_trivially_move_assignable_v); + static_assert(!std::is_copy_constructible_v); + static_assert(!std::is_copy_assignable_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_convertible_v); + static_assert(std::is_convertible_v); + { + OwningView ov = OwningView(NotDefaultConstructible(1)); + assert(ov.base().i == 1); + } + } + { + using OwningView = std::ranges::owning_view; + static_assert(!std::is_constructible_v); + static_assert(!std::default_initializable); + static_assert(std::movable); + static_assert(!std::is_trivially_move_constructible_v); + static_assert(!std::is_trivially_move_assignable_v); + static_assert(!std::is_copy_constructible_v); + static_assert(!std::is_copy_assignable_v); + static_assert(!std::is_constructible_v); + static_assert(!std::is_constructible_v); + static_assert(std::is_constructible_v); + static_assert(!std::is_convertible_v); + static_assert(std::is_convertible_v); + { + // Check that the constructor does indeed move from the target object. + auto m = MoveChecker(42); + OwningView ov = OwningView(std::move(m)); + assert(ov.base().i == 42); + assert(m.i == -1); + } + } + { + // Check that the defaulted constructors are (not) noexcept when appropriate. + + static_assert( std::is_nothrow_constructible_v); // therefore, + static_assert( std::is_nothrow_constructible_v>); + static_assert(!std::is_nothrow_constructible_v); // therefore, + static_assert(!std::is_nothrow_constructible_v>); + + static_assert( std::is_nothrow_move_constructible_v); // therefore, + static_assert( std::is_nothrow_move_constructible_v>); + static_assert(!std::is_nothrow_move_constructible_v); // therefore, + static_assert(!std::is_nothrow_move_constructible_v>); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/data.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/data.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/data.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// constexpr auto data() requires contiguous_range +// constexpr auto data() const requires contiguous_range + +#include + +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" + +template +concept HasData = requires (T t) { + t.data(); +}; + +constexpr bool test() +{ + { + struct ContiguousIters { + contiguous_iterator begin(); + sentinel_wrapper> end(); + }; + using OwningView = std::ranges::owning_view; + static_assert(std::ranges::contiguous_range); + static_assert(!std::ranges::range); // no begin/end + static_assert(HasData); + static_assert(HasData); + static_assert(!HasData); + static_assert(!HasData); + } + { + struct NoData { + random_access_iterator begin(); + random_access_iterator end(); + }; + using OwningView = std::ranges::owning_view; + static_assert(!HasData); + static_assert(!HasData); + static_assert(!HasData); + static_assert(!HasData); + } + { + // Test a view. + int a[] = {1}; + auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1)); + assert(ov.data() == a); + assert(std::as_const(ov).data() == a); + } + { + // Test a non-view. + std::array a = {1, 2}; + auto ov = std::ranges::owning_view(std::move(a)); + assert(ov.data() != a.data()); // because it points into the copy + assert(std::as_const(ov).data() != a.data()); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/empty.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/empty.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/empty.pass.cpp @@ -0,0 +1,105 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// constexpr bool empty() requires requires { ranges::empty(r_); } +// constexpr bool empty() const requires requires { ranges::empty(r_); } + +#include + +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" + +template +concept HasEmpty = requires (T t) { + t.empty(); +}; + +constexpr bool test() +{ + { + struct ComparableIters { + forward_iterator begin(); + forward_iterator end(); + }; + using OwningView = std::ranges::owning_view; + static_assert(HasEmpty); + static_assert(HasEmpty); + static_assert(!HasEmpty); + static_assert(!HasEmpty); + } + { + struct NoEmpty { + cpp20_input_iterator begin(); + sentinel_wrapper> end(); + }; + static_assert(std::ranges::range); + static_assert(!std::invocable); + static_assert(!std::ranges::range); // no begin/end + static_assert(!std::invocable); + using OwningView = std::ranges::owning_view; + static_assert(!HasEmpty); + static_assert(!HasEmpty); + static_assert(!HasEmpty); + static_assert(!HasEmpty); + } + { + struct EmptyMember { + cpp20_input_iterator begin(); + sentinel_wrapper> end(); + bool empty() const; + }; + static_assert(std::ranges::range); + static_assert(std::invocable); + static_assert(!std::ranges::range); // no begin/end + static_assert(std::invocable); + using OwningView = std::ranges::owning_view; + static_assert(std::ranges::range); + static_assert(!std::ranges::range); // no begin/end + static_assert(HasEmpty); + static_assert(HasEmpty); + static_assert(HasEmpty); // but it still has empty() + static_assert(HasEmpty); + } + { + // Test an empty view. + int a[] = {1}; + auto ov = std::ranges::owning_view(std::ranges::subrange(a, a)); + assert(ov.empty()); + assert(std::as_const(ov).empty()); + } + { + // Test a non-empty view. + int a[] = {1}; + auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1)); + assert(!ov.empty()); + assert(!std::as_const(ov).empty()); + } + { + // Test a non-view. + std::array a = {1, 2}; + auto ov = std::ranges::owning_view(std::move(a)); + assert(!ov.empty()); + assert(!std::as_const(ov).empty()); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/size.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/size.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.all/range.owning.view/size.pass.cpp @@ -0,0 +1,99 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// constexpr auto size() requires sized_range +// constexpr auto size() const requires sized_range + +#include + +#include +#include +#include + +#include "test_iterators.h" +#include "test_macros.h" + +template +concept HasSize = requires (T t) { + t.size(); +}; + +constexpr bool test() +{ + { + struct SubtractableIters { + forward_iterator begin(); + sized_sentinel> end(); + }; + using OwningView = std::ranges::owning_view; + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::range); // no begin/end + static_assert(HasSize); + static_assert(HasSize); + static_assert(!HasSize); + static_assert(!HasSize); + } + { + struct NoSize { + bidirectional_iterator begin(); + bidirectional_iterator end(); + }; + using OwningView = std::ranges::owning_view; + static_assert(!HasSize); + static_assert(!HasSize); + static_assert(!HasSize); + static_assert(!HasSize); + } + { + struct SizeMember { + bidirectional_iterator begin(); + bidirectional_iterator end(); + int size() const; + }; + using OwningView = std::ranges::owning_view; + static_assert(std::ranges::sized_range); + static_assert(!std::ranges::range); // no begin/end + static_assert(HasSize); + static_assert(HasSize); + static_assert(!HasSize); // not a range, therefore no size() + static_assert(!HasSize); + } + { + // Test an empty view. + int a[] = {1}; + auto ov = std::ranges::owning_view(std::ranges::subrange(a, a)); + assert(ov.size() == 0); + assert(std::as_const(ov).size() == 0); + } + { + // Test a non-empty view. + int a[] = {1}; + auto ov = std::ranges::owning_view(std::ranges::subrange(a, a+1)); + assert(ov.size() == 1); + assert(std::as_const(ov).size() == 1); + } + { + // Test a non-view. + std::array a = {1, 2}; + auto ov = std::ranges::owning_view(std::move(a)); + assert(ov.size() == 2); + assert(std::as_const(ov).size() == 2); + } + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +} 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 --- 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 @@ -39,22 +39,29 @@ 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(std::move(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(std::move(r))), + std::ranges::common_view> + >); 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>> + std::ranges::common_view> >); } diff --git a/libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.drop/ctad.compile.pass.cpp @@ -11,22 +11,56 @@ // UNSUPPORTED: libcpp-has-no-incomplete-ranges // template -// drop_view(R&&, range_difference_t) -> drop_view>; +// drop_view(R&&, range_difference_t) -> drop_view>; #include +#include +#include -#include "test_macros.h" -#include "types.h" +struct View : std::ranges::view_base { + int *begin() const; + int *end() const; +}; -namespace ranges = std::ranges; +struct Range { + int *begin() const; + int *end() const; +}; -static_assert(std::same_as>); -static_assert(std::same_as>); -static_assert(std::same_as>); -static_assert(std::same_as>); +struct BorrowedRange { + int *begin() const; + int *end() const; +}; +template<> +inline constexpr bool std::ranges::enable_borrowed_range = true; -static_assert(std::same_as(), 0)), - ranges::drop_view>>); +void testCTAD() { + View v; + Range r; + BorrowedRange br; -static_assert(std::same_as>>); + static_assert(std::same_as< + decltype(std::ranges::drop_view(v, 0)), + std::ranges::drop_view + >); + static_assert(std::same_as< + decltype(std::ranges::drop_view(std::move(v), 0)), + std::ranges::drop_view + >); + static_assert(std::same_as< + decltype(std::ranges::drop_view(r, 0)), + std::ranges::drop_view> + >); + static_assert(std::same_as< + decltype(std::ranges::drop_view(std::move(r), 0)), + std::ranges::drop_view> + >); + static_assert(std::same_as< + decltype(std::ranges::drop_view(br, 0)), + std::ranges::drop_view> + >); + static_assert(std::same_as< + decltype(std::ranges::drop_view(std::move(br), 0)), + std::ranges::drop_view> + >); +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.join.view/ctad.compile.pass.cpp @@ -15,58 +15,55 @@ #include -#include "test_iterators.h" +struct Child { + int *begin() const; + int *end() const; +}; -template struct View : std::ranges::view_base { - // All friends here are defined to prevent GCC warnings. - friend T* begin(View&) { return nullptr; } - friend T* begin(View const&) { return nullptr; } - friend sentinel_wrapper end(View&) { return sentinel_wrapper(nullptr); } - friend sentinel_wrapper end(View const&) { return sentinel_wrapper(nullptr); } + Child *begin() const; + Child *end() const; }; -template struct Range { - friend T* begin(Range&) { return nullptr; } - friend T* begin(Range const&) { return nullptr; } - friend sentinel_wrapper end(Range&) { return sentinel_wrapper(nullptr); } - friend sentinel_wrapper end(Range const&) { return sentinel_wrapper(nullptr); } + Child *begin() const; + Child *end() const; }; -template struct BorrowedRange { - friend T* begin(BorrowedRange&) { return nullptr; } - friend T* begin(BorrowedRange const&) { return nullptr; } - friend sentinel_wrapper end(BorrowedRange&) { return sentinel_wrapper(nullptr); } - friend sentinel_wrapper end(BorrowedRange const&) { return sentinel_wrapper(nullptr); } + Child *begin() const; + Child *end() const; }; - template<> -inline constexpr bool std::ranges::enable_borrowed_range>> = true; +inline constexpr bool std::ranges::enable_borrowed_range = true; void testCTAD() { - View> v; - Range> r; - BorrowedRange> br; + View v; + Range r; + BorrowedRange br; static_assert(std::same_as< decltype(std::ranges::join_view(v)), - std::ranges::join_view>> + std::ranges::join_view + >); + static_assert(std::same_as< + decltype(std::ranges::join_view(std::move(v))), + std::ranges::join_view >); static_assert(std::same_as< decltype(std::ranges::join_view(r)), - std::ranges::join_view>>> + std::ranges::join_view> + >); + static_assert(std::same_as< + decltype(std::ranges::join_view(std::move(r))), + std::ranges::join_view> >); - // std::ranges::join_view(std::move(r)) invalid. RValue range must be borrowed. static_assert(std::same_as< decltype(std::ranges::join_view(br)), - std::ranges::join_view>>> + std::ranges::join_view> >); static_assert(std::same_as< decltype(std::ranges::join_view(std::move(br))), - std::ranges::join_view *, - sentinel_wrapper *>, - std::ranges::subrange_kind::unsized>> + std::ranges::join_view> >); } diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.compile.pass.cpp @@ -0,0 +1,69 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// template +// reverse_view(R&&) -> reverse_view>; + +#include + +#include +#include + +#include "test_iterators.h" + +struct View : std::ranges::view_base { + int *begin() const; + int *end() const; +}; + +struct Range { + int *begin() const; + int *end() const; +}; + +struct BorrowedRange { + int *begin() const; + int *end() 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::reverse_view(v)), + std::ranges::reverse_view + >); + static_assert(std::same_as< + decltype(std::ranges::reverse_view(std::move(v))), + std::ranges::reverse_view + >); + static_assert(std::same_as< + decltype(std::ranges::reverse_view(r)), + std::ranges::reverse_view> + >); + static_assert(std::same_as< + decltype(std::ranges::reverse_view(std::move(r))), + std::ranges::reverse_view> + >); + static_assert(std::same_as< + decltype(std::ranges::reverse_view(br)), + std::ranges::reverse_view> + >); + static_assert(std::same_as< + decltype(std::ranges::reverse_view(std::move(br))), + std::ranges::reverse_view> + >); +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.pass.cpp deleted file mode 100644 --- a/libcxx/test/std/ranges/range.adaptors/range.reverse/ctad.pass.cpp +++ /dev/null @@ -1,72 +0,0 @@ -//===----------------------------------------------------------------------===// -// -// 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: libcpp-has-no-incomplete-ranges - -// template -// reverse_view(R&&) -> reverse_view>; - -#include - -#include -#include - -#include "test_iterators.h" - -struct View : std::ranges::view_base { - friend int* begin(View&) { return nullptr; } - friend int* begin(View const&) { return nullptr; } - friend sentinel_wrapper end(View&) { return sentinel_wrapper(nullptr); } - friend sentinel_wrapper end(View const&) { return sentinel_wrapper(nullptr); } -}; - -struct Range { - friend int* begin(Range&) { return nullptr; } - friend int* begin(Range const&) { return nullptr; } - friend sentinel_wrapper end(Range&) { return sentinel_wrapper(nullptr); } - friend sentinel_wrapper end(Range const&) { return sentinel_wrapper(nullptr); } -}; - -struct BorrowedRange { - friend int* begin(BorrowedRange&) { return nullptr; } - friend int* begin(BorrowedRange const&) { return nullptr; } - friend sentinel_wrapper end(BorrowedRange&) { return sentinel_wrapper(nullptr); } - friend sentinel_wrapper end(BorrowedRange const&) { return sentinel_wrapper(nullptr); } -}; - -template<> -inline constexpr bool std::ranges::enable_borrowed_range = true; - -int main(int, char**) { - View v; - Range r; - BorrowedRange br; - - { - std::same_as> auto x = std::ranges::reverse_view(v); - (void)x; - } - { - std::same_as>> auto x = std::ranges::reverse_view(r); - (void)x; - // std::ranges::reverse_view(std::move(r)) is invalid. RValue range must be borrowed. - } - { - std::same_as>> auto x = std::ranges::reverse_view(br); - (void)x; - } - { - using Subrange = std::ranges::subrange, std::ranges::subrange_kind::unsized>; - std::same_as> auto x = std::ranges::reverse_view(std::move(br)); - (void)x; - } - - return 0; -} diff --git a/libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.take/ctad.compile.pass.cpp @@ -17,29 +17,20 @@ #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&); + int *begin() const; + int *end() const; }; struct Range { - friend int* begin(Range&); - friend int* begin(Range const&); - friend sentinel_wrapper end(Range&); - friend sentinel_wrapper end(Range const&); + int *begin() const; + int *end() const; }; struct BorrowedRange { - friend int* begin(BorrowedRange&); - friend int* begin(BorrowedRange const&); - friend sentinel_wrapper end(BorrowedRange&); - friend sentinel_wrapper end(BorrowedRange const&); + int *begin() const; + int *end() const; }; - template<> inline constexpr bool std::ranges::enable_borrowed_range = true; @@ -47,22 +38,29 @@ View v; Range r; BorrowedRange br; + static_assert(std::same_as< decltype(std::ranges::take_view(v, 0)), std::ranges::take_view >); + static_assert(std::same_as< + decltype(std::ranges::take_view(std::move(v), 0)), + std::ranges::take_view + >); static_assert(std::same_as< decltype(std::ranges::take_view(r, 0)), std::ranges::take_view> >); - // std::ranges::take_view(std::move(r), 0) invalid. RValue range must be borrowed. + static_assert(std::same_as< + decltype(std::ranges::take_view(std::move(r), 0)), + std::ranges::take_view> + >); static_assert(std::same_as< decltype(std::ranges::take_view(br, 0)), std::ranges::take_view> >); static_assert(std::same_as< decltype(std::ranges::take_view(std::move(br), 0)), - std::ranges::take_view, std::ranges::subrange_kind::unsized>> + std::ranges::take_view> >); } diff --git a/libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.transform/ctad.compile.pass.cpp @@ -10,17 +10,62 @@ // UNSUPPORTED: libcpp-no-concepts // UNSUPPORTED: libcpp-has-no-incomplete-ranges -// CTAD tests. +// template +// transform_view(R&&, F) -> transform_view, F>; #include +#include #include -#include "test_macros.h" -#include "types.h" +struct PlusOne { + int operator()(int x) const; +}; -static_assert(std::same_as>); -static_assert(std::same_as(), PlusOne())), - std::ranges::transform_view, PlusOne>>); -static_assert(std::same_as, PlusOne>>); +struct View : std::ranges::view_base { + int *begin() const; + int *end() const; +}; + +struct Range { + int *begin() const; + int *end() const; +}; + +struct BorrowedRange { + int *begin() const; + int *end() const; +}; +template<> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +void testCTAD() { + View v; + Range r; + BorrowedRange br; + PlusOne f; + + static_assert(std::same_as< + decltype(std::ranges::transform_view(v, f)), + std::ranges::transform_view + >); + static_assert(std::same_as< + decltype(std::ranges::transform_view(std::move(v), f)), + std::ranges::transform_view + >); + static_assert(std::same_as< + decltype(std::ranges::transform_view(r, f)), + std::ranges::transform_view, PlusOne> + >); + static_assert(std::same_as< + decltype(std::ranges::transform_view(std::move(r), f)), + std::ranges::transform_view, PlusOne> + >); + static_assert(std::same_as< + decltype(std::ranges::transform_view(br, f)), + std::ranges::transform_view, PlusOne> + >); + static_assert(std::same_as< + decltype(std::ranges::transform_view(std::move(br), f)), + std::ranges::transform_view, PlusOne> + >); +} diff --git a/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp b/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp --- a/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.pass.cpp @@ -23,50 +23,53 @@ // range // view> // constructible_from, T> -// borrowed_range +// lvalue_reference_t || movable> +// is-initializer-list // // We test all the relevant combinations of satisfying/not satisfying those constraints. -// viewable_range is not satisfied for (range=false, view=*, constructible_from=*, borrowed_range=*) +// viewable_range is not satisfied for (range=false, view=*, constructible_from=*, lvalue-or-movable=*) struct T1 { }; static_assert(!std::ranges::range); static_assert(!std::ranges::viewable_range); static_assert(!std::ranges::viewable_range); +static_assert(!std::ranges::viewable_range); static_assert(!std::ranges::viewable_range); static_assert(!std::ranges::viewable_range); +static_assert(!std::ranges::viewable_range); -// viewable_range is satisfied for (range=true, view=true, constructible_from=true, borrowed_range=true) +// viewable_range is satisfied for (range=true, view=true, constructible_from=true, lvalue-or-movable=true) struct T2 : test_range, std::ranges::view_base { T2(T2 const&) = default; }; -template<> constexpr bool std::ranges::enable_borrowed_range = true; static_assert(std::ranges::range); static_assert(std::ranges::view); static_assert(std::constructible_from); -static_assert(std::ranges::borrowed_range); static_assert(std::ranges::viewable_range); static_assert(std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::ranges::viewable_range); static_assert(std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); -// viewable_range is satisfied for (range=true, view=true, constructible_from=true, borrowed_range=false) +// viewable_range is satisfied for (range=true, view=true, constructible_from=true, lvalue-or-movable=false) struct T3 : test_range, std::ranges::view_base { T3(T3 const&) = default; }; -template<> constexpr bool std::ranges::enable_borrowed_range = false; static_assert(std::ranges::range); static_assert(std::ranges::view); static_assert(std::constructible_from); -static_assert(!std::ranges::borrowed_range); static_assert(std::ranges::viewable_range); static_assert(std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::ranges::viewable_range); static_assert(std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); -// viewable_range is not satisfied for (range=true, view=true, constructible_from=false, borrowed_range=true) +// viewable_range is not satisfied for (range=true, view=true, constructible_from=false, lvalue-or-movable=true) struct T4 : test_range, std::ranges::view_base { T4(T4 const&) = delete; T4(T4&&) = default; // necessary to model view @@ -75,53 +78,83 @@ static_assert(std::ranges::range); static_assert(std::ranges::view>); static_assert(!std::constructible_from, T4 const&>); -static_assert(std::ranges::borrowed_range); static_assert(!std::ranges::viewable_range); -// A type that satisfies (range=true, view=true, constructible_from=false, borrowed_range=false) can't be formed +// A type that satisfies (range=true, view=true, constructible_from=false, lvalue-or-movable=false) can't be formed, +// because views are movable by definition -// viewable_range is satisfied for (range=true, view=false, constructible_from=true, borrowed_range=true) +// viewable_range is satisfied for (range=true, view=false, constructible_from=true, lvalue-or-movable=true)... struct T5 : test_range { }; -template<> constexpr bool std::ranges::enable_borrowed_range = true; -static_assert(std::ranges::range); +static_assert( std::ranges::range); static_assert(!std::ranges::view); -static_assert(std::constructible_from); -static_assert(std::ranges::borrowed_range); - -static_assert(std::ranges::viewable_range); - -// viewable_range is not satisfied for (range=true, view=false, constructible_from=true, borrowed_range=false) -struct T6 : test_range { }; -template<> constexpr bool std::ranges::enable_borrowed_range = false; -static_assert(std::ranges::range); +static_assert( std::constructible_from); +static_assert( std::movable); +static_assert(!std::movable); + +static_assert( std::ranges::viewable_range); // movable +static_assert( std::ranges::viewable_range); // movable +static_assert( std::ranges::viewable_range); // movable +static_assert(!std::ranges::viewable_range); +static_assert( std::ranges::viewable_range); // lvalue +static_assert(!std::ranges::viewable_range); + +// ...but not if the (non-view, lvalue-or-movable) range is an initializer_list. +static_assert( std::ranges::range>); +static_assert(!std::ranges::view>); +static_assert( std::constructible_from, std::initializer_list>); +static_assert( std::movable>); + +static_assert(!std::ranges::viewable_range>); +static_assert( std::ranges::viewable_range&>); +static_assert(!std::ranges::viewable_range&&>); +static_assert(!std::ranges::viewable_range const>); +static_assert( std::ranges::viewable_range const&>); +static_assert(!std::ranges::viewable_range const&&>); + +// viewable_range is not satisfied for (range=true, view=false, constructible_from=true, lvalue-or-movable=false) +struct T6 : test_range { T6(T6&&); T6& operator=(T6&&) = delete; }; +static_assert( std::ranges::range); static_assert(!std::ranges::view); -static_assert(std::constructible_from); -static_assert(!std::ranges::borrowed_range); +static_assert( std::constructible_from); +static_assert(!std::movable); static_assert(!std::ranges::viewable_range); +static_assert( std::ranges::viewable_range); // lvalue +static_assert(!std::ranges::viewable_range); +static_assert(!std::ranges::viewable_range); +static_assert( std::ranges::viewable_range); // lvalue +static_assert(!std::ranges::viewable_range); -// viewable_range is satisfied for (range=true, view=false, constructible_from=false, borrowed_range=true) +// viewable_range is satisfied for (range=true, view=false, constructible_from=false, lvalue-or-movable=true) struct T7 : test_range { T7(T7 const&) = delete; }; static_assert(std::ranges::range); static_assert(!std::ranges::view>); static_assert(!std::constructible_from, T7&>); -static_assert(std::ranges::borrowed_range); -static_assert(std::ranges::viewable_range); +static_assert(!std::ranges::viewable_range); +static_assert( std::ranges::viewable_range); +static_assert(!std::ranges::viewable_range); +static_assert(!std::ranges::viewable_range); +static_assert( std::ranges::viewable_range); +static_assert(!std::ranges::viewable_range); -// A type that satisfies (range=true, view=false, constructible_from=false, borrowed_range=false) can't be formed +// viewable_range is not satisfied for (range=true, view=false, constructible_from=false, lvalue-or-movable=false) struct T8 : test_range { T8(T8 const&) = delete; }; static_assert(std::ranges::range); static_assert(!std::ranges::view); static_assert(!std::constructible_from); -static_assert(!std::ranges::borrowed_range); static_assert(!std::ranges::viewable_range); +static_assert( std::ranges::viewable_range); +static_assert(!std::ranges::viewable_range); +static_assert(!std::ranges::viewable_range); +static_assert( std::ranges::viewable_range); +static_assert(!std::ranges::viewable_range); // Test with a few degenerate types static_assert(!std::ranges::viewable_range); @@ -129,5 +162,7 @@ static_assert(!std::ranges::viewable_range); static_assert(!std::ranges::viewable_range); static_assert(!std::ranges::viewable_range); -static_assert(!std::ranges::viewable_range); // unbounded array is not a range -static_assert( std::ranges::viewable_range); +static_assert(!std::ranges::viewable_range); // not a range +static_assert( std::ranges::viewable_range); // OK, lvalue +static_assert(!std::ranges::viewable_range); +static_assert(!std::ranges::viewable_range); diff --git a/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/re/re.results/range_concept_conformance.compile.pass.cpp @@ -26,7 +26,7 @@ static_assert(!std::ranges::view); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, std::cmatch::const_iterator>); static_assert(std::ranges::common_range); diff --git a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/strings/basic.string/range_concept_conformance.compile.pass.cpp @@ -26,7 +26,7 @@ static_assert(!std::ranges::view); static_assert(std::ranges::sized_range); static_assert(!std::ranges::borrowed_range); -static_assert(!std::ranges::viewable_range); +static_assert(std::ranges::viewable_range); static_assert(std::same_as, std::string::const_iterator>); static_assert(std::ranges::common_range);