1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 // UNSUPPORTED: c++03, c++11, c++14, c++17 10 // UNSUPPORTED: libcpp-has-no-incomplete-ranges 11 12 // std::views::join 13 14 #include <ranges> 15 16 #include <cassert> 17 #include <type_traits> 18 19 #include "types.h" 20 21 struct MoveOnlyOuter : SimpleForwardCommonOuter<ForwardCommonInner> { 22 using SimpleForwardCommonOuter<ForwardCommonInner>::SimpleForwardCommonOuter; 23 24 constexpr MoveOnlyOuter(MoveOnlyOuter&&) = default; 25 constexpr MoveOnlyOuter(const MoveOnlyOuter&) = delete; 26 27 constexpr MoveOnlyOuter& operator=(MoveOnlyOuter&&) = default; 28 constexpr MoveOnlyOuter& operator=(const MoveOnlyOuter&) = delete; 29 }; 30 31 struct Foo { 32 int i; 33 constexpr Foo(int ii) : i(ii) {} 34 }; 35 36 template <class View, class T> 37 concept CanBePiped = requires(View&& view, T&& t) { 38 { std::forward<View>(view) | std::forward<T>(t) }; 39 }; 40 41 constexpr bool test() { 42 int buffer1[3] = {1, 2, 3}; 43 int buffer2[2] = {4, 5}; 44 int buffer3[4] = {6, 7, 8, 9}; 45 Foo nested[2][3][3] = {{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, {{10, 11, 12}, {13, 14, 15}, {16, 17, 18}}}; 46 47 { 48 // Test `views::join(v)` 49 ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3}; 50 using Result = std::ranges::join_view<std::ranges::ref_view<ForwardCommonInner[3]>>; 51 std::same_as<Result> decltype(auto) v = std::views::join(inners); 52 assert(std::ranges::next(v.begin(), 9) == v.end()); 53 assert(&(*v.begin()) == buffer1); 54 } 55 56 { 57 // Test `views::join(move-only-view)` 58 ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3}; 59 using Result = std::ranges::join_view<MoveOnlyOuter>; 60 std::same_as<Result> decltype(auto) v = std::views::join(MoveOnlyOuter{inners}); 61 assert(std::ranges::next(v.begin(), 9) == v.end()); 62 assert(&(*v.begin()) == buffer1); 63 64 static_assert(std::invocable<decltype(std::views::join), MoveOnlyOuter>); 65 static_assert(!std::invocable<decltype(std::views::join), MoveOnlyOuter&>); 66 } 67 68 { 69 // LWG3474 Nesting `join_views` is broken because of CTAD 70 // views::join(join_view) should join the view instead of calling copy constructor 71 auto jv = std::views::join(nested); 72 ASSERT_SAME_TYPE(std::ranges::range_reference_t<decltype(jv)>, Foo(&)[3]); 73 74 auto jv2 = std::views::join(jv); 75 ASSERT_SAME_TYPE(std::ranges::range_reference_t<decltype(jv2)>, Foo&); 76 77 assert(&(*jv2.begin()) == &nested[0][0][0]); 78 } 79 80 { 81 // Test `v | views::join` 82 ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3}; 83 84 using Result = std::ranges::join_view<std::ranges::ref_view<ForwardCommonInner[3]>>; 85 std::same_as<Result> decltype(auto) v = inners | std::views::join; 86 assert(std::ranges::next(v.begin(), 9) == v.end()); 87 assert(&(*v.begin()) == buffer1); 88 static_assert(CanBePiped<decltype((inners)), decltype((std::views::join))>); 89 } 90 91 { 92 // Test `move-only-view | views::join` 93 ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3}; 94 using Result = std::ranges::join_view<MoveOnlyOuter>; 95 std::same_as<Result> decltype(auto) v = MoveOnlyOuter{inners} | std::views::join; 96 assert(std::ranges::next(v.begin(), 9) == v.end()); 97 assert(&(*v.begin()) == buffer1); 98 99 static_assert(CanBePiped<MoveOnlyOuter, decltype((std::views::join))>); 100 static_assert(!CanBePiped<MoveOnlyOuter&, decltype((std::views::join))>); 101 } 102 103 { 104 // LWG3474 Nesting `join_views` is broken because of CTAD 105 // join_view | views::join should join the view instead of calling copy constructor 106 auto jv = nested | std::views::join | std::views::join; 107 ASSERT_SAME_TYPE(std::ranges::range_reference_t<decltype(jv)>, Foo&); 108 109 assert(&(*jv.begin()) == &nested[0][0][0]); 110 static_assert(CanBePiped<decltype((nested)), decltype((std::views::join))>); 111 } 112 113 { 114 // Test `adaptor | views::join` 115 auto join_twice = std::views::join | std::views::join; 116 auto jv = nested | join_twice; 117 ASSERT_SAME_TYPE(std::ranges::range_reference_t<decltype(jv)>, Foo&); 118 119 assert(&(*jv.begin()) == &nested[0][0][0]); 120 static_assert(CanBePiped<decltype((nested)), decltype((join_twice))>); 121 } 122 123 { 124 static_assert(!CanBePiped<int, decltype((std::views::join))>); 125 static_assert(!CanBePiped<Foo, decltype((std::views::join))>); 126 static_assert(!CanBePiped<int(&)[2], decltype((std::views::join))>); 127 static_assert(CanBePiped<int(&)[2][2], decltype((std::views::join))>); 128 } 129 130 return true; 131 } 132 133 int main(int, char**) { 134 test(); 135 static_assert(test()); 136 137 return 0; 138 } 139