xref: /llvm-project/llvm/unittests/ADT/MappedIteratorTest.cpp (revision c77da6fbaa788863787f8f34f7124498a57e9da8)
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