diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -45,6 +45,7 @@ __ranges/size.h __ranges/ref_view.h __ranges/subrange.h + __ranges/views_all.h __ranges/view_interface.h __ranges/view.h __split_buffer 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 @@ -72,6 +72,13 @@ template concept contiguous_range = random_access_range<_Tp> && contiguous_iterator >; + + + template + concept borrowed_range = + range<_Range> && + (is_lvalue_reference_v<_Range> || enable_borrowed_range>); + } // namespace ranges #endif // !defined(_LIBCPP_HAS_NO_RANGES) diff --git a/libcxx/include/__ranges/ref_view.h b/libcxx/include/__ranges/ref_view.h --- a/libcxx/include/__ranges/ref_view.h +++ b/libcxx/include/__ranges/ref_view.h @@ -29,17 +29,6 @@ // clang-format off namespace ranges { - - template - concept borrowed_range = - range<_Range> && - (is_lvalue_reference_v<_Range> || enable_borrowed_range>); - - template - concept sized_range = range<_Range> && requires(_Range& t) { - ranges::size(t); - }; - template requires is_object_v<_Range> class ref_view : public view_interface> { diff --git a/libcxx/include/__ranges/size.h b/libcxx/include/__ranges/size.h --- a/libcxx/include/__ranges/size.h +++ b/libcxx/include/__ranges/size.h @@ -98,6 +98,12 @@ inline namespace __cpo { inline constexpr auto size = __size::__fn{}; } // namespace __cpo + +template +concept sized_range = range<_Range> && requires(_Range& t) { + ranges::size(t); +}; + } // namespace ranges // clang-format off diff --git a/libcxx/include/__ranges/subrange.h b/libcxx/include/__ranges/subrange.h --- a/libcxx/include/__ranges/subrange.h +++ b/libcxx/include/__ranges/subrange.h @@ -30,17 +30,6 @@ // clang-format off namespace ranges { - - template - concept borrowed_range = - range<_Range> && - (is_lvalue_reference_v<_Range> || enable_borrowed_range>); - - template - concept sized_range = range<_Range> && requires(_Range& t) { - ranges::size(t); - }; - template concept __convertible_to_non_slicing = convertible_to<_From, _To> && diff --git a/libcxx/include/__ranges/view_interface.h b/libcxx/include/__ranges/view_interface.h --- a/libcxx/include/__ranges/view_interface.h +++ b/libcxx/include/__ranges/view_interface.h @@ -13,6 +13,7 @@ #include <__iterator/iterator_traits.h> #include <__iterator/concepts.h> #include <__ranges/access.h> +#include <__ranges/view.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -28,19 +29,6 @@ namespace ranges { -struct view_base { }; - -template -inline constexpr bool enable_view = derived_from<_Tp, view_base>; - -template -concept view = - range<_Tp> && - movable<_Tp> && - default_initializable<_Tp> && - enable_view<_Tp>; - - template concept __can_empty = requires(_Tp __t) { ranges::empty(__t); }; diff --git a/libcxx/include/__ranges/views_all.h b/libcxx/include/__ranges/views_all.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/views_all.h @@ -0,0 +1,69 @@ +// -*- 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_VIEWS_ALL_H +#define _LIBCPP___RANGES_VIEWS_ALL_H + +#include <__config> +#include <__iterator/iterator_traits.h> +#include <__iterator/concepts.h> +#include <__ranges/concepts.h> +#include <__ranges/access.h> +#include <__ranges/view.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_RANGES) + +namespace views { + +namespace __all { + struct __fn { + template + requires ranges::view> + constexpr auto operator()(_Tp&& __t) const { + return _VSTD::move(__t); + } + + template + requires (!ranges::view>) && + requires (_Tp&& __t) { ranges::ref_view{_VSTD::forward<_Tp>(__t)}; } + constexpr auto operator()(_Tp&& __t) const { + return ranges::ref_view{_VSTD::forward<_Tp>(__t)}; + } + + template + requires (!ranges::view> && + !requires (_Tp&& __t) { ranges::ref_view{_VSTD::forward<_Tp>(__t)}; }) + constexpr auto operator()(_Tp&& __t) const { + return ranges::subrange{_VSTD::forward<_Tp>(__t)}; + } + }; +} + +inline namespace __cpo { + inline constexpr const auto all = __all::__fn{}; +} // namespace __cpo + +} + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___RANGES_VIEWS_ALL_H diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -78,6 +78,7 @@ #include <__ranges/size.h> #include <__ranges/ref_view.h> #include <__ranges/subrange.h> +#include <__ranges/views_all.h> #include <__ranges/view_interface.h> #include <__ranges/view.h> #include // Required by the standard. diff --git a/libcxx/test/std/ranges/range.adaptors/range.all.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.all.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.all.pass.cpp @@ -0,0 +1,87 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: libcpp-no-concepts +// UNSUPPORTED: gcc-10 +// XFAIL: msvc && clang + +// std::ranges::size + +#include + +#include +#include "test_macros.h" +#include "test_iterators.h" + +namespace ranges = std::ranges; +namespace views = std::views; + +int globalBuff[8]; + +struct View : std::ranges::view_base { + View() = default; + View(View&&) = default; + View& operator=(View&&) = default; + constexpr friend int* begin(View&) { return globalBuff; } + constexpr friend int* begin(View const&) { return globalBuff; } + constexpr friend int* end(View&) { return globalBuff + 8; } + constexpr friend int* end(View const&) { return globalBuff + 8; } +}; + +struct Range { + int start = 0; + constexpr friend int* begin(Range const& range) { return globalBuff + range.start; } + constexpr friend int* end(Range const&) { return globalBuff + 8; } + constexpr friend int* begin(Range& range) { return globalBuff + range.start; } + constexpr friend int* end(Range&) { return globalBuff + 8; } +}; + +struct BorrowableRange { + int start = 0; + constexpr friend int* begin(BorrowableRange const& range) { return globalBuff + range.start; } + constexpr friend int* end(BorrowableRange const&) { return globalBuff + 8; } + constexpr friend int* begin(BorrowableRange& range) { return globalBuff + range.start; } + constexpr friend int* end(BorrowableRange&) { return globalBuff + 8; } +}; + +template<> +inline constexpr bool ranges::enable_borrowed_range = true; + +constexpr bool test() { + { + ASSERT_SAME_TYPE(decltype(views::all(View())), View); + + View view; + auto viewCopy = views::all(view); + ASSERT_SAME_TYPE(decltype(viewCopy), View); + assert(ranges::begin(viewCopy) == globalBuff); + } + + { + Range range; + auto ref = views::all(range); + ASSERT_SAME_TYPE(decltype(ref), ranges::ref_view); + assert(ranges::begin(ref) == globalBuff); + } + + { + auto subrange = views::all(BorrowableRange()); + ASSERT_SAME_TYPE(decltype(subrange), ranges::subrange); + assert(ranges::begin(subrange) == globalBuff); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +}