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