1 //===------ MappedIteratorTest.cpp - Unit tests for mapped_iterator -------===//
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 #include "llvm/ADT/STLExtras.h"
10 #include "gtest/gtest.h"
11
12 using namespace llvm;
13
14 namespace {
15
16 template <typename T> class MappedIteratorTestBasic : public testing::Test {};
17
18 struct Plus1Lambda {
operator ()__anon1291ca280111::Plus1Lambda19 auto operator()() const {
20 return [](int X) { return X + 1; };
21 }
22 };
23
24 struct Plus1LambdaWithCapture {
25 const int One = 1;
26
operator ()__anon1291ca280111::Plus1LambdaWithCapture27 auto operator()() const {
28 return [=](int X) { return X + One; };
29 }
30 };
31
32 struct Plus1FunctionRef {
plus1__anon1291ca280111::Plus1FunctionRef33 static int plus1(int X) { return X + 1; }
34
35 using FuncT = int (&)(int);
36
operator ()__anon1291ca280111::Plus1FunctionRef37 FuncT operator()() const { return (FuncT)*plus1; }
38 };
39
40 struct Plus1FunctionPtr {
plus1__anon1291ca280111::Plus1FunctionPtr41 static int plus1(int X) { return X + 1; }
42
43 using FuncT = int (*)(int);
44
operator ()__anon1291ca280111::Plus1FunctionPtr45 FuncT operator()() const { return plus1; }
46 };
47
48 struct Plus1Functor {
49 struct Plus1 {
operator ()__anon1291ca280111::Plus1Functor::Plus150 int operator()(int X) const { return X + 1; }
51 };
52
operator ()__anon1291ca280111::Plus1Functor53 auto operator()() const { return Plus1(); }
54 };
55
56 struct Plus1FunctorNotDefaultConstructible {
57 class PlusN {
58 const int N;
59
60 public:
PlusN(int NArg)61 PlusN(int NArg) : N(NArg) {}
62
operator ()(int X) const63 int operator()(int X) const { return X + N; }
64 };
65
operator ()__anon1291ca280111::Plus1FunctorNotDefaultConstructible66 auto operator()() const { return PlusN(1); }
67 };
68
69 // clang-format off
70 using FunctionTypes =
71 ::testing::Types<
72 Plus1Lambda,
73 Plus1LambdaWithCapture,
74 Plus1FunctionRef,
75 Plus1FunctionPtr,
76 Plus1Functor,
77 Plus1FunctorNotDefaultConstructible
78 >;
79 // clang-format on
80
81 TYPED_TEST_SUITE(MappedIteratorTestBasic, FunctionTypes, );
82
83 template <typename T> using GetFuncT = decltype(std::declval<T>().operator()());
84
TYPED_TEST(MappedIteratorTestBasic,DefaultConstruct)85 TYPED_TEST(MappedIteratorTestBasic, DefaultConstruct) {
86 using FuncT = GetFuncT<TypeParam>;
87 using IterT = mapped_iterator<typename std::vector<int>::iterator, FuncT>;
88 TypeParam GetCallable;
89
90 auto Func = GetCallable();
91 (void)Func;
92 constexpr bool DefaultConstruct =
93 std::is_default_constructible_v<callable_detail::Callable<FuncT>>;
94 EXPECT_TRUE(DefaultConstruct);
95 EXPECT_TRUE(std::is_default_constructible_v<IterT>);
96
97 if constexpr (std::is_default_constructible_v<IterT>) {
98 IterT I;
99 (void)I;
100 }
101 }
102
TYPED_TEST(MappedIteratorTestBasic,CopyConstruct)103 TYPED_TEST(MappedIteratorTestBasic, CopyConstruct) {
104 std::vector<int> V({0});
105
106 using FuncT = GetFuncT<TypeParam>;
107 using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;
108
109 EXPECT_TRUE(std::is_copy_constructible_v<IterT>);
110
111 if constexpr (std::is_copy_constructible_v<IterT>) {
112 TypeParam GetCallable;
113
114 IterT I1(V.begin(), GetCallable());
115 IterT I2(I1);
116
117 EXPECT_EQ(I2, I1) << "copy constructed iterator is a different position";
118 }
119 }
120
TYPED_TEST(MappedIteratorTestBasic,MoveConstruct)121 TYPED_TEST(MappedIteratorTestBasic, MoveConstruct) {
122 std::vector<int> V({0});
123
124 using FuncT = GetFuncT<TypeParam>;
125 using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;
126
127 EXPECT_TRUE(std::is_move_constructible_v<IterT>);
128
129 if constexpr (std::is_move_constructible_v<IterT>) {
130 TypeParam GetCallable;
131
132 IterT I1(V.begin(), GetCallable());
133 IterT I2(V.begin(), GetCallable());
134 IterT I3(std::move(I2));
135
136 EXPECT_EQ(I3, I1) << "move constructed iterator is a different position";
137 }
138 }
139
TYPED_TEST(MappedIteratorTestBasic,CopyAssign)140 TYPED_TEST(MappedIteratorTestBasic, CopyAssign) {
141 std::vector<int> V({0});
142
143 using FuncT = GetFuncT<TypeParam>;
144 using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;
145
146 EXPECT_TRUE(std::is_copy_assignable_v<IterT>);
147
148 if constexpr (std::is_copy_assignable_v<IterT>) {
149 TypeParam GetCallable;
150
151 IterT I1(V.begin(), GetCallable());
152 IterT I2(V.end(), GetCallable());
153
154 I2 = I1;
155
156 EXPECT_EQ(I2, I1) << "copy assigned iterator is a different position";
157 }
158 }
159
TYPED_TEST(MappedIteratorTestBasic,MoveAssign)160 TYPED_TEST(MappedIteratorTestBasic, MoveAssign) {
161 std::vector<int> V({0});
162
163 using FuncT = GetFuncT<TypeParam>;
164 using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;
165
166 EXPECT_TRUE(std::is_move_assignable_v<IterT>);
167
168 if constexpr (std::is_move_assignable_v<IterT>) {
169 TypeParam GetCallable;
170
171 IterT I1(V.begin(), GetCallable());
172 IterT I2(V.begin(), GetCallable());
173 IterT I3(V.end(), GetCallable());
174
175 I3 = std::move(I2);
176
177 EXPECT_EQ(I3, I1) << "move assigned iterator is a different position";
178 }
179 }
180
TYPED_TEST(MappedIteratorTestBasic,GetFunction)181 TYPED_TEST(MappedIteratorTestBasic, GetFunction) {
182 std::vector<int> V({0});
183
184 using FuncT = GetFuncT<TypeParam>;
185 using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;
186
187 TypeParam GetCallable;
188 IterT I(V.begin(), GetCallable());
189
190 EXPECT_EQ(I.getFunction()(200), 201);
191 }
192
TYPED_TEST(MappedIteratorTestBasic,GetCurrent)193 TYPED_TEST(MappedIteratorTestBasic, GetCurrent) {
194 std::vector<int> V({0});
195
196 using FuncT = GetFuncT<TypeParam>;
197 using IterT = mapped_iterator<decltype(V)::iterator, FuncT>;
198
199 TypeParam GetCallable;
200 IterT I(V.begin(), GetCallable());
201
202 EXPECT_EQ(I.getCurrent(), V.begin());
203 EXPECT_EQ(std::next(I).getCurrent(), V.end());
204 }
205
TYPED_TEST(MappedIteratorTestBasic,ApplyFunctionOnDereference)206 TYPED_TEST(MappedIteratorTestBasic, ApplyFunctionOnDereference) {
207 std::vector<int> V({0});
208 TypeParam GetCallable;
209
210 auto I = map_iterator(V.begin(), GetCallable());
211
212 EXPECT_EQ(*I, 1) << "should have applied function in dereference";
213 }
214
TEST(MappedIteratorTest,ApplyFunctionOnArrow)215 TEST(MappedIteratorTest, ApplyFunctionOnArrow) {
216 struct S {
217 int Z = 0;
218 };
219
220 std::vector<int> V({0});
221 S Y;
222 S *P = &Y;
223
224 auto I = map_iterator(V.begin(), [&](int X) -> S & { return *(P + X); });
225
226 I->Z = 42;
227
228 EXPECT_EQ(Y.Z, 42) << "should have applied function during arrow";
229 }
230
TEST(MappedIteratorTest,FunctionPreservesReferences)231 TEST(MappedIteratorTest, FunctionPreservesReferences) {
232 std::vector<int> V({1});
233 std::map<int, int> M({{1, 1}});
234
235 auto I = map_iterator(V.begin(), [&](int X) -> int & { return M[X]; });
236 *I = 42;
237
238 EXPECT_EQ(M[1], 42) << "assignment should have modified M";
239 }
240
TEST(MappedIteratorTest,CustomIteratorApplyFunctionOnDereference)241 TEST(MappedIteratorTest, CustomIteratorApplyFunctionOnDereference) {
242 struct CustomMapIterator
243 : public llvm::mapped_iterator_base<CustomMapIterator,
244 std::vector<int>::iterator, int> {
245 using BaseT::BaseT;
246
247 /// Map the element to the iterator result type.
248 int mapElement(int X) const { return X + 1; }
249 };
250
251 std::vector<int> V({0});
252
253 CustomMapIterator I(V.begin());
254
255 EXPECT_EQ(*I, 1) << "should have applied function in dereference";
256 }
257
TEST(MappedIteratorTest,CustomIteratorApplyFunctionOnArrow)258 TEST(MappedIteratorTest, CustomIteratorApplyFunctionOnArrow) {
259 struct S {
260 int Z = 0;
261 };
262 struct CustomMapIterator
263 : public llvm::mapped_iterator_base<CustomMapIterator,
264 std::vector<int>::iterator, S &> {
265 CustomMapIterator(std::vector<int>::iterator it, S *P) : BaseT(it), P(P) {}
266
267 /// Map the element to the iterator result type.
268 S &mapElement(int X) const { return *(P + X); }
269
270 S *P;
271 };
272
273 std::vector<int> V({0});
274 S Y;
275
276 CustomMapIterator I(V.begin(), &Y);
277
278 I->Z = 42;
279
280 EXPECT_EQ(Y.Z, 42) << "should have applied function during arrow";
281 }
282
TEST(MappedIteratorTest,CustomIteratorFunctionPreservesReferences)283 TEST(MappedIteratorTest, CustomIteratorFunctionPreservesReferences) {
284 struct CustomMapIterator
285 : public llvm::mapped_iterator_base<CustomMapIterator,
286 std::vector<int>::iterator, int &> {
287 CustomMapIterator(std::vector<int>::iterator it, std::map<int, int> &M)
288 : BaseT(it), M(M) {}
289
290 /// Map the element to the iterator result type.
291 int &mapElement(int X) const { return M[X]; }
292
293 std::map<int, int> &M;
294 };
295 std::vector<int> V({1});
296 std::map<int, int> M({{1, 1}});
297
298 auto I = CustomMapIterator(V.begin(), M);
299 *I = 42;
300
301 EXPECT_EQ(M[1], 42) << "assignment should have modified M";
302 }
303
304 } // anonymous namespace
305