13ba8548cSNikolas Klauser //===----------------------------------------------------------------------===//
23ba8548cSNikolas Klauser //
33ba8548cSNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43ba8548cSNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
53ba8548cSNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63ba8548cSNikolas Klauser //
73ba8548cSNikolas Klauser //===----------------------------------------------------------------------===//
83ba8548cSNikolas Klauser 
93ba8548cSNikolas Klauser // UNSUPPORTED: c++03, c++11, c++14, c++17
103ba8548cSNikolas Klauser // UNSUPPORTED: libcpp-has-no-incomplete-ranges
113ba8548cSNikolas Klauser 
123ba8548cSNikolas Klauser // <algorithm>
133ba8548cSNikolas Klauser 
143ba8548cSNikolas Klauser // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
153ba8548cSNikolas Klauser //          copy_constructible F, class Proj = identity>
163ba8548cSNikolas Klauser //   requires indirectly_writable<O, indirect_result_t<F&, projected<I, Proj>>>
173ba8548cSNikolas Klauser //   constexpr ranges::unary_transform_result<I, O>
183ba8548cSNikolas Klauser //     ranges::transform(I first1, S last1, O result, F op, Proj proj = {});
193ba8548cSNikolas Klauser // template<input_range R, weakly_incrementable O, copy_constructible F,
203ba8548cSNikolas Klauser //          class Proj = identity>
213ba8548cSNikolas Klauser //   requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R>, Proj>>>
223ba8548cSNikolas Klauser //   constexpr ranges::unary_transform_result<borrowed_iterator_t<R>, O>
233ba8548cSNikolas Klauser //     ranges::transform(R&& r, O result, F op, Proj proj = {});
243ba8548cSNikolas Klauser // template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
253ba8548cSNikolas Klauser //          weakly_incrementable O, copy_constructible F, class Proj1 = identity,
263ba8548cSNikolas Klauser //          class Proj2 = identity>
273ba8548cSNikolas Klauser //   requires indirectly_writable<O, indirect_result_t<F&, projected<I1, Proj1>,
283ba8548cSNikolas Klauser //                                          projected<I2, Proj2>>>
293ba8548cSNikolas Klauser //   constexpr ranges::binary_transform_result<I1, I2, O>
303ba8548cSNikolas Klauser //     ranges::transform(I1 first1, S1 last1, I2 first2, S2 last2, O result,
313ba8548cSNikolas Klauser //                       F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
323ba8548cSNikolas Klauser // template<input_range R1, input_range R2, weakly_incrementable O,
333ba8548cSNikolas Klauser //          copy_constructible F, class Proj1 = identity, class Proj2 = identity>
343ba8548cSNikolas Klauser //   requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R1>, Proj1>,
353ba8548cSNikolas Klauser //                                          projected<iterator_t<R2>, Proj2>>>
363ba8548cSNikolas Klauser //   constexpr ranges::binary_transform_result<borrowed_iterator_t<R1>, borrowed_iterator_t<R2>, O>
373ba8548cSNikolas Klauser //     ranges::transform(R1&& r1, R2&& r2, O result,
383ba8548cSNikolas Klauser //                       F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
393ba8548cSNikolas Klauser 
403ba8548cSNikolas Klauser #include <algorithm>
413ba8548cSNikolas Klauser #include <array>
423ba8548cSNikolas Klauser #include <cassert>
43*faef447eSNikolas Klauser #include <functional>
443ba8548cSNikolas Klauser #include <ranges>
453ba8548cSNikolas Klauser 
463ba8548cSNikolas Klauser #include "test_iterators.h"
473ba8548cSNikolas Klauser #include "almost_satisfies_types.h"
483ba8548cSNikolas Klauser 
493ba8548cSNikolas Klauser struct BinaryFunc {
503ba8548cSNikolas Klauser   int operator()(int, int);
513ba8548cSNikolas Klauser };
523ba8548cSNikolas Klauser 
533ba8548cSNikolas Klauser template <class Range>
543ba8548cSNikolas Klauser concept HasTranformR = requires(Range r, int* out) {
553ba8548cSNikolas Klauser   std::ranges::transform(r, out, std::identity{});
563ba8548cSNikolas Klauser   std::ranges::transform(r, r, out, BinaryFunc{});
573ba8548cSNikolas Klauser };
583ba8548cSNikolas Klauser static_assert(HasTranformR<std::array<int, 1>>);
593ba8548cSNikolas Klauser static_assert(!HasTranformR<int>);
603ba8548cSNikolas Klauser static_assert(!HasTranformR<InputRangeNotDerivedFrom>);
613ba8548cSNikolas Klauser static_assert(!HasTranformR<InputRangeNotIndirectlyReadable>);
623ba8548cSNikolas Klauser static_assert(!HasTranformR<InputRangeNotInputOrOutputIterator>);
633ba8548cSNikolas Klauser static_assert(!HasTranformR<InputRangeNotSentinelSemiregular>);
643ba8548cSNikolas Klauser static_assert(!HasTranformR<InputRangeNotSentinelEqualityComparableWith>);
653ba8548cSNikolas Klauser 
663ba8548cSNikolas Klauser template <class It, class Sent = It>
673ba8548cSNikolas Klauser concept HasTransformIt = requires(It it, Sent sent, int* out) {
683ba8548cSNikolas Klauser   std::ranges::transform(it, sent, out, std::identity{});
693ba8548cSNikolas Klauser   std::ranges::transform(it, sent, it, sent, out, BinaryFunc{});
703ba8548cSNikolas Klauser };
713ba8548cSNikolas Klauser static_assert(HasTransformIt<int*>);
723ba8548cSNikolas Klauser static_assert(!HasTransformIt<InputIteratorNotDerivedFrom>);
733ba8548cSNikolas Klauser static_assert(!HasTransformIt<InputIteratorNotIndirectlyReadable>);
743ba8548cSNikolas Klauser static_assert(!HasTransformIt<InputIteratorNotInputOrOutputIterator>);
753ba8548cSNikolas Klauser static_assert(!HasTransformIt<cpp20_input_iterator<int*>, SentinelForNotSemiregular>);
763ba8548cSNikolas Klauser static_assert(!HasTransformIt<cpp20_input_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>);
773ba8548cSNikolas Klauser 
783ba8548cSNikolas Klauser template <class It>
793ba8548cSNikolas Klauser concept HasTransformOut = requires(int* it, int* sent, It out, std::array<int, 2> range) {
803ba8548cSNikolas Klauser   std::ranges::transform(it, sent, out, std::identity{});
813ba8548cSNikolas Klauser   std::ranges::transform(it, sent, it, sent, out, BinaryFunc{});
823ba8548cSNikolas Klauser   std::ranges::transform(range, out, std::identity{});
833ba8548cSNikolas Klauser   std::ranges::transform(range, range, out, BinaryFunc{});
843ba8548cSNikolas Klauser };
853ba8548cSNikolas Klauser static_assert(HasTransformOut<int*>);
863ba8548cSNikolas Klauser static_assert(!HasTransformOut<WeaklyIncrementableNotMovable>);
873ba8548cSNikolas Klauser 
883ba8548cSNikolas Klauser // check indirectly_readable
893ba8548cSNikolas Klauser static_assert(HasTransformOut<char*>);
903ba8548cSNikolas Klauser static_assert(!HasTransformOut<int**>);
913ba8548cSNikolas Klauser 
923ba8548cSNikolas Klauser struct MoveOnlyFunctor {
933ba8548cSNikolas Klauser   MoveOnlyFunctor(const MoveOnlyFunctor&) = delete;
943ba8548cSNikolas Klauser   MoveOnlyFunctor(MoveOnlyFunctor&&) = default;
953ba8548cSNikolas Klauser   int operator()(int);
963ba8548cSNikolas Klauser   int operator()(int, int);
973ba8548cSNikolas Klauser };
983ba8548cSNikolas Klauser 
993ba8548cSNikolas Klauser template <class Func>
1003ba8548cSNikolas Klauser concept HasTransformFuncUnary = requires(int* it, int* sent, int* out, std::array<int, 2> range, Func func) {
1013ba8548cSNikolas Klauser   std::ranges::transform(it, sent, out, func);
1023ba8548cSNikolas Klauser   std::ranges::transform(range, out, func);
1033ba8548cSNikolas Klauser };
1043ba8548cSNikolas Klauser static_assert(HasTransformFuncUnary<std::identity>);
1053ba8548cSNikolas Klauser static_assert(!HasTransformFuncUnary<MoveOnlyFunctor>);
1063ba8548cSNikolas Klauser 
1073ba8548cSNikolas Klauser template <class Func>
1083ba8548cSNikolas Klauser concept HasTransformFuncBinary = requires(int* it, int* sent, int* out, std::array<int, 2> range, Func func) {
1093ba8548cSNikolas Klauser   std::ranges::transform(it, sent, it, sent, out, func);
1103ba8548cSNikolas Klauser   std::ranges::transform(range, range, out, func);
1113ba8548cSNikolas Klauser };
1123ba8548cSNikolas Klauser static_assert(HasTransformFuncBinary<BinaryFunc>);
1133ba8548cSNikolas Klauser static_assert(!HasTransformFuncBinary<MoveOnlyFunctor>);
1143ba8548cSNikolas Klauser 
1153ba8548cSNikolas Klauser static_assert(std::is_same_v<std::ranges::unary_transform_result<int, long>, std::ranges::in_out_result<int, long>>);
1163ba8548cSNikolas Klauser static_assert(std::is_same_v<std::ranges::binary_transform_result<int, long, char>,
1173ba8548cSNikolas Klauser                              std::ranges::in_in_out_result<int, long, char>>);
1183ba8548cSNikolas Klauser 
1193ba8548cSNikolas Klauser template <class In1, class In2, class Out, class Sent1, class Sent2>
test_iterators()1203ba8548cSNikolas Klauser constexpr bool test_iterators() {
1213ba8548cSNikolas Klauser   { // simple
1223ba8548cSNikolas Klauser     { // unary
1233ba8548cSNikolas Klauser       {
1243ba8548cSNikolas Klauser         int a[] = {1, 2, 3, 4, 5};
1253ba8548cSNikolas Klauser         int b[5];
1263ba8548cSNikolas Klauser         std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret =
1273ba8548cSNikolas Klauser           std::ranges::transform(In1(a), Sent1(In1(a + 5)), Out(b), [](int i) { return i * 2; });
1283ba8548cSNikolas Klauser         assert((std::to_array(b) == std::array{2, 4, 6, 8, 10}));
1293ba8548cSNikolas Klauser         assert(base(ret.in) == a + 5);
1303ba8548cSNikolas Klauser         assert(base(ret.out) == b + 5);
1313ba8548cSNikolas Klauser       }
1323ba8548cSNikolas Klauser 
1333ba8548cSNikolas Klauser       {
1343ba8548cSNikolas Klauser         int a[] = {1, 2, 3, 4, 5};
1353ba8548cSNikolas Klauser         int b[5];
1363ba8548cSNikolas Klauser         auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 5)));
1373ba8548cSNikolas Klauser         std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret =
1383ba8548cSNikolas Klauser           std::ranges::transform(range, Out(b), [](int i) { return i * 2; });
1393ba8548cSNikolas Klauser         assert((std::to_array(b) == std::array{2, 4, 6, 8, 10}));
1403ba8548cSNikolas Klauser         assert(base(ret.in) == a + 5);
1413ba8548cSNikolas Klauser         assert(base(ret.out) == b + 5);
1423ba8548cSNikolas Klauser       }
1433ba8548cSNikolas Klauser     }
1443ba8548cSNikolas Klauser 
1453ba8548cSNikolas Klauser     { // binary
1463ba8548cSNikolas Klauser       {
1473ba8548cSNikolas Klauser         int a[] = {1, 2, 3, 4, 5};
1483ba8548cSNikolas Klauser         int b[] = {5, 4, 3, 2, 1};
1493ba8548cSNikolas Klauser         int c[5];
1503ba8548cSNikolas Klauser 
1513ba8548cSNikolas Klauser         std::same_as<std::ranges::in_in_out_result<In1, In2, Out>> decltype(auto) ret = std::ranges::transform(
1523ba8548cSNikolas Klauser             In1(a), Sent1(In1(a + 5)), In2(b), Sent2(In2(b + 5)), Out(c), [](int i, int j) { return i + j; });
1533ba8548cSNikolas Klauser 
1543ba8548cSNikolas Klauser         assert((std::to_array(c) == std::array{6, 6, 6, 6, 6}));
1553ba8548cSNikolas Klauser         assert(base(ret.in1) == a + 5);
1563ba8548cSNikolas Klauser         assert(base(ret.in2) == b + 5);
1573ba8548cSNikolas Klauser         assert(base(ret.out) == c + 5);
1583ba8548cSNikolas Klauser       }
1593ba8548cSNikolas Klauser 
1603ba8548cSNikolas Klauser       {
1613ba8548cSNikolas Klauser         int a[] = {1, 2, 3, 4, 5};
1623ba8548cSNikolas Klauser         int b[] = {5, 4, 3, 2, 1};
1633ba8548cSNikolas Klauser         int c[5];
1643ba8548cSNikolas Klauser 
1653ba8548cSNikolas Klauser         auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 5)));
1663ba8548cSNikolas Klauser         auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 5)));
1673ba8548cSNikolas Klauser 
1683ba8548cSNikolas Klauser         std::same_as<std::ranges::in_in_out_result<In1, In2, Out>> decltype(auto) ret = std::ranges::transform(
1693ba8548cSNikolas Klauser             range1, range2, Out(c), [](int i, int j) { return i + j; });
1703ba8548cSNikolas Klauser 
1713ba8548cSNikolas Klauser         assert((std::to_array(c) == std::array{6, 6, 6, 6, 6}));
1723ba8548cSNikolas Klauser         assert(base(ret.in1) == a + 5);
1733ba8548cSNikolas Klauser         assert(base(ret.in2) == b + 5);
1743ba8548cSNikolas Klauser         assert(base(ret.out) == c + 5);
1753ba8548cSNikolas Klauser       }
1763ba8548cSNikolas Klauser     }
1773ba8548cSNikolas Klauser   }
1783ba8548cSNikolas Klauser 
1793ba8548cSNikolas Klauser   { // first range empty
1803ba8548cSNikolas Klauser     { // unary
1813ba8548cSNikolas Klauser       {
1823ba8548cSNikolas Klauser         int a[] = {};
1833ba8548cSNikolas Klauser         int b[5];
1843ba8548cSNikolas Klauser         auto ret = std::ranges::transform(In1(a), Sent1(In1(a)), Out(b), [](int i) { return i * 2; });
1853ba8548cSNikolas Klauser         assert(base(ret.in) == a);
1863ba8548cSNikolas Klauser         assert(base(ret.out) == b);
1873ba8548cSNikolas Klauser       }
1883ba8548cSNikolas Klauser 
1893ba8548cSNikolas Klauser       {
1903ba8548cSNikolas Klauser         int a[] = {};
1913ba8548cSNikolas Klauser         int b[5];
1923ba8548cSNikolas Klauser         auto range = std::ranges::subrange(In1(a), Sent1(In1(a)));
1933ba8548cSNikolas Klauser         auto ret = std::ranges::transform(range, Out(b), [](int i) { return i * 2; });
1943ba8548cSNikolas Klauser         assert(base(ret.in) == a);
1953ba8548cSNikolas Klauser         assert(base(ret.out) == b);
1963ba8548cSNikolas Klauser       }
1973ba8548cSNikolas Klauser     }
1983ba8548cSNikolas Klauser 
1993ba8548cSNikolas Klauser     { // binary
2003ba8548cSNikolas Klauser       {
2013ba8548cSNikolas Klauser         int a[] = {};
2023ba8548cSNikolas Klauser         int b[] = {5, 4, 3, 2, 1};
2033ba8548cSNikolas Klauser         int c[5];
2043ba8548cSNikolas Klauser 
2053ba8548cSNikolas Klauser         auto ret = std::ranges::transform(
2063ba8548cSNikolas Klauser             In1(a), Sent1(In1(a)), In2(b), Sent2(In2(b + 5)), Out(c), [](int i, int j) { return i + j; });
2073ba8548cSNikolas Klauser 
2083ba8548cSNikolas Klauser         assert(base(ret.in1) == a);
2093ba8548cSNikolas Klauser         assert(base(ret.in2) == b);
2103ba8548cSNikolas Klauser         assert(base(ret.out) == c);
2113ba8548cSNikolas Klauser       }
2123ba8548cSNikolas Klauser 
2133ba8548cSNikolas Klauser       {
2143ba8548cSNikolas Klauser         int a[] = {};
2153ba8548cSNikolas Klauser         int b[] = {5, 4, 3, 2, 1};
2163ba8548cSNikolas Klauser         int c[5];
2173ba8548cSNikolas Klauser 
2183ba8548cSNikolas Klauser         auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a)));
2193ba8548cSNikolas Klauser         auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 5)));
2203ba8548cSNikolas Klauser 
2213ba8548cSNikolas Klauser         auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; });
2223ba8548cSNikolas Klauser 
2233ba8548cSNikolas Klauser         assert(base(ret.in1) == a);
2243ba8548cSNikolas Klauser         assert(base(ret.in2) == b);
2253ba8548cSNikolas Klauser         assert(base(ret.out) == c);
2263ba8548cSNikolas Klauser       }
2273ba8548cSNikolas Klauser     }
2283ba8548cSNikolas Klauser   }
2293ba8548cSNikolas Klauser 
2303ba8548cSNikolas Klauser   { // second range empty (binary)
2313ba8548cSNikolas Klauser     {
2323ba8548cSNikolas Klauser       int a[] = {5, 4, 3, 2, 1};
2333ba8548cSNikolas Klauser       int b[] = {};
2343ba8548cSNikolas Klauser       int c[5];
2353ba8548cSNikolas Klauser 
2363ba8548cSNikolas Klauser       auto ret = std::ranges::transform(
2373ba8548cSNikolas Klauser           In1(a), Sent1(In1(a + 5)), In2(b), Sent2(In2(b)), Out(c), [](int i, int j) { return i + j; });
2383ba8548cSNikolas Klauser 
2393ba8548cSNikolas Klauser       assert(base(ret.in1) == a);
2403ba8548cSNikolas Klauser       assert(base(ret.in2) == b);
2413ba8548cSNikolas Klauser       assert(base(ret.out) == c);
2423ba8548cSNikolas Klauser     }
2433ba8548cSNikolas Klauser 
2443ba8548cSNikolas Klauser     {
2453ba8548cSNikolas Klauser       int a[] = {5, 4, 3, 2, 1};
2463ba8548cSNikolas Klauser       int b[] = {};
2473ba8548cSNikolas Klauser       int c[5];
2483ba8548cSNikolas Klauser 
2493ba8548cSNikolas Klauser       auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 5)));
2503ba8548cSNikolas Klauser       auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b)));
2513ba8548cSNikolas Klauser 
2523ba8548cSNikolas Klauser       auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; });
2533ba8548cSNikolas Klauser 
2543ba8548cSNikolas Klauser       assert(base(ret.in1) == a);
2553ba8548cSNikolas Klauser       assert(base(ret.in2) == b);
2563ba8548cSNikolas Klauser       assert(base(ret.out) == c);
2573ba8548cSNikolas Klauser     }
2583ba8548cSNikolas Klauser   }
2593ba8548cSNikolas Klauser 
2603ba8548cSNikolas Klauser   { // both ranges empty (binary)
2613ba8548cSNikolas Klauser     {
2623ba8548cSNikolas Klauser       int a[] = {};
2633ba8548cSNikolas Klauser       int b[] = {};
2643ba8548cSNikolas Klauser       int c[5];
2653ba8548cSNikolas Klauser 
2663ba8548cSNikolas Klauser       auto ret = std::ranges::transform(
2673ba8548cSNikolas Klauser           In1(a), Sent1(In1(a)), In2(b), Sent2(In2(b)), Out(c), [](int i, int j) { return i + j; });
2683ba8548cSNikolas Klauser 
2693ba8548cSNikolas Klauser       assert(base(ret.in1) == a);
2703ba8548cSNikolas Klauser       assert(base(ret.in2) == b);
2713ba8548cSNikolas Klauser       assert(base(ret.out) == c);
2723ba8548cSNikolas Klauser     }
2733ba8548cSNikolas Klauser 
2743ba8548cSNikolas Klauser     {
2753ba8548cSNikolas Klauser       int a[] = {};
2763ba8548cSNikolas Klauser       int b[] = {};
2773ba8548cSNikolas Klauser       int c[5];
2783ba8548cSNikolas Klauser 
2793ba8548cSNikolas Klauser       auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a)));
2803ba8548cSNikolas Klauser       auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b)));
2813ba8548cSNikolas Klauser 
2823ba8548cSNikolas Klauser       auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; });
2833ba8548cSNikolas Klauser 
2843ba8548cSNikolas Klauser       assert(base(ret.in1) == a);
2853ba8548cSNikolas Klauser       assert(base(ret.in2) == b);
2863ba8548cSNikolas Klauser       assert(base(ret.out) == c);
2873ba8548cSNikolas Klauser     }
2883ba8548cSNikolas Klauser   }
2893ba8548cSNikolas Klauser 
2903ba8548cSNikolas Klauser   { // first range one element
2913ba8548cSNikolas Klauser     { // unary
2923ba8548cSNikolas Klauser       {
2933ba8548cSNikolas Klauser         int a[] = {2};
2943ba8548cSNikolas Klauser         int b[5];
2953ba8548cSNikolas Klauser         auto ret = std::ranges::transform(In1(a), Sent1(In1(a + 1)), Out(b), [](int i) { return i * 2; });
2963ba8548cSNikolas Klauser         assert(b[0] == 4);
2973ba8548cSNikolas Klauser         assert(base(ret.in) == a + 1);
2983ba8548cSNikolas Klauser         assert(base(ret.out) == b + 1);
2993ba8548cSNikolas Klauser       }
3003ba8548cSNikolas Klauser 
3013ba8548cSNikolas Klauser       {
3023ba8548cSNikolas Klauser         int a[] = {2};
3033ba8548cSNikolas Klauser         int b[5];
3043ba8548cSNikolas Klauser         auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 1)));
3053ba8548cSNikolas Klauser         auto ret = std::ranges::transform(range, Out(b), [](int i) { return i * 2; });
3063ba8548cSNikolas Klauser         assert(b[0] == 4);
3073ba8548cSNikolas Klauser         assert(base(ret.in) == a + 1);
3083ba8548cSNikolas Klauser         assert(base(ret.out) == b + 1);
3093ba8548cSNikolas Klauser       }
3103ba8548cSNikolas Klauser     }
3113ba8548cSNikolas Klauser 
3123ba8548cSNikolas Klauser     { // binary
3133ba8548cSNikolas Klauser       {
3143ba8548cSNikolas Klauser         int a[] = {2};
3153ba8548cSNikolas Klauser         int b[] = {5, 4, 3, 2, 1};
3163ba8548cSNikolas Klauser         int c[5];
3173ba8548cSNikolas Klauser 
3183ba8548cSNikolas Klauser         auto ret = std::ranges::transform(
3193ba8548cSNikolas Klauser             In1(a), Sent1(In1(a + 1)), In2(b), Sent2(In2(b + 5)), Out(c), [](int i, int j) { return i + j; });
3203ba8548cSNikolas Klauser 
3213ba8548cSNikolas Klauser         assert(c[0] == 7);
3223ba8548cSNikolas Klauser         assert(base(ret.in1) == a + 1);
3233ba8548cSNikolas Klauser         assert(base(ret.in2) == b + 1);
3243ba8548cSNikolas Klauser         assert(base(ret.out) == c + 1);
3253ba8548cSNikolas Klauser       }
3263ba8548cSNikolas Klauser 
3273ba8548cSNikolas Klauser       {
3283ba8548cSNikolas Klauser         int a[] = {2};
3293ba8548cSNikolas Klauser         int b[] = {5, 4, 3, 2, 1};
3303ba8548cSNikolas Klauser         int c[5];
3313ba8548cSNikolas Klauser 
3323ba8548cSNikolas Klauser         auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 1)));
3333ba8548cSNikolas Klauser         auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 5)));
3343ba8548cSNikolas Klauser 
3353ba8548cSNikolas Klauser         auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; });
3363ba8548cSNikolas Klauser 
3373ba8548cSNikolas Klauser         assert(c[0] == 7);
3383ba8548cSNikolas Klauser         assert(base(ret.in1) == a + 1);
3393ba8548cSNikolas Klauser         assert(base(ret.in2) == b + 1);
3403ba8548cSNikolas Klauser         assert(base(ret.out) == c + 1);
3413ba8548cSNikolas Klauser       }
3423ba8548cSNikolas Klauser     }
3433ba8548cSNikolas Klauser   }
3443ba8548cSNikolas Klauser 
3453ba8548cSNikolas Klauser   { // second range contains one element (binary)
3463ba8548cSNikolas Klauser     {
3473ba8548cSNikolas Klauser       int a[] = {5, 4, 3, 2, 1};
3483ba8548cSNikolas Klauser       int b[] = {4};
3493ba8548cSNikolas Klauser       int c[5];
3503ba8548cSNikolas Klauser 
3513ba8548cSNikolas Klauser       auto ret = std::ranges::transform(
3523ba8548cSNikolas Klauser           In1(a), Sent1(In1(a + 5)), In2(b), Sent2(In2(b + 1)), Out(c), [](int i, int j) { return i + j; });
3533ba8548cSNikolas Klauser 
3543ba8548cSNikolas Klauser       assert(c[0] == 9);
3553ba8548cSNikolas Klauser       assert(base(ret.in1) == a + 1);
3563ba8548cSNikolas Klauser       assert(base(ret.in2) == b + 1);
3573ba8548cSNikolas Klauser       assert(base(ret.out) == c + 1);
3583ba8548cSNikolas Klauser     }
3593ba8548cSNikolas Klauser 
3603ba8548cSNikolas Klauser     {
3613ba8548cSNikolas Klauser       int a[] = {5, 4, 3, 2, 1};
3623ba8548cSNikolas Klauser       int b[] = {4};
3633ba8548cSNikolas Klauser       int c[5];
3643ba8548cSNikolas Klauser 
3653ba8548cSNikolas Klauser       auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 5)));
3663ba8548cSNikolas Klauser       auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 1)));
3673ba8548cSNikolas Klauser 
3683ba8548cSNikolas Klauser       auto ret = std::ranges::transform(range1, range2, Out(c), [](int i, int j) { return i + j; });
3693ba8548cSNikolas Klauser 
3703ba8548cSNikolas Klauser       assert(c[0] == 9);
3713ba8548cSNikolas Klauser       assert(base(ret.in1) == a + 1);
3723ba8548cSNikolas Klauser       assert(base(ret.in2) == b + 1);
3733ba8548cSNikolas Klauser       assert(base(ret.out) == c + 1);
3743ba8548cSNikolas Klauser     }
3753ba8548cSNikolas Klauser   }
3763ba8548cSNikolas Klauser 
3773ba8548cSNikolas Klauser   { // check that the transform function and projection call counts are correct
3783ba8548cSNikolas Klauser     { // unary
3793ba8548cSNikolas Klauser       {
3803ba8548cSNikolas Klauser         int predCount = 0;
3813ba8548cSNikolas Klauser         int projCount = 0;
3823ba8548cSNikolas Klauser         auto pred = [&](int) { ++predCount; return 1; };
3833ba8548cSNikolas Klauser         auto proj = [&](int) { ++projCount; return 0; };
3843ba8548cSNikolas Klauser         int a[] = {1, 2, 3, 4};
3853ba8548cSNikolas Klauser         std::array<int, 4> c;
3863ba8548cSNikolas Klauser         std::ranges::transform(In1(a), Sent1(In1(a + 4)), Out(c.data()), pred, proj);
3873ba8548cSNikolas Klauser         assert(predCount == 4);
3883ba8548cSNikolas Klauser         assert(projCount == 4);
3893ba8548cSNikolas Klauser         assert((c == std::array{1, 1, 1, 1}));
3903ba8548cSNikolas Klauser       }
3913ba8548cSNikolas Klauser       {
3923ba8548cSNikolas Klauser         int predCount = 0;
3933ba8548cSNikolas Klauser         int projCount = 0;
3943ba8548cSNikolas Klauser         auto pred = [&](int) { ++predCount; return 1; };
3953ba8548cSNikolas Klauser         auto proj = [&](int) { ++projCount; return 0; };
3963ba8548cSNikolas Klauser         int a[] = {1, 2, 3, 4};
3973ba8548cSNikolas Klauser         std::array<int, 4> c;
3983ba8548cSNikolas Klauser         auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 4)));
3993ba8548cSNikolas Klauser         std::ranges::transform(range, Out(c.data()), pred, proj);
4003ba8548cSNikolas Klauser         assert(predCount == 4);
4013ba8548cSNikolas Klauser         assert(projCount == 4);
4023ba8548cSNikolas Klauser         assert((c == std::array{1, 1, 1, 1}));
4033ba8548cSNikolas Klauser       }
4043ba8548cSNikolas Klauser     }
4053ba8548cSNikolas Klauser     { // binary
4063ba8548cSNikolas Klauser       {
4073ba8548cSNikolas Klauser         int predCount = 0;
4083ba8548cSNikolas Klauser         int proj1Count = 0;
4093ba8548cSNikolas Klauser         int proj2Count = 0;
4103ba8548cSNikolas Klauser         auto pred = [&](int, int) { ++predCount; return 1; };
4113ba8548cSNikolas Klauser         auto proj1 = [&](int) { ++proj1Count; return 0; };
4123ba8548cSNikolas Klauser         auto proj2 = [&](int) { ++proj2Count; return 0; };
4133ba8548cSNikolas Klauser         int a[] = {1, 2, 3, 4};
4143ba8548cSNikolas Klauser         int b[] = {1, 2, 3, 4};
4153ba8548cSNikolas Klauser         std::array<int, 4> c;
4163ba8548cSNikolas Klauser         std::ranges::transform(In1(a), Sent1(In1(a + 4)), In2(b), Sent2(In2(b + 4)), Out(c.data()), pred, proj1, proj2);
4173ba8548cSNikolas Klauser         assert(predCount == 4);
4183ba8548cSNikolas Klauser         assert(proj1Count == 4);
4193ba8548cSNikolas Klauser         assert(proj2Count == 4);
4203ba8548cSNikolas Klauser         assert((c == std::array{1, 1, 1, 1}));
4213ba8548cSNikolas Klauser       }
4223ba8548cSNikolas Klauser       {
4233ba8548cSNikolas Klauser         int predCount = 0;
4243ba8548cSNikolas Klauser         int proj1Count = 0;
4253ba8548cSNikolas Klauser         int proj2Count = 0;
4263ba8548cSNikolas Klauser         auto pred = [&](int, int) { ++predCount; return 1; };
4273ba8548cSNikolas Klauser         auto proj1 = [&](int) { ++proj1Count; return 0; };
4283ba8548cSNikolas Klauser         auto proj2 = [&](int) { ++proj2Count; return 0; };
4293ba8548cSNikolas Klauser         int a[] = {1, 2, 3, 4};
4303ba8548cSNikolas Klauser         int b[] = {1, 2, 3, 4};
4313ba8548cSNikolas Klauser         std::array<int, 4> c;
4323ba8548cSNikolas Klauser         auto range1 = std::ranges::subrange(In1(a), Sent1(In1(a + 4)));
4333ba8548cSNikolas Klauser         auto range2 = std::ranges::subrange(In2(b), Sent2(In2(b + 4)));
4343ba8548cSNikolas Klauser         std::ranges::transform(range1, range2, Out(c.data()), pred, proj1, proj2);
4353ba8548cSNikolas Klauser         assert(predCount == 4);
4363ba8548cSNikolas Klauser         assert(proj1Count == 4);
4373ba8548cSNikolas Klauser         assert(proj2Count == 4);
4383ba8548cSNikolas Klauser         assert((c == std::array{1, 1, 1, 1}));
4393ba8548cSNikolas Klauser       }
4403ba8548cSNikolas Klauser     }
4413ba8548cSNikolas Klauser   }
4423ba8548cSNikolas Klauser 
4433ba8548cSNikolas Klauser   return true;
4443ba8548cSNikolas Klauser }
4453ba8548cSNikolas Klauser 
4463ba8548cSNikolas Klauser template <class In2, class Out, class Sent2 = In2>
test_iterator_in1()4473ba8548cSNikolas Klauser constexpr void test_iterator_in1() {
4483ba8548cSNikolas Klauser   test_iterators<cpp17_input_iterator<int*>, In2, Out, sentinel_wrapper<cpp17_input_iterator<int*>>, Sent2>();
4493ba8548cSNikolas Klauser   test_iterators<cpp20_input_iterator<int*>, In2, Out, sentinel_wrapper<cpp20_input_iterator<int*>>, Sent2>();
4503ba8548cSNikolas Klauser   test_iterators<forward_iterator<int*>, In2, Out, forward_iterator<int*>, Sent2>();
4513ba8548cSNikolas Klauser   test_iterators<bidirectional_iterator<int*>, In2, Out, bidirectional_iterator<int*>, Sent2>();
4523ba8548cSNikolas Klauser   test_iterators<random_access_iterator<int*>, In2, Out, random_access_iterator<int*>, Sent2>();
4533ba8548cSNikolas Klauser   test_iterators<contiguous_iterator<int*>, In2, Out, contiguous_iterator<int*>, Sent2>();
4543ba8548cSNikolas Klauser   test_iterators<int*, In2, Out, int*, Sent2>();
4553ba8548cSNikolas Klauser   // static_asserting here to avoid hitting the constant evaluation step limit
4563ba8548cSNikolas Klauser   static_assert(test_iterators<cpp17_input_iterator<int*>, In2, Out, sentinel_wrapper<cpp17_input_iterator<int*>>, Sent2>());
4573ba8548cSNikolas Klauser   static_assert(test_iterators<cpp20_input_iterator<int*>, In2, Out, sentinel_wrapper<cpp20_input_iterator<int*>>, Sent2>());
4583ba8548cSNikolas Klauser   static_assert(test_iterators<forward_iterator<int*>, In2, Out, forward_iterator<int*>, Sent2>());
4593ba8548cSNikolas Klauser   static_assert(test_iterators<bidirectional_iterator<int*>, In2, Out, bidirectional_iterator<int*>, Sent2>());
4603ba8548cSNikolas Klauser   static_assert(test_iterators<random_access_iterator<int*>, In2, Out, random_access_iterator<int*>, Sent2>());
4613ba8548cSNikolas Klauser   static_assert(test_iterators<contiguous_iterator<int*>, In2, Out, contiguous_iterator<int*>, Sent2>());
4623ba8548cSNikolas Klauser   static_assert(test_iterators<int*, In2, Out, int*, Sent2>());
4633ba8548cSNikolas Klauser }
4643ba8548cSNikolas Klauser 
4653ba8548cSNikolas Klauser template <class Out>
test_iterators_in1_in2()4663ba8548cSNikolas Klauser void test_iterators_in1_in2() {
4673ba8548cSNikolas Klauser   test_iterator_in1<cpp17_input_iterator<int*>, Out, sentinel_wrapper<cpp17_input_iterator<int*>>>();
4683ba8548cSNikolas Klauser   test_iterator_in1<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>();
4693ba8548cSNikolas Klauser   test_iterator_in1<forward_iterator<int*>, Out>();
4703ba8548cSNikolas Klauser   test_iterator_in1<bidirectional_iterator<int*>, Out>();
4713ba8548cSNikolas Klauser   test_iterator_in1<random_access_iterator<int*>, Out>();
4723ba8548cSNikolas Klauser   test_iterator_in1<contiguous_iterator<int*>, Out>();
4733ba8548cSNikolas Klauser   test_iterator_in1<int*, Out>();
4743ba8548cSNikolas Klauser }
4753ba8548cSNikolas Klauser 
test()4763ba8548cSNikolas Klauser constexpr bool test() {
4773ba8548cSNikolas Klauser   { // check that std::ranges::dangling is returned properly
4783ba8548cSNikolas Klauser     { // unary
4793ba8548cSNikolas Klauser       std::array<int, 5> b;
4803ba8548cSNikolas Klauser       std::same_as<std::ranges::in_out_result<std::ranges::dangling, int*>> auto ret =
4813ba8548cSNikolas Klauser           std::ranges::transform(std::array{1, 2, 3, 5, 4}, b.data(), [](int i) { return i * i; });
4823ba8548cSNikolas Klauser       assert((b == std::array{1, 4, 9, 25, 16}));
4833ba8548cSNikolas Klauser       assert(ret.out == b.data() + b.size());
4843ba8548cSNikolas Klauser     }
4853ba8548cSNikolas Klauser     // binary
4863ba8548cSNikolas Klauser     {
4873ba8548cSNikolas Klauser       int b[] = {2, 5, 4, 3, 1};
4883ba8548cSNikolas Klauser       std::array<int, 5> c;
4893ba8548cSNikolas Klauser       std::same_as<std::ranges::in_in_out_result<std::ranges::dangling, int*, int*>> auto ret =
4903ba8548cSNikolas Klauser           std::ranges::transform(std::array{1, 2, 3, 5, 4}, b, c.data(), [](int i, int j) { return i * j; });
4913ba8548cSNikolas Klauser       assert((c == std::array{2, 10, 12, 15, 4}));
4923ba8548cSNikolas Klauser       assert(ret.in2 == b + 5);
4933ba8548cSNikolas Klauser       assert(ret.out == c.data() + c.size());
4943ba8548cSNikolas Klauser     }
4953ba8548cSNikolas Klauser     {
4963ba8548cSNikolas Klauser       int a[] = {2, 5, 4, 3, 1, 4, 5, 6};
4973ba8548cSNikolas Klauser       std::array<int, 8> c;
4983ba8548cSNikolas Klauser       std::same_as<std::ranges::in_in_out_result<int*, std::ranges::dangling, int*>> auto ret =
4993ba8548cSNikolas Klauser           std::ranges::transform(a, std::array{1, 2, 3, 5, 4, 5, 6, 7}, c.data(), [](int i, int j) { return i * j; });
5003ba8548cSNikolas Klauser       assert((c == std::array{2, 10, 12, 15, 4, 20, 30, 42}));
5013ba8548cSNikolas Klauser       assert(ret.in1 == a + 8);
5023ba8548cSNikolas Klauser       assert(ret.out == c.data() + c.size());
5033ba8548cSNikolas Klauser     }
5043ba8548cSNikolas Klauser     {
5053ba8548cSNikolas Klauser       std::array<int, 3> c;
5063ba8548cSNikolas Klauser       std::same_as<std::ranges::in_in_out_result<std::ranges::dangling, std::ranges::dangling, int*>> auto ret =
5073ba8548cSNikolas Klauser           std::ranges::transform(std::array{4, 4, 4}, std::array{4, 4, 4}, c.data(), [](int i, int j) { return i * j; });
5083ba8548cSNikolas Klauser       assert((c == std::array{16, 16, 16}));
5093ba8548cSNikolas Klauser       assert(ret.out == c.data() + c.size());
5103ba8548cSNikolas Klauser     }
5113ba8548cSNikolas Klauser   }
5123ba8548cSNikolas Klauser 
5133ba8548cSNikolas Klauser   { // check that returning another type from the projection works
5143ba8548cSNikolas Klauser     { // unary
5153ba8548cSNikolas Klauser       {
5163ba8548cSNikolas Klauser         struct S { int i; int other; };
5173ba8548cSNikolas Klauser         S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} };
5183ba8548cSNikolas Klauser         std::array<int, 4> b;
5193ba8548cSNikolas Klauser         std::ranges::transform(a, a + 4, b.begin(), [](S s) { return s.i; });
5203ba8548cSNikolas Klauser         assert((b == std::array{0, 1, 3, 10}));
5213ba8548cSNikolas Klauser       }
5223ba8548cSNikolas Klauser       {
5233ba8548cSNikolas Klauser         struct S { int i; int other; };
5243ba8548cSNikolas Klauser         S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} };
5253ba8548cSNikolas Klauser         std::array<int, 4> b;
5263ba8548cSNikolas Klauser         std::ranges::transform(a, b.begin(), [](S s) { return s.i; });
5273ba8548cSNikolas Klauser         assert((b == std::array{0, 1, 3, 10}));
5283ba8548cSNikolas Klauser       }
5293ba8548cSNikolas Klauser     }
5303ba8548cSNikolas Klauser     { // binary
5313ba8548cSNikolas Klauser       {
5323ba8548cSNikolas Klauser         struct S { int i; int other; };
5333ba8548cSNikolas Klauser         S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} };
5343ba8548cSNikolas Klauser         S b[] = { S{0, 10}, S{1, 20}, S{3, 30}, S{10, 40} };
5353ba8548cSNikolas Klauser         std::array<int, 4> c;
5363ba8548cSNikolas Klauser         std::ranges::transform(a, a + 4, b, b + 4, c.begin(), [](S s1, S s2) { return s1.i + s2.other; });
5373ba8548cSNikolas Klauser         assert((c == std::array{10, 21, 33, 50}));
5383ba8548cSNikolas Klauser       }
5393ba8548cSNikolas Klauser       {
5403ba8548cSNikolas Klauser         struct S { int i; int other; };
5413ba8548cSNikolas Klauser         S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} };
5423ba8548cSNikolas Klauser         S b[] = { S{0, 10}, S{1, 20}, S{3, 30}, S{10, 40} };
5433ba8548cSNikolas Klauser         std::array<int, 4> c;
5443ba8548cSNikolas Klauser         std::ranges::transform(a, b, c.begin(), [](S s1, S s2) { return s1.i + s2.other; });
5453ba8548cSNikolas Klauser         assert((c == std::array{10, 21, 33, 50}));
5463ba8548cSNikolas Klauser       }
5473ba8548cSNikolas Klauser     }
5483ba8548cSNikolas Klauser   }
5493ba8548cSNikolas Klauser 
5503ba8548cSNikolas Klauser   { // check that std::invoke is used
5513ba8548cSNikolas Klauser     { // unary
5523ba8548cSNikolas Klauser       struct S { int i; };
5533ba8548cSNikolas Klauser       S a[] = { S{1}, S{3}, S{2} };
5543ba8548cSNikolas Klauser       std::array<int, 3> b;
5553ba8548cSNikolas Klauser       auto ret = std::ranges::transform(a, b.data(), [](int i) { return i; }, &S::i);
5563ba8548cSNikolas Klauser       assert((b == std::array{1, 3, 2}));
5573ba8548cSNikolas Klauser       assert(ret.out == b.data() + 3);
5583ba8548cSNikolas Klauser     }
5593ba8548cSNikolas Klauser     { // binary
5603ba8548cSNikolas Klauser       struct S { int i; };
5613ba8548cSNikolas Klauser       S a[] = { S{1}, S{3}, S{2} };
5623ba8548cSNikolas Klauser       S b[] = { S{2}, S{5}, S{3} };
5633ba8548cSNikolas Klauser       std::array<int, 3> c;
5643ba8548cSNikolas Klauser       auto ret = std::ranges::transform(a, b, c.data(), [](int i, int j) { return i + j + 2; }, &S::i, &S::i);
5653ba8548cSNikolas Klauser       assert((c == std::array{5, 10, 7}));
5663ba8548cSNikolas Klauser       assert(ret.out == c.data() + 3);
5673ba8548cSNikolas Klauser     }
5683ba8548cSNikolas Klauser   }
5693ba8548cSNikolas Klauser 
5703ba8548cSNikolas Klauser   return true;
5713ba8548cSNikolas Klauser }
5723ba8548cSNikolas Klauser 
main(int,char **)5733ba8548cSNikolas Klauser int main(int, char**) {
5743ba8548cSNikolas Klauser   test_iterators_in1_in2<cpp17_output_iterator<int*>>();
5753fb37709SMark de Wever   test_iterators_in1_in2<cpp20_output_iterator<int*>>();
5763ba8548cSNikolas Klauser   test_iterators_in1_in2<forward_iterator<int*>>();
5773ba8548cSNikolas Klauser   test_iterators_in1_in2<bidirectional_iterator<int*>>();
5783ba8548cSNikolas Klauser   test_iterators_in1_in2<random_access_iterator<int*>>();
5793ba8548cSNikolas Klauser   test_iterators_in1_in2<contiguous_iterator<int*>>();
5803ba8548cSNikolas Klauser   test_iterators_in1_in2<int*>();
5813ba8548cSNikolas Klauser   test();
5823ba8548cSNikolas Klauser   static_assert(test());
5833ba8548cSNikolas Klauser 
5843ba8548cSNikolas Klauser   return 0;
5853ba8548cSNikolas Klauser }
586