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 // <algorithm>
13
14 // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
15 // copy_constructible F, class Proj = identity>
16 // requires indirectly_writable<O, indirect_result_t<F&, projected<I, Proj>>>
17 // constexpr ranges::unary_transform_result<I, O>
18 // ranges::transform(I first1, S last1, O result, F op, Proj proj = {});
19 // template<input_range R, weakly_incrementable O, copy_constructible F,
20 // class Proj = identity>
21 // requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R>, Proj>>>
22 // constexpr ranges::unary_transform_result<borrowed_iterator_t<R>, O>
23 // ranges::transform(R&& r, O result, F op, Proj proj = {});
24 // template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
25 // weakly_incrementable O, copy_constructible F, class Proj1 = identity,
26 // class Proj2 = identity>
27 // requires indirectly_writable<O, indirect_result_t<F&, projected<I1, Proj1>,
28 // projected<I2, Proj2>>>
29 // constexpr ranges::binary_transform_result<I1, I2, O>
30 // ranges::transform(I1 first1, S1 last1, I2 first2, S2 last2, O result,
31 // F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
32 // template<input_range R1, input_range R2, weakly_incrementable O,
33 // copy_constructible F, class Proj1 = identity, class Proj2 = identity>
34 // requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R1>, Proj1>,
35 // projected<iterator_t<R2>, Proj2>>>
36 // constexpr ranges::binary_transform_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
37 // ranges::transform(R1&& r1, R2&& r2, O result,
38 // F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
39
40 #include <algorithm>
41 #include <array>
42 #include <cassert>
43 #include <functional>
44 #include <ranges>
45
46 #include "test_iterators.h"
47 #include "almost_satisfies_types.h"
48
49 struct BinaryFunc {
50 int operator()(int, int);
51 };
52
53 template <class Range>
54 concept HasTranformR = requires(Range r, int* out) {
55 std::ranges::transform(r, out, std::identity{});
56 std::ranges::transform(r, r, out, BinaryFunc{});
57 };
58 static_assert(HasTranformR<std::array<int, 1>>);
59 static_assert(!HasTranformR<int>);
60 static_assert(!HasTranformR<InputRangeNotDerivedFrom>);
61 static_assert(!HasTranformR<InputRangeNotIndirectlyReadable>);
62 static_assert(!HasTranformR<InputRangeNotInputOrOutputIterator>);
63 static_assert(!HasTranformR<InputRangeNotSentinelSemiregular>);
64 static_assert(!HasTranformR<InputRangeNotSentinelEqualityComparableWith>);
65
66 template <class It, class Sent = It>
67 concept HasTransformIt = requires(It it, Sent sent, int* out) {
68 std::ranges::transform(it, sent, out, std::identity{});
69 std::ranges::transform(it, sent, it, sent, out, BinaryFunc{});
70 };
71 static_assert(HasTransformIt<int*>);
72 static_assert(!HasTransformIt<InputIteratorNotDerivedFrom>);
73 static_assert(!HasTransformIt<InputIteratorNotIndirectlyReadable>);
74 static_assert(!HasTransformIt<InputIteratorNotInputOrOutputIterator>);
75 static_assert(!HasTransformIt<cpp20_input_iterator<int*>, SentinelForNotSemiregular>);
76 static_assert(!HasTransformIt<cpp20_input_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>);
77
78 template <class It>
79 concept HasTransformOut = requires(int* it, int* sent, It out, std::array<int, 2> range) {
80 std::ranges::transform(it, sent, out, std::identity{});
81 std::ranges::transform(it, sent, it, sent, out, BinaryFunc{});
82 std::ranges::transform(range, out, std::identity{});
83 std::ranges::transform(range, range, out, BinaryFunc{});
84 };
85 static_assert(HasTransformOut<int*>);
86 static_assert(!HasTransformOut<WeaklyIncrementableNotMovable>);
87
88 // check indirectly_readable
89 static_assert(HasTransformOut<char*>);
90 static_assert(!HasTransformOut<int**>);
91
92 struct MoveOnlyFunctor {
93 MoveOnlyFunctor(const MoveOnlyFunctor&) = delete;
94 MoveOnlyFunctor(MoveOnlyFunctor&&) = default;
95 int operator()(int);
96 int operator()(int, int);
97 };
98
99 template <class Func>
100 concept HasTransformFuncUnary = requires(int* it, int* sent, int* out, std::array<int, 2> range, Func func) {
101 std::ranges::transform(it, sent, out, func);
102 std::ranges::transform(range, out, func);
103 };
104 static_assert(HasTransformFuncUnary<std::identity>);
105 static_assert(!HasTransformFuncUnary<MoveOnlyFunctor>);
106
107 template <class Func>
108 concept HasTransformFuncBinary = requires(int* it, int* sent, int* out, std::array<int, 2> range, Func func) {
109 std::ranges::transform(it, sent, it, sent, out, func);
110 std::ranges::transform(range, range, out, func);
111 };
112 static_assert(HasTransformFuncBinary<BinaryFunc>);
113 static_assert(!HasTransformFuncBinary<MoveOnlyFunctor>);
114
115 static_assert(std::is_same_v<std::ranges::unary_transform_result<int, long>, std::ranges::in_out_result<int, long>>);
116 static_assert(std::is_same_v<std::ranges::binary_transform_result<int, long, char>,
117 std::ranges::in_in_out_result<int, long, char>>);
118
119 template <class In1, class In2, class Out, class Sent1, class Sent2>
test_iterators()120 constexpr bool test_iterators() {
121 { // simple
122 { // unary
123 {
124 int a[] = {1, 2, 3, 4, 5};
125 int b[5];
126 std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret =
127 std::ranges::transform(In1(a), Sent1(In1(a + 5)), Out(b), [](int i) { return i * 2; });
128 assert((std::to_array(b) == std::array{2, 4, 6, 8, 10}));
129 assert(base(ret.in) == a + 5);
130 assert(base(ret.out) == b + 5);
131 }
132
133 {
134 int a[] = {1, 2, 3, 4, 5};
135 int b[5];
136 auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 5)));
137 std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret =
138 std::ranges::transform(range, Out(b), [](int i) { return i * 2; });
139 assert((std::to_array(b) == std::array{2, 4, 6, 8, 10}));
140 assert(base(ret.in) == a + 5);
141 assert(base(ret.out) == b + 5);
142 }
143 }
144
145 { // binary
146 {
147 int a[] = {1, 2, 3, 4, 5};
148 int b[] = {5, 4, 3, 2, 1};
149 int c[5];
150
151 std::same_as<std::ranges::in_in_out_result<In1, In2, Out>> decltype(auto) ret = std::ranges::transform(
152 In1(a), Sent1(In1(a + 5)), In2(b), Sent2(In2(b + 5)), Out(c), [](int i, int j) { return i + j; });
153
154 assert((std::to_array(c) == std::array{6, 6, 6, 6, 6}));
155 assert(base(ret.in1) == a + 5);
156 assert(base(ret.in2) == b + 5);
157 assert(base(ret.out) == c + 5);
158 }
159
160 {
161 int a[] = {1, 2, 3, 4, 5};
162 int b[] = {5, 4, 3, 2, 1};
163 int c[5];
164
165 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 5)));
166 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 5)));
167
168 std::same_as<std::ranges::in_in_out_result<In1, In2, Out>> decltype(auto) ret = std::ranges::transform(
169 range1, range2, Out(c), [](int i, int j) { return i + j; });
170
171 assert((std::to_array(c) == std::array{6, 6, 6, 6, 6}));
172 assert(base(ret.in1) == a + 5);
173 assert(base(ret.in2) == b + 5);
174 assert(base(ret.out) == c + 5);
175 }
176 }
177 }
178
179 { // first range empty
180 { // unary
181 {
182 int a[] = {};
183 int b[5];
184 auto ret = std::ranges::transform(In1(a), Sent1(In1(a)), Out(b), [](int i) { return i * 2; });
185 assert(base(ret.in) == a);
186 assert(base(ret.out) == b);
187 }
188
189 {
190 int a[] = {};
191 int b[5];
192 auto range = std::ranges::subrange(In1(a), Sent1(In1(a)));
193 auto ret = std::ranges::transform(range, Out(b), [](int i) { return i * 2; });
194 assert(base(ret.in) == a);
195 assert(base(ret.out) == b);
196 }
197 }
198
199 { // binary
200 {
201 int a[] = {};
202 int b[] = {5, 4, 3, 2, 1};
203 int c[5];
204
205 auto ret = std::ranges::transform(
206 In1(a), Sent1(In1(a)), In2(b), Sent2(In2(b + 5)), Out(c), [](int i, int j) { return i + j; });
207
208 assert(base(ret.in1) == a);
209 assert(base(ret.in2) == b);
210 assert(base(ret.out) == c);
211 }
212
213 {
214 int a[] = {};
215 int b[] = {5, 4, 3, 2, 1};
216 int c[5];
217
218 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a)));
219 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 5)));
220
221 auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; });
222
223 assert(base(ret.in1) == a);
224 assert(base(ret.in2) == b);
225 assert(base(ret.out) == c);
226 }
227 }
228 }
229
230 { // second range empty (binary)
231 {
232 int a[] = {5, 4, 3, 2, 1};
233 int b[] = {};
234 int c[5];
235
236 auto ret = std::ranges::transform(
237 In1(a), Sent1(In1(a + 5)), In2(b), Sent2(In2(b)), Out(c), [](int i, int j) { return i + j; });
238
239 assert(base(ret.in1) == a);
240 assert(base(ret.in2) == b);
241 assert(base(ret.out) == c);
242 }
243
244 {
245 int a[] = {5, 4, 3, 2, 1};
246 int b[] = {};
247 int c[5];
248
249 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 5)));
250 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b)));
251
252 auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; });
253
254 assert(base(ret.in1) == a);
255 assert(base(ret.in2) == b);
256 assert(base(ret.out) == c);
257 }
258 }
259
260 { // both ranges empty (binary)
261 {
262 int a[] = {};
263 int b[] = {};
264 int c[5];
265
266 auto ret = std::ranges::transform(
267 In1(a), Sent1(In1(a)), In2(b), Sent2(In2(b)), Out(c), [](int i, int j) { return i + j; });
268
269 assert(base(ret.in1) == a);
270 assert(base(ret.in2) == b);
271 assert(base(ret.out) == c);
272 }
273
274 {
275 int a[] = {};
276 int b[] = {};
277 int c[5];
278
279 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a)));
280 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b)));
281
282 auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; });
283
284 assert(base(ret.in1) == a);
285 assert(base(ret.in2) == b);
286 assert(base(ret.out) == c);
287 }
288 }
289
290 { // first range one element
291 { // unary
292 {
293 int a[] = {2};
294 int b[5];
295 auto ret = std::ranges::transform(In1(a), Sent1(In1(a + 1)), Out(b), [](int i) { return i * 2; });
296 assert(b[0] == 4);
297 assert(base(ret.in) == a + 1);
298 assert(base(ret.out) == b + 1);
299 }
300
301 {
302 int a[] = {2};
303 int b[5];
304 auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 1)));
305 auto ret = std::ranges::transform(range, Out(b), [](int i) { return i * 2; });
306 assert(b[0] == 4);
307 assert(base(ret.in) == a + 1);
308 assert(base(ret.out) == b + 1);
309 }
310 }
311
312 { // binary
313 {
314 int a[] = {2};
315 int b[] = {5, 4, 3, 2, 1};
316 int c[5];
317
318 auto ret = std::ranges::transform(
319 In1(a), Sent1(In1(a + 1)), In2(b), Sent2(In2(b + 5)), Out(c), [](int i, int j) { return i + j; });
320
321 assert(c[0] == 7);
322 assert(base(ret.in1) == a + 1);
323 assert(base(ret.in2) == b + 1);
324 assert(base(ret.out) == c + 1);
325 }
326
327 {
328 int a[] = {2};
329 int b[] = {5, 4, 3, 2, 1};
330 int c[5];
331
332 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 1)));
333 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 5)));
334
335 auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; });
336
337 assert(c[0] == 7);
338 assert(base(ret.in1) == a + 1);
339 assert(base(ret.in2) == b + 1);
340 assert(base(ret.out) == c + 1);
341 }
342 }
343 }
344
345 { // second range contains one element (binary)
346 {
347 int a[] = {5, 4, 3, 2, 1};
348 int b[] = {4};
349 int c[5];
350
351 auto ret = std::ranges::transform(
352 In1(a), Sent1(In1(a + 5)), In2(b), Sent2(In2(b + 1)), Out(c), [](int i, int j) { return i + j; });
353
354 assert(c[0] == 9);
355 assert(base(ret.in1) == a + 1);
356 assert(base(ret.in2) == b + 1);
357 assert(base(ret.out) == c + 1);
358 }
359
360 {
361 int a[] = {5, 4, 3, 2, 1};
362 int b[] = {4};
363 int c[5];
364
365 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 5)));
366 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 1)));
367
368 auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; });
369
370 assert(c[0] == 9);
371 assert(base(ret.in1) == a + 1);
372 assert(base(ret.in2) == b + 1);
373 assert(base(ret.out) == c + 1);
374 }
375 }
376
377 { // check that the transform function and projection call counts are correct
378 { // unary
379 {
380 int predCount = 0;
381 int projCount = 0;
382 auto pred = [&](int) { ++predCount; return 1; };
383 auto proj = [&](int) { ++projCount; return 0; };
384 int a[] = {1, 2, 3, 4};
385 std::array<int, 4> c;
386 std::ranges::transform(In1(a), Sent1(In1(a + 4)), Out(c.data()), pred, proj);
387 assert(predCount == 4);
388 assert(projCount == 4);
389 assert((c == std::array{1, 1, 1, 1}));
390 }
391 {
392 int predCount = 0;
393 int projCount = 0;
394 auto pred = [&](int) { ++predCount; return 1; };
395 auto proj = [&](int) { ++projCount; return 0; };
396 int a[] = {1, 2, 3, 4};
397 std::array<int, 4> c;
398 auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 4)));
399 std::ranges::transform(range, Out(c.data()), pred, proj);
400 assert(predCount == 4);
401 assert(projCount == 4);
402 assert((c == std::array{1, 1, 1, 1}));
403 }
404 }
405 { // binary
406 {
407 int predCount = 0;
408 int proj1Count = 0;
409 int proj2Count = 0;
410 auto pred = [&](int, int) { ++predCount; return 1; };
411 auto proj1 = [&](int) { ++proj1Count; return 0; };
412 auto proj2 = [&](int) { ++proj2Count; return 0; };
413 int a[] = {1, 2, 3, 4};
414 int b[] = {1, 2, 3, 4};
415 std::array<int, 4> c;
416 std::ranges::transform(In1(a), Sent1(In1(a + 4)), In2(b), Sent2(In2(b + 4)), Out(c.data()), pred, proj1, proj2);
417 assert(predCount == 4);
418 assert(proj1Count == 4);
419 assert(proj2Count == 4);
420 assert((c == std::array{1, 1, 1, 1}));
421 }
422 {
423 int predCount = 0;
424 int proj1Count = 0;
425 int proj2Count = 0;
426 auto pred = [&](int, int) { ++predCount; return 1; };
427 auto proj1 = [&](int) { ++proj1Count; return 0; };
428 auto proj2 = [&](int) { ++proj2Count; return 0; };
429 int a[] = {1, 2, 3, 4};
430 int b[] = {1, 2, 3, 4};
431 std::array<int, 4> c;
432 auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 4)));
433 auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 4)));
434 std::ranges::transform(range1, range2, Out(c.data()), pred, proj1, proj2);
435 assert(predCount == 4);
436 assert(proj1Count == 4);
437 assert(proj2Count == 4);
438 assert((c == std::array{1, 1, 1, 1}));
439 }
440 }
441 }
442
443 return true;
444 }
445
446 template <class In2, class Out, class Sent2 = In2>
test_iterator_in1()447 constexpr void test_iterator_in1() {
448 test_iterators<cpp17_input_iterator<int*>, In2, Out, sentinel_wrapper<cpp17_input_iterator<int*>>, Sent2>();
449 test_iterators<cpp20_input_iterator<int*>, In2, Out, sentinel_wrapper<cpp20_input_iterator<int*>>, Sent2>();
450 test_iterators<forward_iterator<int*>, In2, Out, forward_iterator<int*>, Sent2>();
451 test_iterators<bidirectional_iterator<int*>, In2, Out, bidirectional_iterator<int*>, Sent2>();
452 test_iterators<random_access_iterator<int*>, In2, Out, random_access_iterator<int*>, Sent2>();
453 test_iterators<contiguous_iterator<int*>, In2, Out, contiguous_iterator<int*>, Sent2>();
454 test_iterators<int*, In2, Out, int*, Sent2>();
455 // static_asserting here to avoid hitting the constant evaluation step limit
456 static_assert(test_iterators<cpp17_input_iterator<int*>, In2, Out, sentinel_wrapper<cpp17_input_iterator<int*>>, Sent2>());
457 static_assert(test_iterators<cpp20_input_iterator<int*>, In2, Out, sentinel_wrapper<cpp20_input_iterator<int*>>, Sent2>());
458 static_assert(test_iterators<forward_iterator<int*>, In2, Out, forward_iterator<int*>, Sent2>());
459 static_assert(test_iterators<bidirectional_iterator<int*>, In2, Out, bidirectional_iterator<int*>, Sent2>());
460 static_assert(test_iterators<random_access_iterator<int*>, In2, Out, random_access_iterator<int*>, Sent2>());
461 static_assert(test_iterators<contiguous_iterator<int*>, In2, Out, contiguous_iterator<int*>, Sent2>());
462 static_assert(test_iterators<int*, In2, Out, int*, Sent2>());
463 }
464
465 template <class Out>
test_iterators_in1_in2()466 void test_iterators_in1_in2() {
467 test_iterator_in1<cpp17_input_iterator<int*>, Out, sentinel_wrapper<cpp17_input_iterator<int*>>>();
468 test_iterator_in1<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>();
469 test_iterator_in1<forward_iterator<int*>, Out>();
470 test_iterator_in1<bidirectional_iterator<int*>, Out>();
471 test_iterator_in1<random_access_iterator<int*>, Out>();
472 test_iterator_in1<contiguous_iterator<int*>, Out>();
473 test_iterator_in1<int*, Out>();
474 }
475
test()476 constexpr bool test() {
477 { // check that std::ranges::dangling is returned properly
478 { // unary
479 std::array<int, 5> b;
480 std::same_as<std::ranges::in_out_result<std::ranges::dangling, int*>> auto ret =
481 std::ranges::transform(std::array{1, 2, 3, 5, 4}, b.data(), [](int i) { return i * i; });
482 assert((b == std::array{1, 4, 9, 25, 16}));
483 assert(ret.out == b.data() + b.size());
484 }
485 // binary
486 {
487 int b[] = {2, 5, 4, 3, 1};
488 std::array<int, 5> c;
489 std::same_as<std::ranges::in_in_out_result<std::ranges::dangling, int*, int*>> auto ret =
490 std::ranges::transform(std::array{1, 2, 3, 5, 4}, b, c.data(), [](int i, int j) { return i * j; });
491 assert((c == std::array{2, 10, 12, 15, 4}));
492 assert(ret.in2 == b + 5);
493 assert(ret.out == c.data() + c.size());
494 }
495 {
496 int a[] = {2, 5, 4, 3, 1, 4, 5, 6};
497 std::array<int, 8> c;
498 std::same_as<std::ranges::in_in_out_result<int*, std::ranges::dangling, int*>> auto ret =
499 std::ranges::transform(a, std::array{1, 2, 3, 5, 4, 5, 6, 7}, c.data(), [](int i, int j) { return i * j; });
500 assert((c == std::array{2, 10, 12, 15, 4, 20, 30, 42}));
501 assert(ret.in1 == a + 8);
502 assert(ret.out == c.data() + c.size());
503 }
504 {
505 std::array<int, 3> c;
506 std::same_as<std::ranges::in_in_out_result<std::ranges::dangling, std::ranges::dangling, int*>> auto ret =
507 std::ranges::transform(std::array{4, 4, 4}, std::array{4, 4, 4}, c.data(), [](int i, int j) { return i * j; });
508 assert((c == std::array{16, 16, 16}));
509 assert(ret.out == c.data() + c.size());
510 }
511 }
512
513 { // check that returning another type from the projection works
514 { // unary
515 {
516 struct S { int i; int other; };
517 S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} };
518 std::array<int, 4> b;
519 std::ranges::transform(a, a + 4, b.begin(), [](S s) { return s.i; });
520 assert((b == std::array{0, 1, 3, 10}));
521 }
522 {
523 struct S { int i; int other; };
524 S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} };
525 std::array<int, 4> b;
526 std::ranges::transform(a, b.begin(), [](S s) { return s.i; });
527 assert((b == std::array{0, 1, 3, 10}));
528 }
529 }
530 { // binary
531 {
532 struct S { int i; int other; };
533 S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} };
534 S b[] = { S{0, 10}, S{1, 20}, S{3, 30}, S{10, 40} };
535 std::array<int, 4> c;
536 std::ranges::transform(a, a + 4, b, b + 4, c.begin(), [](S s1, S s2) { return s1.i + s2.other; });
537 assert((c == std::array{10, 21, 33, 50}));
538 }
539 {
540 struct S { int i; int other; };
541 S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} };
542 S b[] = { S{0, 10}, S{1, 20}, S{3, 30}, S{10, 40} };
543 std::array<int, 4> c;
544 std::ranges::transform(a, b, c.begin(), [](S s1, S s2) { return s1.i + s2.other; });
545 assert((c == std::array{10, 21, 33, 50}));
546 }
547 }
548 }
549
550 { // check that std::invoke is used
551 { // unary
552 struct S { int i; };
553 S a[] = { S{1}, S{3}, S{2} };
554 std::array<int, 3> b;
555 auto ret = std::ranges::transform(a, b.data(), [](int i) { return i; }, &S::i);
556 assert((b == std::array{1, 3, 2}));
557 assert(ret.out == b.data() + 3);
558 }
559 { // binary
560 struct S { int i; };
561 S a[] = { S{1}, S{3}, S{2} };
562 S b[] = { S{2}, S{5}, S{3} };
563 std::array<int, 3> c;
564 auto ret = std::ranges::transform(a, b, c.data(), [](int i, int j) { return i + j + 2; }, &S::i, &S::i);
565 assert((c == std::array{5, 10, 7}));
566 assert(ret.out == c.data() + 3);
567 }
568 }
569
570 return true;
571 }
572
main(int,char **)573 int main(int, char**) {
574 test_iterators_in1_in2<cpp17_output_iterator<int*>>();
575 test_iterators_in1_in2<cpp20_output_iterator<int*>>();
576 test_iterators_in1_in2<forward_iterator<int*>>();
577 test_iterators_in1_in2<bidirectional_iterator<int*>>();
578 test_iterators_in1_in2<random_access_iterator<int*>>();
579 test_iterators_in1_in2<contiguous_iterator<int*>>();
580 test_iterators_in1_in2<int*>();
581 test();
582 static_assert(test());
583
584 return 0;
585 }
586