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 I, sentinel_for<I> S, weakly_incrementable O,
14 // copy_constructible F, class Proj = identity>
15 // requires indirectly_writable<O, indirect_result_t<F&, projected<I, Proj>>>
16 // constexpr ranges::unary_transform_result<I, O>
17 // ranges::transform(I first1, S last1, O result, F op, Proj proj = {});
18 // template<input_range R, weakly_incrementable O, copy_constructible F,
19 // class Proj = identity>
20 // requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R>, Proj>>>
21 // constexpr ranges::unary_transform_result<borrowed_iterator_t<R>, O>
22 // ranges::transform(R&& r, O result, F op, Proj proj = {});
30 #include "test_iterators.h"
31 #include "almost_satisfies_types.h"
33 template <class Range
>
34 concept HasTranformR
= requires(Range r
, int* out
) { std::ranges::transform(r
, out
, std::identity
{}); };
36 static_assert(HasTranformR
<std::array
<int, 1>>);
37 static_assert(!HasTranformR
<int>);
38 static_assert(!HasTranformR
<InputRangeNotDerivedFrom
>);
39 static_assert(!HasTranformR
<InputRangeNotIndirectlyReadable
>);
40 static_assert(!HasTranformR
<InputRangeNotInputOrOutputIterator
>);
41 static_assert(!HasTranformR
<InputRangeNotSentinelSemiregular
>);
42 static_assert(!HasTranformR
<InputRangeNotSentinelEqualityComparableWith
>);
44 template <class It
, class Sent
= It
>
45 concept HasTransformIt
=
46 requires(It it
, Sent sent
, int* out
) { std::ranges::transform(it
, sent
, out
, std::identity
{}); };
48 static_assert(HasTransformIt
<int*>);
49 static_assert(!HasTransformIt
<InputIteratorNotDerivedFrom
>);
50 static_assert(!HasTransformIt
<InputIteratorNotIndirectlyReadable
>);
51 static_assert(!HasTransformIt
<InputIteratorNotInputOrOutputIterator
>);
52 static_assert(!HasTransformIt
<cpp20_input_iterator
<int*>, SentinelForNotSemiregular
>);
53 static_assert(!HasTransformIt
<cpp20_input_iterator
<int*>, InputRangeNotSentinelEqualityComparableWith
>);
56 concept HasTransformOut
= requires(int* it
, int* sent
, It out
, std::array
<int, 2> range
) {
57 std::ranges::transform(it
, sent
, out
, std::identity
{});
58 std::ranges::transform(range
, out
, std::identity
{});
60 static_assert(HasTransformOut
<int*>);
61 static_assert(!HasTransformOut
<WeaklyIncrementableNotMovable
>);
63 // check indirectly_readable
64 static_assert(HasTransformOut
<char*>);
65 static_assert(!HasTransformOut
<int**>);
67 struct MoveOnlyFunctor
{
68 MoveOnlyFunctor(const MoveOnlyFunctor
&) = delete;
69 MoveOnlyFunctor(MoveOnlyFunctor
&&) = default;
74 concept HasTransformFuncUnary
= requires(int* it
, int* sent
, int* out
, std::array
<int, 2> range
, Func func
) {
75 std::ranges::transform(it
, sent
, out
, func
);
76 std::ranges::transform(range
, out
, func
);
78 static_assert(HasTransformFuncUnary
<std::identity
>);
79 static_assert(!HasTransformFuncUnary
<MoveOnlyFunctor
>);
81 static_assert(std::is_same_v
<std::ranges::unary_transform_result
<int, long>, std::ranges::in_out_result
<int, long>>);
84 template <class In1
, class Out
, class Sent1
>
85 constexpr bool test_iterators() {
88 int a
[] = {1, 2, 3, 4, 5};
90 std::same_as
<std::ranges::in_out_result
<In1
, Out
>> decltype(auto) ret
=
91 std::ranges::transform(In1(a
), Sent1(In1(a
+ 5)), Out(b
), [](int i
) { return i
* 2; });
92 assert((std::to_array(b
) == std::array
{2, 4, 6, 8, 10}));
93 assert(base(ret
.in
) == a
+ 5);
94 assert(base(ret
.out
) == b
+ 5);
98 int a
[] = {1, 2, 3, 4, 5};
100 auto range
= std::ranges::subrange(In1(a
), Sent1(In1(a
+ 5)));
101 std::same_as
<std::ranges::in_out_result
<In1
, Out
>> decltype(auto) ret
=
102 std::ranges::transform(range
, Out(b
), [](int i
) { return i
* 2; });
103 assert((std::to_array(b
) == std::array
{2, 4, 6, 8, 10}));
104 assert(base(ret
.in
) == a
+ 5);
105 assert(base(ret
.out
) == b
+ 5);
109 { // first range empty
113 auto ret
= std::ranges::transform(In1(a
), Sent1(In1(a
)), Out(b
), [](int i
) { return i
* 2; });
114 assert(base(ret
.in
) == a
);
115 assert(base(ret
.out
) == b
);
121 auto range
= std::ranges::subrange(In1(a
), Sent1(In1(a
)));
122 auto ret
= std::ranges::transform(range
, Out(b
), [](int i
) { return i
* 2; });
123 assert(base(ret
.in
) == a
);
124 assert(base(ret
.out
) == b
);
128 { // one element range
132 auto ret
= std::ranges::transform(In1(a
), Sent1(In1(a
+ 1)), Out(b
), [](int i
) { return i
* 2; });
134 assert(base(ret
.in
) == a
+ 1);
135 assert(base(ret
.out
) == b
+ 1);
141 auto range
= std::ranges::subrange(In1(a
), Sent1(In1(a
+ 1)));
142 auto ret
= std::ranges::transform(range
, Out(b
), [](int i
) { return i
* 2; });
144 assert(base(ret
.in
) == a
+ 1);
145 assert(base(ret
.out
) == b
+ 1);
149 { // check that the transform function and projection call counts are correct
153 auto pred
= [&](int) { ++predCount
; return 1; };
154 auto proj
= [&](int) { ++projCount
; return 0; };
155 int a
[] = {1, 2, 3, 4};
156 std::array
<int, 4> c
;
157 std::ranges::transform(In1(a
), Sent1(In1(a
+ 4)), Out(c
.data()), pred
, proj
);
158 assert(predCount
== 4);
159 assert(projCount
== 4);
160 assert((c
== std::array
{1, 1, 1, 1}));
165 auto pred
= [&](int) { ++predCount
; return 1; };
166 auto proj
= [&](int) { ++projCount
; return 0; };
167 int a
[] = {1, 2, 3, 4};
168 std::array
<int, 4> c
;
169 auto range
= std::ranges::subrange(In1(a
), Sent1(In1(a
+ 4)));
170 std::ranges::transform(range
, Out(c
.data()), pred
, proj
);
171 assert(predCount
== 4);
172 assert(projCount
== 4);
173 assert((c
== std::array
{1, 1, 1, 1}));
181 constexpr void test_iterator_in1() {
182 test_iterators
<cpp17_input_iterator
<int*>, Out
, sentinel_wrapper
<cpp17_input_iterator
<int*>>>();
183 test_iterators
<cpp20_input_iterator
<int*>, Out
, sentinel_wrapper
<cpp20_input_iterator
<int*>>>();
184 test_iterators
<forward_iterator
<int*>, Out
, forward_iterator
<int*>>();
185 test_iterators
<bidirectional_iterator
<int*>, Out
, bidirectional_iterator
<int*>>();
186 test_iterators
<random_access_iterator
<int*>, Out
, random_access_iterator
<int*>>();
187 test_iterators
<contiguous_iterator
<int*>, Out
, contiguous_iterator
<int*>>();
188 test_iterators
<int*, Out
, int*>();
189 // static_asserting here to avoid hitting the constant evaluation step limit
190 static_assert(test_iterators
<cpp17_input_iterator
<int*>, Out
, sentinel_wrapper
<cpp17_input_iterator
<int*>>>());
191 static_assert(test_iterators
<cpp20_input_iterator
<int*>, Out
, sentinel_wrapper
<cpp20_input_iterator
<int*>>>());
192 static_assert(test_iterators
<forward_iterator
<int*>, Out
, forward_iterator
<int*>>());
193 static_assert(test_iterators
<bidirectional_iterator
<int*>, Out
, bidirectional_iterator
<int*>>());
194 static_assert(test_iterators
<random_access_iterator
<int*>, Out
, random_access_iterator
<int*>>());
195 static_assert(test_iterators
<contiguous_iterator
<int*>, Out
, contiguous_iterator
<int*>>());
196 static_assert(test_iterators
<int*, Out
, int*>());
199 constexpr bool test() {
200 { // check that std::ranges::dangling is returned properly
201 std::array
<int, 5> b
;
202 std::same_as
<std::ranges::in_out_result
<std::ranges::dangling
, int*>> auto ret
=
203 std::ranges::transform(std::array
{1, 2, 3, 5, 4}, b
.data(), [](int i
) { return i
* i
; });
204 assert((b
== std::array
{1, 4, 9, 25, 16}));
205 assert(ret
.out
== b
.data() + b
.size());
208 { // check that returning another type from the projection works
210 struct S
{ int i
; int other
; };
211 S a
[] = { S
{0, 0}, S
{1, 0}, S
{3, 0}, S
{10, 0} };
212 std::array
<int, 4> b
;
213 std::ranges::transform(a
, a
+ 4, b
.begin(), [](S s
) { return s
.i
; });
214 assert((b
== std::array
{0, 1, 3, 10}));
217 struct S
{ int i
; int other
; };
218 S a
[] = { S
{0, 0}, S
{1, 0}, S
{3, 0}, S
{10, 0} };
219 std::array
<int, 4> b
;
220 std::ranges::transform(a
, b
.begin(), [](S s
) { return s
.i
; });
221 assert((b
== std::array
{0, 1, 3, 10}));
225 { // check that std::invoke is used
227 S a
[] = { S
{1}, S
{3}, S
{2} };
228 std::array
<int, 3> b
;
229 auto ret
= std::ranges::transform(a
, b
.data(), [](int i
) { return i
; }, &S::i
);
230 assert((b
== std::array
{1, 3, 2}));
231 assert(ret
.out
== b
.data() + 3);
237 int main(int, char**) {
238 test_iterator_in1
<cpp17_output_iterator
<int*>>();
239 test_iterator_in1
<cpp20_output_iterator
<int*>>();
240 test_iterator_in1
<forward_iterator
<int*>>();
241 test_iterator_in1
<bidirectional_iterator
<int*>>();
242 test_iterator_in1
<random_access_iterator
<int*>>();
243 test_iterator_in1
<contiguous_iterator
<int*>>();
244 test_iterator_in1
<int*>();
246 static_assert(test());