//===----------------------------------------------------------------------===// // // 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 // std::views::all; #include #include #include #include #include #include "test_iterators.h" #include "test_macros.h" #include "test_range.h" int globalBuff[8]; template struct View : std::ranges::view_base { int start_ = 0; explicit View() noexcept(IsNoexcept) = default; constexpr explicit View(int start) : start_(start) {} View(View&&) noexcept(IsNoexcept) = default; View& operator=(View&&) noexcept(IsNoexcept) = default; constexpr int* begin() const { return globalBuff + start_; } constexpr int* end() const { return globalBuff + 8; } }; static_assert(std::ranges::view>); static_assert(std::ranges::view>); template struct CopyableView : std::ranges::view_base { int start_ = 0; explicit 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 int* begin() const { return globalBuff + start_; } constexpr int* end() const { return globalBuff + 8; } }; static_assert(std::ranges::view>); static_assert(std::ranges::view>); struct MoveOnlyView : std::ranges::view_base{ MoveOnlyView() = default; MoveOnlyView(const MoveOnlyView&) = delete; MoveOnlyView& operator=(const MoveOnlyView&) = delete; MoveOnlyView(MoveOnlyView&&) = default; MoveOnlyView& operator=(MoveOnlyView&&) = default; int* begin() const; int* end() const; }; struct Range { int start_; constexpr explicit Range(int start) noexcept : start_(start) {} constexpr int* begin() const { return globalBuff + start_; } constexpr int* end() const { return globalBuff + 8; } }; struct BorrowableRange { int start_; constexpr explicit BorrowableRange(int start) noexcept : start_(start) {} constexpr int* begin() const { return globalBuff + start_; } constexpr int* end() const { return globalBuff + 8; } }; template<> inline constexpr bool std::ranges::enable_borrowed_range = true; struct RandomAccessRange { constexpr auto begin() { return random_access_iterator(globalBuff); } constexpr auto end() { return sized_sentinel(random_access_iterator(globalBuff + 8)); } }; 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); auto own = std::views::all(std::move(range)); ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view); assert(std::ranges::begin(own) == globalBuff + 2); assert(std::ranges::end(own) == globalBuff + 8); auto cref = std::views::all(std::as_const(range)); ASSERT_SAME_TYPE(decltype(cref), std::ranges::ref_view); assert(std::ranges::begin(cref) == globalBuff + 2); assert(std::ranges::end(cref) == globalBuff + 8); static_assert(!std::is_invocable_v); } { auto own = std::views::all(BorrowableRange(2)); ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view); assert(std::ranges::begin(own) == globalBuff + 2); assert(std::ranges::end(own) == globalBuff + 8); } { auto own = std::views::all(RandomAccessRange()); ASSERT_SAME_TYPE(decltype(own), std::ranges::owning_view); assert(base(std::ranges::begin(own)) == globalBuff); assert(base(base(std::ranges::end(own))) == globalBuff + 8); } // Check SFINAE friendliness of the call operator { static_assert(!std::is_invocable_v); static_assert(!std::is_invocable_v); // `views::all(v)` is expression equivalent to `decay-copy(v)` if the decayed type // of `v` models `view`. If `v` is an lvalue-reference to a move-only view, the // expression should be ill-formed because `v` is not copyable static_assert(!std::is_invocable_v); } // Test that std::views::all is a range adaptor { // Test `v | views::all` { Range range(0); auto result = range | std::views::all; ASSERT_SAME_TYPE(decltype(result), std::ranges::ref_view); assert(&result.base() == &range); } // Test `adaptor | views::all` { Range range(0); auto f = [](int i) { return i; }; auto const partial = std::views::transform(f) | std::views::all; using Result = std::ranges::transform_view, decltype(f)>; std::same_as auto result = partial(range); assert(&result.base().base() == &range); } // Test `views::all | adaptor` { Range range(0); auto f = [](int i) { return i; }; auto const partial = std::views::all | std::views::transform(f); using Result = std::ranges::transform_view, decltype(f)>; std::same_as auto result = partial(range); assert(&result.base().base() == &range); } { struct NotAView { }; static_assert( CanBePiped); static_assert(!CanBePiped); } } { static_assert(std::same_as); } return true; } int main(int, char**) { test(); static_assert(test()); return 0; }