1a3315606SNikolas Klauser //===----------------------------------------------------------------------===//
2a3315606SNikolas Klauser //
3a3315606SNikolas Klauser // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4a3315606SNikolas Klauser // See https://llvm.org/LICENSE.txt for license information.
5a3315606SNikolas Klauser // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6a3315606SNikolas Klauser //
7a3315606SNikolas Klauser //===----------------------------------------------------------------------===//
8a3315606SNikolas Klauser 
9a3315606SNikolas Klauser // UNSUPPORTED: c++03, c++11, c++14, c++17
10a3315606SNikolas Klauser 
11a3315606SNikolas Klauser // <algorithm>
12a3315606SNikolas Klauser 
13a3315606SNikolas Klauser // template<input_iterator I, sentinel_for<I> S, weakly_incrementable O,
14a3315606SNikolas Klauser //          copy_constructible F, class Proj = identity>
15a3315606SNikolas Klauser //   requires indirectly_writable<O, indirect_result_t<F&, projected<I, Proj>>>
16a3315606SNikolas Klauser //   constexpr ranges::unary_transform_result<I, O>
17a3315606SNikolas Klauser //     ranges::transform(I first1, S last1, O result, F op, Proj proj = {});
18a3315606SNikolas Klauser // template<input_range R, weakly_incrementable O, copy_constructible F,
19a3315606SNikolas Klauser //          class Proj = identity>
20a3315606SNikolas Klauser //   requires indirectly_writable<O, indirect_result_t<F&, projected<iterator_t<R>, Proj>>>
21a3315606SNikolas Klauser //   constexpr ranges::unary_transform_result<borrowed_iterator_t<R>, O>
22a3315606SNikolas Klauser //     ranges::transform(R&& r, O result, F op, Proj proj = {});
23a3315606SNikolas Klauser 
24a3315606SNikolas Klauser #include <algorithm>
25a3315606SNikolas Klauser #include <array>
26a3315606SNikolas Klauser #include <cassert>
27a3315606SNikolas Klauser #include <functional>
28a3315606SNikolas Klauser #include <ranges>
29a3315606SNikolas Klauser 
30a3315606SNikolas Klauser #include "test_iterators.h"
31a3315606SNikolas Klauser #include "almost_satisfies_types.h"
32a3315606SNikolas Klauser 
33a3315606SNikolas Klauser template <class Range>
34f5832babSStephan T. Lavavej concept HasTransformR = requires(Range r, int* out) { std::ranges::transform(r, out, std::identity{}); };
35a3315606SNikolas Klauser 
36f5832babSStephan T. Lavavej static_assert(HasTransformR<std::array<int, 1>>);
37f5832babSStephan T. Lavavej static_assert(!HasTransformR<int>);
38f5832babSStephan T. Lavavej static_assert(!HasTransformR<InputRangeNotDerivedFrom>);
39f5832babSStephan T. Lavavej static_assert(!HasTransformR<InputRangeNotIndirectlyReadable>);
40f5832babSStephan T. Lavavej static_assert(!HasTransformR<InputRangeNotInputOrOutputIterator>);
41f5832babSStephan T. Lavavej static_assert(!HasTransformR<InputRangeNotSentinelSemiregular>);
42f5832babSStephan T. Lavavej static_assert(!HasTransformR<InputRangeNotSentinelEqualityComparableWith>);
43a3315606SNikolas Klauser 
44a3315606SNikolas Klauser template <class It, class Sent = It>
45a3315606SNikolas Klauser concept HasTransformIt =
46a3315606SNikolas Klauser     requires(It it, Sent sent, int* out) { std::ranges::transform(it, sent, out, std::identity{}); };
47a3315606SNikolas Klauser 
48a3315606SNikolas Klauser static_assert(HasTransformIt<int*>);
49a3315606SNikolas Klauser static_assert(!HasTransformIt<InputIteratorNotDerivedFrom>);
50a3315606SNikolas Klauser static_assert(!HasTransformIt<InputIteratorNotIndirectlyReadable>);
51a3315606SNikolas Klauser static_assert(!HasTransformIt<InputIteratorNotInputOrOutputIterator>);
52a3315606SNikolas Klauser static_assert(!HasTransformIt<cpp20_input_iterator<int*>, SentinelForNotSemiregular>);
53a3315606SNikolas Klauser static_assert(!HasTransformIt<cpp20_input_iterator<int*>, InputRangeNotSentinelEqualityComparableWith>);
54a3315606SNikolas Klauser 
55a3315606SNikolas Klauser template <class It>
56a3315606SNikolas Klauser concept HasTransformOut = requires(int* it, int* sent, It out, std::array<int, 2> range) {
57a3315606SNikolas Klauser   std::ranges::transform(it, sent, out, std::identity{});
58a3315606SNikolas Klauser   std::ranges::transform(range, out, std::identity{});
59a3315606SNikolas Klauser };
60a3315606SNikolas Klauser static_assert(HasTransformOut<int*>);
61a3315606SNikolas Klauser static_assert(!HasTransformOut<WeaklyIncrementableNotMovable>);
62a3315606SNikolas Klauser 
63a3315606SNikolas Klauser // check indirectly_readable
64a3315606SNikolas Klauser static_assert(HasTransformOut<char*>);
65a3315606SNikolas Klauser static_assert(!HasTransformOut<int**>);
66a3315606SNikolas Klauser 
67a3315606SNikolas Klauser struct MoveOnlyFunctor {
68a3315606SNikolas Klauser   MoveOnlyFunctor(const MoveOnlyFunctor&) = delete;
69a3315606SNikolas Klauser   MoveOnlyFunctor(MoveOnlyFunctor&&)      = default;
70a3315606SNikolas Klauser   int operator()(int);
71a3315606SNikolas Klauser };
72a3315606SNikolas Klauser 
73a3315606SNikolas Klauser template <class Func>
74a3315606SNikolas Klauser concept HasTransformFuncUnary = requires(int* it, int* sent, int* out, std::array<int, 2> range, Func func) {
75a3315606SNikolas Klauser   std::ranges::transform(it, sent, out, func);
76a3315606SNikolas Klauser   std::ranges::transform(range, out, func);
77a3315606SNikolas Klauser };
78a3315606SNikolas Klauser static_assert(HasTransformFuncUnary<std::identity>);
79a3315606SNikolas Klauser static_assert(!HasTransformFuncUnary<MoveOnlyFunctor>);
80a3315606SNikolas Klauser 
81a3315606SNikolas Klauser static_assert(std::is_same_v<std::ranges::unary_transform_result<int, long>, std::ranges::in_out_result<int, long>>);
82a3315606SNikolas Klauser 
83a3315606SNikolas Klauser // clang-format off
84a3315606SNikolas Klauser template <class In1, class Out, class Sent1>
test_iterators()85a3315606SNikolas Klauser constexpr bool test_iterators() {
86a3315606SNikolas Klauser   { // simple
87a3315606SNikolas Klauser     {
88a3315606SNikolas Klauser       int a[] = {1, 2, 3, 4, 5};
89a3315606SNikolas Klauser       int b[5];
90a3315606SNikolas Klauser       std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret =
91a3315606SNikolas Klauser         std::ranges::transform(In1(a), Sent1(In1(a + 5)), Out(b), [](int i) { return i * 2; });
92a3315606SNikolas Klauser       assert((std::to_array(b) == std::array{2, 4, 6, 8, 10}));
93a3315606SNikolas Klauser       assert(base(ret.in) == a + 5);
94a3315606SNikolas Klauser       assert(base(ret.out) == b + 5);
95a3315606SNikolas Klauser     }
96a3315606SNikolas Klauser 
97a3315606SNikolas Klauser     {
98a3315606SNikolas Klauser       int a[] = {1, 2, 3, 4, 5};
99a3315606SNikolas Klauser       int b[5];
100a3315606SNikolas Klauser       auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 5)));
101a3315606SNikolas Klauser       std::same_as<std::ranges::in_out_result<In1, Out>> decltype(auto) ret =
102a3315606SNikolas Klauser         std::ranges::transform(range, Out(b), [](int i) { return i * 2; });
103a3315606SNikolas Klauser       assert((std::to_array(b) == std::array{2, 4, 6, 8, 10}));
104a3315606SNikolas Klauser       assert(base(ret.in) == a + 5);
105a3315606SNikolas Klauser       assert(base(ret.out) == b + 5);
106a3315606SNikolas Klauser     }
107a3315606SNikolas Klauser   }
108a3315606SNikolas Klauser 
109a3315606SNikolas Klauser   { // first range empty
110a3315606SNikolas Klauser     {
111*c000f754SStephan T. Lavavej       std::array<int, 0> a = {};
112a3315606SNikolas Klauser       int b[5];
113*c000f754SStephan T. Lavavej       auto ret = std::ranges::transform(In1(a.data()), Sent1(In1(a.data())), Out(b), [](int i) { return i * 2; });
114*c000f754SStephan T. Lavavej       assert(base(ret.in) == a.data());
115a3315606SNikolas Klauser       assert(base(ret.out) == b);
116a3315606SNikolas Klauser     }
117a3315606SNikolas Klauser 
118a3315606SNikolas Klauser     {
119*c000f754SStephan T. Lavavej       std::array<int, 0> a = {};
120a3315606SNikolas Klauser       int b[5];
121*c000f754SStephan T. Lavavej       auto range = std::ranges::subrange(In1(a.data()), Sent1(In1(a.data())));
122a3315606SNikolas Klauser       auto ret = std::ranges::transform(range, Out(b), [](int i) { return i * 2; });
123*c000f754SStephan T. Lavavej       assert(base(ret.in) == a.data());
124a3315606SNikolas Klauser       assert(base(ret.out) == b);
125a3315606SNikolas Klauser     }
126a3315606SNikolas Klauser   }
127a3315606SNikolas Klauser 
128a3315606SNikolas Klauser   { // one element range
129a3315606SNikolas Klauser     {
130a3315606SNikolas Klauser       int a[] = {2};
131a3315606SNikolas Klauser       int b[5];
132a3315606SNikolas Klauser       auto ret = std::ranges::transform(In1(a), Sent1(In1(a + 1)), Out(b), [](int i) { return i * 2; });
133a3315606SNikolas Klauser       assert(b[0] == 4);
134a3315606SNikolas Klauser       assert(base(ret.in) == a + 1);
135a3315606SNikolas Klauser       assert(base(ret.out) == b + 1);
136a3315606SNikolas Klauser     }
137a3315606SNikolas Klauser 
138a3315606SNikolas Klauser     {
139a3315606SNikolas Klauser       int a[] = {2};
140a3315606SNikolas Klauser       int b[5];
141a3315606SNikolas Klauser       auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 1)));
142a3315606SNikolas Klauser       auto ret = std::ranges::transform(range, Out(b), [](int i) { return i * 2; });
143a3315606SNikolas Klauser       assert(b[0] == 4);
144a3315606SNikolas Klauser       assert(base(ret.in) == a + 1);
145a3315606SNikolas Klauser       assert(base(ret.out) == b + 1);
146a3315606SNikolas Klauser     }
147a3315606SNikolas Klauser   }
148a3315606SNikolas Klauser 
149a3315606SNikolas Klauser   { // check that the transform function and projection call counts are correct
150a3315606SNikolas Klauser     {
151a3315606SNikolas Klauser       int predCount = 0;
152a3315606SNikolas Klauser       int projCount = 0;
153a3315606SNikolas Klauser       auto pred = [&](int) { ++predCount; return 1; };
154a3315606SNikolas Klauser       auto proj = [&](int) { ++projCount; return 0; };
155a3315606SNikolas Klauser       int a[] = {1, 2, 3, 4};
156a3315606SNikolas Klauser       std::array<int, 4> c;
157a3315606SNikolas Klauser       std::ranges::transform(In1(a), Sent1(In1(a + 4)), Out(c.data()), pred, proj);
158a3315606SNikolas Klauser       assert(predCount == 4);
159a3315606SNikolas Klauser       assert(projCount == 4);
160a3315606SNikolas Klauser       assert((c == std::array{1, 1, 1, 1}));
161a3315606SNikolas Klauser     }
162a3315606SNikolas Klauser     {
163a3315606SNikolas Klauser       int predCount = 0;
164a3315606SNikolas Klauser       int projCount = 0;
165a3315606SNikolas Klauser       auto pred = [&](int) { ++predCount; return 1; };
166a3315606SNikolas Klauser       auto proj = [&](int) { ++projCount; return 0; };
167a3315606SNikolas Klauser       int a[] = {1, 2, 3, 4};
168a3315606SNikolas Klauser       std::array<int, 4> c;
169a3315606SNikolas Klauser       auto range = std::ranges::subrange(In1(a), Sent1(In1(a + 4)));
170a3315606SNikolas Klauser       std::ranges::transform(range, Out(c.data()), pred, proj);
171a3315606SNikolas Klauser       assert(predCount == 4);
172a3315606SNikolas Klauser       assert(projCount == 4);
173a3315606SNikolas Klauser       assert((c == std::array{1, 1, 1, 1}));
174a3315606SNikolas Klauser     }
175a3315606SNikolas Klauser   }
176a3315606SNikolas Klauser   return true;
177a3315606SNikolas Klauser }
178a3315606SNikolas Klauser // clang-format on
179a3315606SNikolas Klauser 
180a3315606SNikolas Klauser template <class Out>
test_iterator_in1()181a3315606SNikolas Klauser constexpr void test_iterator_in1() {
182a3315606SNikolas Klauser   test_iterators<cpp17_input_iterator<int*>, Out, sentinel_wrapper<cpp17_input_iterator<int*>>>();
183a3315606SNikolas Klauser   test_iterators<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>();
184a3315606SNikolas Klauser   test_iterators<forward_iterator<int*>, Out, forward_iterator<int*>>();
185a3315606SNikolas Klauser   test_iterators<bidirectional_iterator<int*>, Out, bidirectional_iterator<int*>>();
186a3315606SNikolas Klauser   test_iterators<random_access_iterator<int*>, Out, random_access_iterator<int*>>();
187a3315606SNikolas Klauser   test_iterators<contiguous_iterator<int*>, Out, contiguous_iterator<int*>>();
188a3315606SNikolas Klauser   test_iterators<int*, Out, int*>();
189a3315606SNikolas Klauser   // static_asserting here to avoid hitting the constant evaluation step limit
190a3315606SNikolas Klauser   static_assert(test_iterators<cpp17_input_iterator<int*>, Out, sentinel_wrapper<cpp17_input_iterator<int*>>>());
191a3315606SNikolas Klauser   static_assert(test_iterators<cpp20_input_iterator<int*>, Out, sentinel_wrapper<cpp20_input_iterator<int*>>>());
192a3315606SNikolas Klauser   static_assert(test_iterators<forward_iterator<int*>, Out, forward_iterator<int*>>());
193a3315606SNikolas Klauser   static_assert(test_iterators<bidirectional_iterator<int*>, Out, bidirectional_iterator<int*>>());
194a3315606SNikolas Klauser   static_assert(test_iterators<random_access_iterator<int*>, Out, random_access_iterator<int*>>());
195a3315606SNikolas Klauser   static_assert(test_iterators<contiguous_iterator<int*>, Out, contiguous_iterator<int*>>());
196a3315606SNikolas Klauser   static_assert(test_iterators<int*, Out, int*>());
197a3315606SNikolas Klauser }
198a3315606SNikolas Klauser 
test()199a3315606SNikolas Klauser constexpr bool test() {
200a3315606SNikolas Klauser   { // check that std::ranges::dangling is returned properly
201a3315606SNikolas Klauser     std::array<int, 5> b;
202a3315606SNikolas Klauser     std::same_as<std::ranges::in_out_result<std::ranges::dangling, int*>> auto ret =
203a3315606SNikolas Klauser         std::ranges::transform(std::array{1, 2, 3, 5, 4}, b.data(), [](int i) { return i * i; });
204a3315606SNikolas Klauser     assert((b == std::array{1, 4, 9, 25, 16}));
205a3315606SNikolas Klauser     assert(ret.out == b.data() + b.size());
206a3315606SNikolas Klauser   }
207a3315606SNikolas Klauser 
208a3315606SNikolas Klauser   { // check that returning another type from the projection works
209a3315606SNikolas Klauser     {
210a3315606SNikolas Klauser       struct S { int i; int other; };
211a3315606SNikolas Klauser       S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} };
212a3315606SNikolas Klauser       std::array<int, 4> b;
213a3315606SNikolas Klauser       std::ranges::transform(a, a + 4, b.begin(), [](S s) { return s.i; });
214a3315606SNikolas Klauser       assert((b == std::array{0, 1, 3, 10}));
215a3315606SNikolas Klauser     }
216a3315606SNikolas Klauser     {
217a3315606SNikolas Klauser       struct S { int i; int other; };
218a3315606SNikolas Klauser       S a[] = { S{0, 0}, S{1, 0}, S{3, 0}, S{10, 0} };
219a3315606SNikolas Klauser       std::array<int, 4> b;
220a3315606SNikolas Klauser       std::ranges::transform(a, b.begin(), [](S s) { return s.i; });
221a3315606SNikolas Klauser       assert((b == std::array{0, 1, 3, 10}));
222a3315606SNikolas Klauser     }
223a3315606SNikolas Klauser   }
224a3315606SNikolas Klauser 
225a3315606SNikolas Klauser   { // check that std::invoke is used
226a3315606SNikolas Klauser     struct S { int i; };
227a3315606SNikolas Klauser     S a[] = { S{1}, S{3}, S{2} };
228a3315606SNikolas Klauser     std::array<int, 3> b;
229a3315606SNikolas Klauser     auto ret = std::ranges::transform(a, b.data(), [](int i) { return i; }, &S::i);
230a3315606SNikolas Klauser     assert((b == std::array{1, 3, 2}));
231a3315606SNikolas Klauser     assert(ret.out == b.data() + 3);
232a3315606SNikolas Klauser   }
233a3315606SNikolas Klauser 
234a3315606SNikolas Klauser   return true;
235a3315606SNikolas Klauser }
236a3315606SNikolas Klauser 
main(int,char **)237a3315606SNikolas Klauser int main(int, char**) {
238a3315606SNikolas Klauser   test_iterator_in1<cpp17_output_iterator<int*>>();
239a3315606SNikolas Klauser   test_iterator_in1<cpp20_output_iterator<int*>>();
240a3315606SNikolas Klauser   test_iterator_in1<forward_iterator<int*>>();
241a3315606SNikolas Klauser   test_iterator_in1<bidirectional_iterator<int*>>();
242a3315606SNikolas Klauser   test_iterator_in1<random_access_iterator<int*>>();
243a3315606SNikolas Klauser   test_iterator_in1<contiguous_iterator<int*>>();
244a3315606SNikolas Klauser   test_iterator_in1<int*>();
245a3315606SNikolas Klauser   test();
246a3315606SNikolas Klauser   static_assert(test());
247a3315606SNikolas Klauser 
248a3315606SNikolas Klauser   return 0;
249a3315606SNikolas Klauser }
250