1 //===----------------------------------------------------------------------===//
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
7 //===----------------------------------------------------------------------===//
9 // UNSUPPORTED: c++03, c++11, c++14, c++17
13 // template<input_iterator I1, sentinel_for<I1> S1, input_iterator I2, sentinel_for<I2> S2,
14 // weakly_incrementable O, copy_constructible F, class Proj1 = identity,
15 // class Proj2 = identity>
16 // requires indirectly_writable<O, indirect_result_t<F&, projected<I1, Proj1>,
17 // projected<I2, Proj2>>>
18 // constexpr ranges::binary_transform_result<I1, I2, O>
19 // ranges::transform(I1 first1, S1 last1, I2 first2, S2 last2, O result,
20 // F binary_op, Proj1 proj1 = {}, Proj2 proj2 = {});
22 // The range overloads are tested in ranges.tranform.binary.range.pass.cpp.
30 #include "test_iterators.h"
31 #include "almost_satisfies_types.h"
34 int operator()(int, int);
37 template <class It
, class Sent
= It
>
38 concept HasTransformIt
=
39 requires(It it
, Sent sent
, int* out
) { std::ranges::transform(it
, sent
, it
, sent
, out
, BinaryFunc
{}); };
40 static_assert(HasTransformIt
<int*>);
41 static_assert(!HasTransformIt
<InputIteratorNotDerivedFrom
>);
42 static_assert(!HasTransformIt
<InputIteratorNotIndirectlyReadable
>);
43 static_assert(!HasTransformIt
<InputIteratorNotInputOrOutputIterator
>);
44 static_assert(!HasTransformIt
<cpp20_input_iterator
<int*>, SentinelForNotSemiregular
>);
45 static_assert(!HasTransformIt
<cpp20_input_iterator
<int*>, InputRangeNotSentinelEqualityComparableWith
>);
48 concept HasTransformOut
= requires(int* it
, int* sent
, It out
, std::array
<int, 2> range
) {
49 std::ranges::transform(it
, sent
, it
, sent
, out
, BinaryFunc
{});
51 static_assert(HasTransformOut
<int*>);
52 static_assert(!HasTransformOut
<WeaklyIncrementableNotMovable
>);
54 // check indirectly_readable
55 static_assert(HasTransformOut
<char*>);
56 static_assert(!HasTransformOut
<int**>);
58 struct MoveOnlyFunctor
{
59 MoveOnlyFunctor(const MoveOnlyFunctor
&) = delete;
60 MoveOnlyFunctor(MoveOnlyFunctor
&&) = default;
61 int operator()(int, int);
65 concept HasTransformFuncBinary
= requires(int* it
, int* sent
, int* out
, std::array
<int, 2> range
, Func func
) {
66 std::ranges::transform(it
, sent
, it
, sent
, out
, func
);
68 static_assert(HasTransformFuncBinary
<BinaryFunc
>);
69 static_assert(!HasTransformFuncBinary
<MoveOnlyFunctor
>);
71 static_assert(std::is_same_v
<std::ranges::binary_transform_result
<int, long, char>,
72 std::ranges::in_in_out_result
<int, long, char>>);
75 template <class In1
, class In2
, class Out
, class Sent1
, class Sent2
>
76 constexpr bool test_iterators() {
78 int a
[] = {1, 2, 3, 4, 5};
79 int b
[] = {5, 4, 3, 2, 1};
82 std::same_as
<std::ranges::in_in_out_result
<In1
, In2
, Out
>> decltype(auto) ret
= std::ranges::transform(
83 In1(a
), Sent1(In1(a
+ 5)), In2(b
), Sent2(In2(b
+ 5)), Out(c
), [](int i
, int j
) { return i
+ j
; });
85 assert((std::to_array(c
) == std::array
{6, 6, 6, 6, 6}));
86 assert(base(ret
.in1
) == a
+ 5);
87 assert(base(ret
.in2
) == b
+ 5);
88 assert(base(ret
.out
) == c
+ 5);
91 { // first range empty
93 int b
[] = {5, 4, 3, 2, 1};
96 auto ret
= std::ranges::transform(
97 In1(a
), Sent1(In1(a
)), In2(b
), Sent2(In2(b
+ 5)), Out(c
), [](int i
, int j
) { return i
+ j
; });
99 assert(base(ret
.in1
) == a
);
100 assert(base(ret
.in2
) == b
);
101 assert(base(ret
.out
) == c
);
104 { // second range empty
105 int a
[] = {5, 4, 3, 2, 1};
109 auto ret
= std::ranges::transform(
110 In1(a
), Sent1(In1(a
+ 5)), In2(b
), Sent2(In2(b
)), Out(c
), [](int i
, int j
) { return i
+ j
; });
112 assert(base(ret
.in1
) == a
);
113 assert(base(ret
.in2
) == b
);
114 assert(base(ret
.out
) == c
);
117 { // both ranges empty
122 auto ret
= std::ranges::transform(
123 In1(a
), Sent1(In1(a
)), In2(b
), Sent2(In2(b
)), Out(c
), [](int i
, int j
) { return i
+ j
; });
125 assert(base(ret
.in1
) == a
);
126 assert(base(ret
.in2
) == b
);
127 assert(base(ret
.out
) == c
);
130 { // first range one element
132 int b
[] = {5, 4, 3, 2, 1};
135 auto ret
= std::ranges::transform(
136 In1(a
), Sent1(In1(a
+ 1)), In2(b
), Sent2(In2(b
+ 5)), Out(c
), [](int i
, int j
) { return i
+ j
; });
139 assert(base(ret
.in1
) == a
+ 1);
140 assert(base(ret
.in2
) == b
+ 1);
141 assert(base(ret
.out
) == c
+ 1);
144 { // second range contains one element
145 int a
[] = {5, 4, 3, 2, 1};
149 auto ret
= std::ranges::transform(
150 In1(a
), Sent1(In1(a
+ 5)), In2(b
), Sent2(In2(b
+ 1)), Out(c
), [](int i
, int j
) { return i
+ j
; });
153 assert(base(ret
.in1
) == a
+ 1);
154 assert(base(ret
.in2
) == b
+ 1);
155 assert(base(ret
.out
) == c
+ 1);
158 { // check that the transform function and projection call counts are correct
162 auto pred
= [&](int, int) { ++predCount
; return 1; };
163 auto proj1
= [&](int) { ++proj1Count
; return 0; };
164 auto proj2
= [&](int) { ++proj2Count
; return 0; };
165 int a
[] = {1, 2, 3, 4};
166 int b
[] = {1, 2, 3, 4};
167 std::array
<int, 4> c
;
168 std::ranges::transform(In1(a
), Sent1(In1(a
+ 4)), In2(b
), Sent2(In2(b
+ 4)), Out(c
.data()), pred
, proj1
, proj2
);
169 assert(predCount
== 4);
170 assert(proj1Count
== 4);
171 assert(proj2Count
== 4);
172 assert((c
== std::array
{1, 1, 1, 1}));
179 template <class In2
, class Out
, class Sent2
= In2
>
180 constexpr void test_iterator_in1() {
181 test_iterators
<cpp17_input_iterator
<int*>, In2
, Out
, sentinel_wrapper
<cpp17_input_iterator
<int*>>, Sent2
>();
182 test_iterators
<cpp20_input_iterator
<int*>, In2
, Out
, sentinel_wrapper
<cpp20_input_iterator
<int*>>, Sent2
>();
183 test_iterators
<forward_iterator
<int*>, In2
, Out
, forward_iterator
<int*>, Sent2
>();
184 test_iterators
<bidirectional_iterator
<int*>, In2
, Out
, bidirectional_iterator
<int*>, Sent2
>();
185 test_iterators
<random_access_iterator
<int*>, In2
, Out
, random_access_iterator
<int*>, Sent2
>();
186 test_iterators
<contiguous_iterator
<int*>, In2
, Out
, contiguous_iterator
<int*>, Sent2
>();
187 test_iterators
<int*, In2
, Out
, int*, Sent2
>();
191 constexpr void test_iterators_in1_in2() {
192 test_iterator_in1
<cpp17_input_iterator
<int*>, Out
, sentinel_wrapper
<cpp17_input_iterator
<int*>>>();
193 test_iterator_in1
<cpp20_input_iterator
<int*>, Out
, sentinel_wrapper
<cpp20_input_iterator
<int*>>>();
194 test_iterator_in1
<forward_iterator
<int*>, Out
>();
195 test_iterator_in1
<bidirectional_iterator
<int*>, Out
>();
196 test_iterator_in1
<random_access_iterator
<int*>, Out
>();
197 test_iterator_in1
<contiguous_iterator
<int*>, Out
>();
198 test_iterator_in1
<int*, Out
>();
201 constexpr bool test() {
202 test_iterators_in1_in2
<cpp17_output_iterator
<int*>>();
203 test_iterators_in1_in2
<cpp20_output_iterator
<int*>>();
204 test_iterators_in1_in2
<forward_iterator
<int*>>();
205 test_iterators_in1_in2
<bidirectional_iterator
<int*>>();
206 test_iterators_in1_in2
<random_access_iterator
<int*>>();
207 test_iterators_in1_in2
<contiguous_iterator
<int*>>();
208 test_iterators_in1_in2
<int*>();
210 { // check that returning another type from the projection works
211 struct S
{ int i
; int other
; };
212 S a
[] = { S
{0, 0}, S
{1, 0}, S
{3, 0}, S
{10, 0} };
213 S b
[] = { S
{0, 10}, S
{1, 20}, S
{3, 30}, S
{10, 40} };
214 std::array
<int, 4> c
;
215 std::ranges::transform(a
, a
+ 4, b
, b
+ 4, c
.begin(), [](S s1
, S s2
) { return s1
.i
+ s2
.other
; });
216 assert((c
== std::array
{10, 21, 33, 50}));
222 int main(int, char**) {
224 static_assert(test());