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// REQUIRES: std-at-least-c++23
10
11// <ranges>
12
13// template<input_range R>
14// requires constructible_from<V, views::all_t<R>> &&
15// constructible_from<Pattern, single_view<range_value_t<InnerRng>>>
16// constexpr explicit join_with_view(R&& r, range_value_t<InnerRng> e);
17
18#include <ranges>
19
20#include <algorithm>
21#include <array>
22#include <cassert>
23#include <type_traits>
24#include <utility>
25
26#include "../types.h"
27#include "test_iterators.h"
28#include "test_range.h"
29
30struct MoveOnlyInt {
31 MoveOnlyInt() = default;
32 MoveOnlyInt(MoveOnlyInt&&) = default;
33 MoveOnlyInt& operator=(MoveOnlyInt&&) = default;
34
35 constexpr MoveOnlyInt(int val) : val_(val) {}
36 constexpr operator int() const { return val_; }
37
38 int val_ = 0;
39};
40
41template <>
42struct std::common_type<MoveOnlyInt, int> {
43 using type = int;
44};
45
46template <>
47struct std::common_type<int, MoveOnlyInt> {
48 using type = int;
49};
50
51struct OutputView : std::ranges::view_base {
52 using It = cpp20_output_iterator<int*>;
53 It begin() const;
54 sentinel_wrapper<It> end() const;
55};
56
57static_assert(std::ranges::output_range<OutputView, int>);
58static_assert(std::ranges::view<OutputView>);
59
60struct InputRange {
61 using It = cpp20_input_iterator<int*>;
62 It begin() const;
63 sentinel_wrapper<It> end() const;
64};
65
66struct InputView : InputRange, std::ranges::view_base {};
67
68static_assert(std::ranges::input_range<InputRange>);
69static_assert(std::ranges::input_range<const InputRange>);
70static_assert(std::ranges::view<InputView>);
71static_assert(std::ranges::input_range<InputView>);
72static_assert(std::ranges::input_range<const InputView>);
73
74class View : public std::ranges::view_base {
75 using OuterRange = std::array<std::array<MoveOnlyInt, 2>, 3>;
76
77 static constexpr OuterRange range_on_input_view = {._M_elems: {{1, 1}, {1, 1}, {1, 1}}};
78 static constexpr OuterRange range_on_ref_input_range = {._M_elems: {{2, 2}, {2, 2}, {2, 2}}};
79 static constexpr OuterRange range_on_const_ref_input_range = {._M_elems: {{3, 3}, {3, 3}, {3, 3}}};
80 static constexpr OuterRange range_on_owning_input_range = {._M_elems: {{4, 4}, {4, 4}, {4, 4}}};
81
82 const OuterRange* r_;
83
84public:
85 // Those functions should never be called in this test.
86 View(View&&) { assert(false); }
87 View(OutputView) { assert(false); }
88 View& operator=(View&&) {
89 assert(false);
90 return *this;
91 }
92
93 constexpr explicit View(InputView) : r_(&range_on_input_view) {}
94 constexpr explicit View(InputRange) = delete;
95 constexpr explicit View(std::ranges::ref_view<InputRange>) : r_(&range_on_ref_input_range) {}
96 constexpr explicit View(std::ranges::ref_view<const InputRange>) : r_(&range_on_const_ref_input_range) {}
97 constexpr explicit View(std::ranges::owning_view<InputRange>) : r_(&range_on_owning_input_range) {}
98
99 constexpr auto begin() const { return r_->begin(); }
100 constexpr auto end() const { return r_->end(); }
101};
102
103static_assert(std::ranges::input_range<View>);
104static_assert(std::ranges::input_range<const View>);
105
106class Pattern : public std::ranges::view_base {
107 int val_;
108
109public:
110 // Those functions should never be called in this test.
111 Pattern(Pattern&&) { assert(false); }
112 template <class T>
113 Pattern(const std::ranges::single_view<T>&) {
114 assert(false);
115 }
116 Pattern& operator=(Pattern&&) {
117 assert(false);
118 return *this;
119 }
120
121 template <class T>
122 constexpr explicit Pattern(std::ranges::single_view<T>&& v) : val_(v[0]) {}
123
124 constexpr const int* begin() const { return &val_; }
125 constexpr const int* end() const { return &val_ + 1; }
126};
127
128static_assert(std::ranges::forward_range<Pattern>);
129static_assert(std::ranges::forward_range<const Pattern>);
130
131constexpr void test_ctor_with_view_and_element() {
132 // Check construction from `r` and `e`, when `r` models `std::ranges::view`
133
134 { // `r` and `e` are glvalues
135 InputView r;
136 int e = 0;
137 std::ranges::join_with_view<View, Pattern> jwv(r, e);
138 assert(std::ranges::equal(jwv, std::array{1, 1, 0, 1, 1, 0, 1, 1}));
139 }
140
141 { // `r` and `e` are const glvalues
142 const InputView r;
143 const int e = 1;
144 std::ranges::join_with_view<View, Pattern> jwv(r, e);
145 assert(std::ranges::equal(jwv, std::array{1, 1, 1, 1, 1, 1, 1, 1}));
146 }
147
148 { // `r` and `e` are prvalues
149 std::ranges::join_with_view<View, Pattern> jwv(InputView{}, MoveOnlyInt{2});
150 assert(std::ranges::equal(jwv, std::array{1, 1, 2, 1, 1, 2, 1, 1}));
151 }
152
153 { // `r` and `e` are xvalues
154 InputView r;
155 MoveOnlyInt e = 3;
156 std::ranges::join_with_view<View, Pattern> jwv(std::move(r), std::move(e));
157 assert(std::ranges::equal(jwv, std::array{1, 1, 3, 1, 1, 3, 1, 1}));
158 }
159
160 // Check explicitness
161 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, InputView, MoveOnlyInt>);
162 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, InputView, int>);
163 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, InputView&, int&>);
164 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, const InputView, const int>);
165 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, const InputView&, const int&>);
166}
167
168constexpr void test_ctor_with_non_view_and_element() {
169 // Check construction from `r` and `e`, when `r` does not model `std::ranges::view`
170
171 { // `r` and `e` are glvalues
172 InputRange r;
173 int e = 0;
174 std::ranges::join_with_view<View, Pattern> jwv(r, e);
175 assert(std::ranges::equal(jwv, std::array{2, 2, 0, 2, 2, 0, 2, 2}));
176 }
177
178 { // `r` and `e` are const glvalues
179 const InputRange r;
180 const int e = 1;
181 std::ranges::join_with_view<View, Pattern> jwv(r, e);
182 assert(std::ranges::equal(jwv, std::array{3, 3, 1, 3, 3, 1, 3, 3}));
183 }
184
185 { // `r` and `e` are prvalues
186 std::ranges::join_with_view<View, Pattern> jwv(InputRange{}, MoveOnlyInt{2});
187 assert(std::ranges::equal(jwv, std::array{4, 4, 2, 4, 4, 2, 4, 4}));
188 }
189
190 { // `r` and `e` are xvalues
191 InputRange r;
192 MoveOnlyInt e = 3;
193 std::ranges::join_with_view<View, Pattern> jwv(std::move(r), std::move(e));
194 assert(std::ranges::equal(jwv, std::array{4, 4, 3, 4, 4, 3, 4, 4}));
195 }
196
197 // Check explicitness
198 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, InputRange, MoveOnlyInt>);
199 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, InputRange, int>);
200 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, InputRange&, int&>);
201 static_assert(ConstructionIsExplicit<std::ranges::join_with_view<View, Pattern>, const InputRange&, const int&>);
202}
203
204constexpr void test_constraints() {
205 { // `R` is not an input range
206 using R = OutputView;
207 static_assert(!std::ranges::input_range<R>);
208 static_assert(std::constructible_from<View, std::views::all_t<R>>);
209 static_assert(std::constructible_from<Pattern, std::ranges::single_view<int>>);
210 static_assert(!std::constructible_from<std::ranges::join_with_view<View, Pattern>, R, int>);
211 }
212
213 { // `V` is not constructible from `views::all_t<R>`
214 using R = test_range<cpp20_input_iterator>;
215 static_assert(std::ranges::input_range<R>);
216 static_assert(!std::constructible_from<View, std::views::all_t<R>>);
217 static_assert(std::constructible_from<Pattern, std::ranges::single_view<int>>);
218 static_assert(!std::constructible_from<std::ranges::join_with_view<View, Pattern>, R, int>);
219 }
220
221 { // `Pattern` is not constructible from `single_view<range_value_t<InnerRng>>`
222 using R = InputView;
223 using Pat = test_view<forward_iterator>;
224 static_assert(std::ranges::input_range<R>);
225 static_assert(std::constructible_from<View, std::views::all_t<R>>);
226 static_assert(!std::constructible_from<Pat, std::ranges::single_view<int>>);
227 static_assert(!std::constructible_from<std::ranges::join_with_view<View, Pat>, R, int>);
228 }
229}
230
231constexpr bool test() {
232 test_ctor_with_view_and_element();
233 test_ctor_with_non_view_and_element();
234 test_constraints();
235
236 return true;
237}
238
239int main(int, char**) {
240 test();
241 static_assert(test());
242
243 return 0;
244}
245

source code of libcxx/test/std/ranges/range.adaptors/range.join.with/range.join.with.view/ctor.range.element.pass.cpp