diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -38,6 +38,7 @@ __node_handle __nullptr __ranges/access.h + __ranges/all.h __ranges/concepts.h __ranges/data.h __ranges/empty.h diff --git a/libcxx/include/__ranges/all.h b/libcxx/include/__ranges/all.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/all.h @@ -0,0 +1,77 @@ +// -*- 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_ALL_H +#define _LIBCPP___RANGES_ALL_H + +#include <__config> +#include <__iterator/concepts.h> +#include <__iterator/iterator_traits.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__ranges/ref_view.h> +#include <__ranges/subrange.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 + noexcept(noexcept(_VSTD::__decay_copy(_VSTD::forward<_Tp>(__t)))) + { + return _VSTD::forward<_Tp>(__t); + } + + template + requires (!ranges::view>) && + requires (_Tp&& __t) { ranges::ref_view{_VSTD::forward<_Tp>(__t)}; } + constexpr auto operator()(_Tp&& __t) const + noexcept(noexcept(ranges::ref_view{_VSTD::forward<_Tp>(__t)})) + { + 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 + noexcept(noexcept(ranges::subrange{_VSTD::forward<_Tp>(__t)})) + { + return ranges::subrange{_VSTD::forward<_Tp>(__t)}; + } + }; +} + +inline namespace __cpo { + inline constexpr auto all = __all::__fn{}; +} // namespace __cpo + +} // namespace views + +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___RANGES_ALL_H 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 @@ -66,6 +66,12 @@ template concept random_access_range = bidirectional_range<_Tp> && random_access_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 @@ -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 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 @@ -118,6 +118,11 @@ inline constexpr const auto ssize = __ssize::__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 @@ -31,17 +31,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 @@ -14,6 +14,7 @@ #include <__iterator/concepts.h> #include <__ranges/access.h> #include <__ranges/empty.h> +#include <__ranges/view.h> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -77,6 +77,7 @@ #include <__config> #include <__ranges/access.h> +#include <__ranges/all.h> #include <__ranges/concepts.h> #include <__ranges/data.h> #include <__ranges/empty.h> 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,82 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// std::views::all; + +#include + +#include +#include "test_macros.h" +#include "test_iterators.h" + +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 std::ranges::enable_borrowed_range = true; + +constexpr bool test() { + { + ASSERT_SAME_TYPE(decltype(std::views::all(View())), View); + + auto viewCopy = std::views::all(View()); + ASSERT_SAME_TYPE(decltype(viewCopy), View); + assert(std::ranges::begin(viewCopy) == globalBuff); + } + + { + Range range; + auto ref = std::views::all(range); + ASSERT_SAME_TYPE(decltype(ref), std::ranges::ref_view); + assert(std::ranges::begin(ref) == globalBuff); + } + + { + auto subrange = std::views::all(BorrowableRange()); + ASSERT_SAME_TYPE(decltype(subrange), std::ranges::subrange); + assert(std::ranges::begin(subrange) == globalBuff); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +}