Skip to content

Commit c15ba1b

Browse files
committed
[libc++] Split ranges.transform.binary.pass.cpp up
`ranges.transform.binary.pass.cpp` took ~25s to compile. `ranges.transform.binary.range.pass.cpp` and `ranges.transform.binary.iterator.pass.cpp` take ~13s each. Reviewed By: ldionne, #libc Spies: libcxx-commits Differential Revision: https://reviews.llvm.org/D142183
1 parent 97b5e01 commit c15ba1b

File tree

3 files changed

+515
-426
lines changed

3 files changed

+515
-426
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,227 @@
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+
11+
// <algorithm>
12+
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 = {});
21+
22+
// The range overloads are tested in ranges.tranform.binary.range.pass.cpp.
23+
24+
#include <algorithm>
25+
#include <array>
26+
#include <cassert>
27+
#include <functional>
28+
#include <ranges>
29+
30+
#include "test_iterators.h"
31+
#include "almost_satisfies_types.h"
32+
33+
struct BinaryFunc {
34+
int operator()(int, int);
35+
};
36+
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>);
46+
47+
template <class It>
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{});
50+
};
51+
static_assert(HasTransformOut<int*>);
52+
static_assert(!HasTransformOut<WeaklyIncrementableNotMovable>);
53+
54+
// check indirectly_readable
55+
static_assert(HasTransformOut<char*>);
56+
static_assert(!HasTransformOut<int**>);
57+
58+
struct MoveOnlyFunctor {
59+
MoveOnlyFunctor(const MoveOnlyFunctor&) = delete;
60+
MoveOnlyFunctor(MoveOnlyFunctor&&) = default;
61+
int operator()(int, int);
62+
};
63+
64+
template <class Func>
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);
67+
};
68+
static_assert(HasTransformFuncBinary<BinaryFunc>);
69+
static_assert(!HasTransformFuncBinary<MoveOnlyFunctor>);
70+
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>>);
73+
74+
// clang-format off
75+
template <class In1, class In2, class Out, class Sent1, class Sent2>
76+
constexpr bool test_iterators() {
77+
{ // simple
78+
int a[] = {1, 2, 3, 4, 5};
79+
int b[] = {5, 4, 3, 2, 1};
80+
int c[5];
81+
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; });
84+
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);
89+
}
90+
91+
{ // first range empty
92+
int a[] = {};
93+
int b[] = {5, 4, 3, 2, 1};
94+
int c[5];
95+
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; });
98+
99+
assert(base(ret.in1) == a);
100+
assert(base(ret.in2) == b);
101+
assert(base(ret.out) == c);
102+
}
103+
104+
{ // second range empty
105+
int a[] = {5, 4, 3, 2, 1};
106+
int b[] = {};
107+
int c[5];
108+
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; });
111+
112+
assert(base(ret.in1) == a);
113+
assert(base(ret.in2) == b);
114+
assert(base(ret.out) == c);
115+
}
116+
117+
{ // both ranges empty
118+
int a[] = {};
119+
int b[] = {};
120+
int c[5];
121+
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; });
124+
125+
assert(base(ret.in1) == a);
126+
assert(base(ret.in2) == b);
127+
assert(base(ret.out) == c);
128+
}
129+
130+
{ // first range one element
131+
int a[] = {2};
132+
int b[] = {5, 4, 3, 2, 1};
133+
int c[5];
134+
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; });
137+
138+
assert(c[0] == 7);
139+
assert(base(ret.in1) == a + 1);
140+
assert(base(ret.in2) == b + 1);
141+
assert(base(ret.out) == c + 1);
142+
}
143+
144+
{ // second range contains one element
145+
int a[] = {5, 4, 3, 2, 1};
146+
int b[] = {4};
147+
int c[5];
148+
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; });
151+
152+
assert(c[0] == 9);
153+
assert(base(ret.in1) == a + 1);
154+
assert(base(ret.in2) == b + 1);
155+
assert(base(ret.out) == c + 1);
156+
}
157+
158+
{ // check that the transform function and projection call counts are correct
159+
int predCount = 0;
160+
int proj1Count = 0;
161+
int proj2Count = 0;
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}));
173+
}
174+
175+
return true;
176+
}
177+
// clang-format on
178+
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>();
188+
}
189+
190+
template <class Out>
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>();
199+
}
200+
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*>();
209+
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}));
217+
}
218+
219+
return true;
220+
}
221+
222+
int main(int, char**) {
223+
test();
224+
static_assert(test());
225+
226+
return 0;
227+
}

0 commit comments

Comments
 (0)