xref: /llvm-project/libcxx/test/std/ranges/range.adaptors/range.join/adaptor.pass.cpp (revision ba2236d3000645d3127f972aa7ac1844c47e299c)
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 
11 // std::views::join
12 
13 #include <ranges>
14 
15 #include <cassert>
16 #include <type_traits>
17 
18 #include "test_range.h"
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;
FooFoo33   constexpr Foo(int ii) : i(ii) {}
34 };
35 
test()36 constexpr bool test() {
37   int buffer1[3] = {1, 2, 3};
38   int buffer2[2] = {4, 5};
39   int buffer3[4] = {6, 7, 8, 9};
40   Foo nested[2][3][3] = {{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}}, {{10, 11, 12}, {13, 14, 15}, {16, 17, 18}}};
41 
42   {
43     // Test `views::join(v)`
44     ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3};
45     using Result = std::ranges::join_view<std::ranges::ref_view<ForwardCommonInner[3]>>;
46     std::same_as<Result> decltype(auto) v = std::views::join(inners);
47     assert(std::ranges::next(v.begin(), 9) == v.end());
48     assert(&(*v.begin()) == buffer1);
49   }
50 
51   {
52     // Test `views::join(move-only-view)`
53     ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3};
54     using Result = std::ranges::join_view<MoveOnlyOuter>;
55     std::same_as<Result> decltype(auto) v = std::views::join(MoveOnlyOuter{inners});
56     assert(std::ranges::next(v.begin(), 9) == v.end());
57     assert(&(*v.begin()) == buffer1);
58 
59     static_assert(std::invocable<decltype(std::views::join), MoveOnlyOuter>);
60     static_assert(!std::invocable<decltype(std::views::join), MoveOnlyOuter&>);
61   }
62 
63   {
64     // LWG3474 Nesting `join_views` is broken because of CTAD
65     // views::join(join_view) should join the view instead of calling copy constructor
66     auto jv = std::views::join(nested);
67     ASSERT_SAME_TYPE(std::ranges::range_reference_t<decltype(jv)>, Foo(&)[3]);
68 
69     auto jv2 = std::views::join(jv);
70     ASSERT_SAME_TYPE(std::ranges::range_reference_t<decltype(jv2)>, Foo&);
71 
72     assert(&(*jv2.begin()) == &nested[0][0][0]);
73   }
74 
75   {
76     // Test `v | views::join`
77     ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3};
78 
79     using Result = std::ranges::join_view<std::ranges::ref_view<ForwardCommonInner[3]>>;
80     std::same_as<Result> decltype(auto) v = inners | std::views::join;
81     assert(std::ranges::next(v.begin(), 9) == v.end());
82     assert(&(*v.begin()) == buffer1);
83     static_assert(CanBePiped<decltype((inners)), decltype((std::views::join))>);
84   }
85 
86   {
87     // Test `move-only-view | views::join`
88     ForwardCommonInner inners[3] = {buffer1, buffer2, buffer3};
89     using Result = std::ranges::join_view<MoveOnlyOuter>;
90     std::same_as<Result> decltype(auto) v = MoveOnlyOuter{inners} | std::views::join;
91     assert(std::ranges::next(v.begin(), 9) == v.end());
92     assert(&(*v.begin()) == buffer1);
93 
94     static_assert(CanBePiped<MoveOnlyOuter, decltype((std::views::join))>);
95     static_assert(!CanBePiped<MoveOnlyOuter&, decltype((std::views::join))>);
96   }
97 
98   {
99     // LWG3474 Nesting `join_views` is broken because of CTAD
100     // join_view | views::join should join the view instead of calling copy constructor
101     auto jv = nested | std::views::join | std::views::join;
102     ASSERT_SAME_TYPE(std::ranges::range_reference_t<decltype(jv)>, Foo&);
103 
104     assert(&(*jv.begin()) == &nested[0][0][0]);
105     static_assert(CanBePiped<decltype((nested)), decltype((std::views::join))>);
106   }
107 
108   {
109     // Test `adaptor | views::join`
110     auto join_twice = std::views::join | std::views::join;
111     auto jv = nested | join_twice;
112     ASSERT_SAME_TYPE(std::ranges::range_reference_t<decltype(jv)>, Foo&);
113 
114     assert(&(*jv.begin()) == &nested[0][0][0]);
115     static_assert(CanBePiped<decltype((nested)), decltype((join_twice))>);
116   }
117 
118   {
119     static_assert(!CanBePiped<int, decltype((std::views::join))>);
120     static_assert(!CanBePiped<Foo, decltype((std::views::join))>);
121     static_assert(!CanBePiped<int(&)[2], decltype((std::views::join))>);
122     static_assert(CanBePiped<int(&)[2][2], decltype((std::views::join))>);
123   }
124 
125   return true;
126 }
127 
main(int,char **)128 int main(int, char**) {
129   test();
130   static_assert(test());
131 
132   return 0;
133 }
134