diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -119,8 +119,8 @@ | `ranges::bidirectional_range `_ | `ranges::random_access_range `_ | ranges::contiguous_range -| `ranges::common_range `_ -| ranges::viewable_range",[range.range],Christopher Di Bella,In progress +| `ranges::common_range `_",[range.range],Christopher Di Bella,✅ +`[range.refinements]`_,`ranges::viewable_range `_,[range.range],Louis Dionne,✅ `[range.utility.helpers] `_,"| *simple-view* | *has-arrow* | *not-same-as*","| [range.range] 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 @@ -17,6 +17,7 @@ #include <__ranges/ref_view.h> #include <__ranges/subrange.h> #include <__utility/__decay_copy.h> +#include <__utility/declval.h> #include <__utility/forward.h> #include @@ -68,6 +69,9 @@ inline constexpr auto all = __all::__fn{}; } // namespace __cpo +template +using all_t = decltype(views::all(declval<_Range>())); + } // namespace views #endif // !defined(_LIBCPP_HAS_NO_RANGES) 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 @@ -112,6 +112,13 @@ template concept common_range = range<_Tp> && same_as, sentinel_t<_Tp> >; + + template + concept viewable_range = + range<_Tp> && ( + (view> && constructible_from, _Tp>) || + (!view> && borrowed_range<_Tp>) + ); } // namespace ranges #endif // !defined(_LIBCPP_HAS_NO_RANGES) diff --git a/libcxx/include/__ranges/drop_view.h b/libcxx/include/__ranges/drop_view.h --- a/libcxx/include/__ranges/drop_view.h +++ b/libcxx/include/__ranges/drop_view.h @@ -140,9 +140,7 @@ }; template - drop_view(_Range&&, range_difference_t<_Range>) - // TODO: this is just recreating all_t. - -> drop_view()))>; + drop_view(_Range&&, range_difference_t<_Range>) -> drop_view>; template inline constexpr bool enable_borrowed_range> = enable_borrowed_range<_Tp>; diff --git a/libcxx/include/__ranges/transform_view.h b/libcxx/include/__ranges/transform_view.h --- a/libcxx/include/__ranges/transform_view.h +++ b/libcxx/include/__ranges/transform_view.h @@ -10,10 +10,11 @@ #define _LIBCPP___RANGES_TRANSFORM_VIEW_H #include <__config> -#include <__iterator/iterator_traits.h> #include <__iterator/concepts.h> #include <__iterator/iter_swap.h> +#include <__iterator/iterator_traits.h> #include <__ranges/access.h> +#include <__ranges/all.h> #include <__ranges/concepts.h> #include <__ranges/copyable_box.h> #include <__ranges/empty.h> @@ -93,10 +94,8 @@ constexpr auto size() const requires sized_range { return ranges::size(__base_); } }; -// TODO: replace the decltype with all_t when that's implemented. template -transform_view(_Range&&, _Fn) - -> transform_view())), _Fn>; +transform_view(_Range&&, _Fn) -> transform_view, _Fn>; template struct __transform_view_iterator_concept { using type = input_iterator_tag; }; diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -50,7 +50,7 @@ template using range_rvalue_reference_t = iter_rvalue_reference_t>; - // [range.sized] + // [range.sized], sized ranges template inline constexpr bool disable_sized_range = false; @@ -85,6 +85,9 @@ template concept common_range = see below; + template + concept viewable_range = see below; + // [view.interface], class template view_interface template requires is_class_v && same_as> @@ -95,6 +98,21 @@ requires is_object_v class empty_view; + // [range.all], all view + namespace views { + inline constexpr unspecified all = unspecified; + + template + using all_t = decltype(all(declval())); + } + + template + requires is_object_v + class ref_view; + + template + inline constexpr bool enable_borrowed_range> = true; + // [range.drop], drop view template class drop_view; 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,6 +27,7 @@ static_assert(!stdr::random_access_range); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::random_access_range); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +27,7 @@ static_assert(!stdr::random_access_range); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::random_access_range); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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 @@ -27,6 +27,7 @@ static_assert(!stdr::random_access_range); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::random_access_range); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +28,7 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::bidirectional_range); @@ -37,3 +38,4 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +27,7 @@ static_assert(stdr::contiguous_range); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(!stdr::view); static_assert(std::same_as, range::const_iterator>); @@ -35,3 +36,4 @@ static_assert(stdr::contiguous_range); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); 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,6 +27,7 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +27,7 @@ static_assert(!stdr::view); static_assert(!stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::view); static_assert(!stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +27,7 @@ static_assert(!stdr::random_access_range); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::random_access_range); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +27,7 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +27,7 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +27,7 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +27,7 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +27,7 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +27,7 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, range::const_iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); diff --git a/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/containers/views/range_concept_conformance.compile.pass.cpp @@ -27,6 +27,7 @@ static_assert(stdr::view && stdr::enable_view); static_assert(stdr::sized_range); static_assert(stdr::borrowed_range); +static_assert(stdr::viewable_range); static_assert(std::same_as, range::iterator>); static_assert(stdr::common_range); @@ -35,3 +36,4 @@ static_assert(!stdr::view && !stdr::enable_view); static_assert(stdr::sized_range); static_assert(stdr::borrowed_range); +static_assert(stdr::viewable_range); diff --git a/libcxx/test/std/input.output/filesystems/class.directory_iterator/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/input.output/filesystems/class.directory_iterator/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/input.output/filesystems/class.directory_iterator/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/input.output/filesystems/class.directory_iterator/range_concept_conformance.compile.pass.cpp @@ -26,6 +26,7 @@ static_assert(!stdr::view); static_assert(!stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, fs::directory_iterator>); static_assert(stdr::common_range); @@ -33,6 +34,7 @@ static_assert(!stdr::view); static_assert(!stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, fs::recursive_directory_iterator>); static_assert(stdr::common_range); @@ -40,6 +42,7 @@ static_assert(!stdr::view); static_assert(!stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, fs::recursive_directory_iterator>); static_assert(stdr::common_range); @@ -47,3 +50,4 @@ static_assert(!stdr::view); static_assert(!stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +26,7 @@ static_assert(!stdr::random_access_range); static_assert(!stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, fs::path::const_iterator>); static_assert(stdr::common_range); @@ -34,3 +35,4 @@ static_assert(!stdr::random_access_range); static_assert(!stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); diff --git a/libcxx/test/std/ranges/range.adaptors/range.all.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp rename from libcxx/test/std/ranges/range.adaptors/range.all.pass.cpp rename to libcxx/test/std/ranges/range.adaptors/range.all/all.pass.cpp 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 new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.all/all_t.compile.pass.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// using all_t = decltype(views::all(declval())); + +#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 { }; +template<> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +// 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); + +// 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); + +// 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>); diff --git a/libcxx/test/std/ranges/range.adaptors/range.ref.view.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.ref.view.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.ref.view.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.ref.view.pass.cpp @@ -10,7 +10,9 @@ // UNSUPPORTED: libcpp-no-concepts // UNSUPPORTED: gcc-10 -// std::ranges::ref_view +// template +// requires is_object_v +// class ref_view; #include 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 new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.req/range.refinements/viewable_range.compile.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: gcc-10 + +// template +// concept viewable_range; + +#include +#include + +#include "test_iterators.h" +#include "test_range.h" + +// The constraints we have in viewable_range are: +// range +// view> +// constructible_from, T> +// borrowed_range +// +// 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=*) +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); + +// viewable_range is satisfied for (range=true, view=true, constructible_from=true, borrowed_range=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); + +// viewable_range is satisfied for (range=true, view=true, constructible_from=true, borrowed_range=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); + +// viewable_range is not satisfied for (range=true, view=true, constructible_from=false, borrowed_range=true) +struct T4 : test_range, std::ranges::view_base { + T4(T4 const&) = delete; + T4(T4&&) = default; // necessary to model view + T4& operator=(T4&&) = default; // necessary to model view +}; +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 + +// viewable_range is satisfied for (range=true, view=false, constructible_from=true, borrowed_range=true) +struct T5 : test_range { }; +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); + +// 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::ranges::view); +static_assert(std::constructible_from); +static_assert(!std::ranges::borrowed_range); + +static_assert(!std::ranges::viewable_range); + +// viewable_range is satisfied for (range=true, view=false, constructible_from=false, borrowed_range=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); + +// A type that satisfies (range=true, view=false, constructible_from=false, borrowed_range=false) can't be formed +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); + +// Test with a few degenerate types +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); // unbounded array is not a 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,6 +26,7 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, std::cmatch::const_iterator>); static_assert(stdr::common_range); @@ -34,3 +35,4 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_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,6 +26,7 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); static_assert(std::same_as, std::string::const_iterator>); static_assert(stdr::common_range); @@ -34,3 +35,4 @@ static_assert(!stdr::view); static_assert(stdr::sized_range); static_assert(!stdr::borrowed_range); +static_assert(!stdr::viewable_range); diff --git a/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp b/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp --- a/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp +++ b/libcxx/test/std/strings/string.view/range_concept_conformance.compile.pass.cpp @@ -26,6 +26,7 @@ static_assert(stdr::view && stdr::enable_view); static_assert(stdr::sized_range); static_assert(stdr::borrowed_range); +static_assert(stdr::viewable_range); static_assert(std::same_as, std::string_view::const_iterator>); static_assert(stdr::common_range); @@ -34,3 +35,4 @@ static_assert(!stdr::view && !stdr::enable_view); static_assert(stdr::sized_range); static_assert(stdr::borrowed_range); +static_assert(stdr::viewable_range);