diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -44,6 +44,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 + +#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/size.h b/libcxx/include/__ranges/size.h --- a/libcxx/include/__ranges/size.h +++ b/libcxx/include/__ranges/size.h @@ -116,7 +116,6 @@ inline namespace __cpo { inline constexpr const auto ssize = __ssize::__fn{}; } // namespace __cpo - } // namespace ranges // clang-format off diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -94,6 +94,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,156 @@ +//===----------------------------------------------------------------------===// +// +// 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]; + +template +struct View : std::ranges::view_base { + int start = 0; + constexpr explicit View(int start) : start(start) {} + View() noexcept(IsNoexcept) = default; + View(View&&) noexcept(IsNoexcept) = default; + View& operator=(View&&) noexcept(IsNoexcept) = 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>); +static_assert(std::ranges::view>); + +template +struct CopyableView : std::ranges::view_base { + int start = 0; + CopyableView() noexcept(IsNoexcept) = default; + CopyableView(CopyableView const&) noexcept(IsNoexcept) = default; + CopyableView& operator=(CopyableView const&) noexcept(IsNoexcept) = default; + constexpr explicit CopyableView(int start) noexcept : 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>); +static_assert(std::ranges::view>); + +struct Range { + int start = 0; + constexpr explicit Range(int start) noexcept : 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) noexcept : 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); + static_assert(noexcept(std::views::all(View()))); + static_assert(!noexcept(std::views::all(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); + static_assert(noexcept(std::views::all(CopyableView()))); + static_assert(!noexcept(std::views::all(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); + 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 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 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; +}