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,78 @@ +// -*- 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)}; } && + requires (_Tp&& __t) { ranges::subrange{_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,146 @@ +//===----------------------------------------------------------------------===// +// +// 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 { + int start = 0; + constexpr explicit View(int start) : start(start) {} + View() = default; + View(View&&) = default; + View& operator=(View&&) = default; + constexpr friend int* begin(View& view) { return globalBuff + view.start; } + constexpr friend int* begin(View const& view) { return globalBuff + view.start; } + constexpr friend int* end(View&) { return globalBuff + 8; } + constexpr friend int* end(View const&) { return globalBuff + 8; } +}; + +static_assert(std::ranges::view); + +struct CopyableView : std::ranges::view_base { + int start = 0; + CopyableView() = default; + constexpr explicit CopyableView(int start) : start(start) {} + constexpr friend int* begin(CopyableView& view) { return globalBuff + view.start; } + constexpr friend int* begin(CopyableView const& view) { return globalBuff + view.start; } + constexpr friend int* end(CopyableView&) { return globalBuff + 8; } + constexpr friend int* end(CopyableView const&) { return globalBuff + 8; } +}; + +static_assert(std::ranges::view); + +struct Range { + int start = 0; + constexpr explicit Range(int start) : start(start) {} + 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 explicit BorrowableRange(int start) : start(start) {} + 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; + +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 {}; } +}; + + +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(2)); + ASSERT_SAME_TYPE(decltype(viewCopy), View); + assert(std::ranges::begin(viewCopy) == globalBuff + 2); + assert(std::ranges::end(viewCopy) == globalBuff + 8); + } + + { + ASSERT_SAME_TYPE(decltype(std::views::all(std::declval())), CopyableView); + + CopyableView view(2); + auto viewCopy = std::views::all(view); + ASSERT_SAME_TYPE(decltype(viewCopy), CopyableView); + assert(std::ranges::begin(viewCopy) == globalBuff + 2); + assert(std::ranges::end(viewCopy) == globalBuff + 8); + } + + { + Range range(2); + auto ref = 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); + + static_assert(!std::is_invocable_v); + } + + { + const Range range(2); + auto ref = 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 subrange = 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 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); + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +}