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
21struct 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
31struct Foo {
32 int i;
33 constexpr Foo(int ii) : i(ii) {}
34};
35
36constexpr 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
128int main(int, char**) {
129 test();
130 static_assert(test());
131
132 return 0;
133}
134

source code of libcxx/test/std/ranges/range.adaptors/range.join/adaptor.pass.cpp