blob: de0a6710789ce4c5fcae67af71015e1ead4f306a [file] [log] [blame]
Chandler Carruth9a6be8b2014-04-24 03:31:23 +00001//===- IteratorTest.cpp - Unit tests for iterator utilities ---------------===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
David Blaikiedd1a9282018-11-14 07:19:21 +000010#include "llvm/ADT/ilist.h"
Chandler Carruth9a67b072017-06-06 11:06:56 +000011#include "llvm/ADT/iterator.h"
Vedant Kumar75fda2e2018-04-25 21:50:09 +000012#include "llvm/ADT/ArrayRef.h"
Chandler Carruthd5835ee2014-04-24 21:10:35 +000013#include "llvm/ADT/STLExtras.h"
Chandler Carruth9a6be8b2014-04-24 03:31:23 +000014#include "llvm/ADT/SmallVector.h"
15#include "gtest/gtest.h"
16
17using namespace llvm;
18
19namespace {
20
Tim Shen75c16562016-08-09 20:23:13 +000021template <int> struct Shadow;
22
23struct WeirdIter : std::iterator<std::input_iterator_tag, Shadow<0>, Shadow<1>,
24 Shadow<2>, Shadow<3>> {};
25
26struct AdaptedIter : iterator_adaptor_base<AdaptedIter, WeirdIter> {};
27
28// Test that iterator_adaptor_base forwards typedefs, if value_type is
29// unchanged.
30static_assert(std::is_same<typename AdaptedIter::value_type, Shadow<0>>::value,
31 "");
32static_assert(
33 std::is_same<typename AdaptedIter::difference_type, Shadow<1>>::value, "");
34static_assert(std::is_same<typename AdaptedIter::pointer, Shadow<2>>::value,
35 "");
36static_assert(std::is_same<typename AdaptedIter::reference, Shadow<3>>::value,
37 "");
38
David Blaikiedd1a9282018-11-14 07:19:21 +000039// Ensure that pointe{e,r}_iterator adaptors correctly forward the category of
40// the underlying iterator.
41
42using RandomAccessIter = SmallVectorImpl<int*>::iterator;
43using BidiIter = ilist<int*>::iterator;
44
45template<class T>
46using pointee_iterator_defaulted = pointee_iterator<T>;
47template<class T>
48using pointer_iterator_defaulted = pointer_iterator<T>;
49
50// Ensures that an iterator and its adaptation have the same iterator_category.
51template<template<typename> class A, typename It>
52using IsAdaptedIterCategorySame =
53 std::is_same<typename std::iterator_traits<It>::iterator_category,
54 typename std::iterator_traits<A<It>>::iterator_category>;
55
56// pointeE_iterator
57static_assert(IsAdaptedIterCategorySame<pointee_iterator_defaulted,
58 RandomAccessIter>::value, "");
59static_assert(IsAdaptedIterCategorySame<pointee_iterator_defaulted,
60 BidiIter>::value, "");
61// pointeR_iterator
62static_assert(IsAdaptedIterCategorySame<pointer_iterator_defaulted,
63 RandomAccessIter>::value, "");
64static_assert(IsAdaptedIterCategorySame<pointer_iterator_defaulted,
65 BidiIter>::value, "");
66
Chandler Carruth9a6be8b2014-04-24 03:31:23 +000067TEST(PointeeIteratorTest, Basic) {
Bryant Wong332e6e52017-02-23 23:00:46 +000068 int arr[4] = {1, 2, 3, 4};
Chandler Carruth9a6be8b2014-04-24 03:31:23 +000069 SmallVector<int *, 4> V;
70 V.push_back(&arr[0]);
71 V.push_back(&arr[1]);
72 V.push_back(&arr[2]);
73 V.push_back(&arr[3]);
74
Bryant Wong332e6e52017-02-23 23:00:46 +000075 typedef pointee_iterator<SmallVectorImpl<int *>::const_iterator>
76 test_iterator;
Chandler Carruth9a6be8b2014-04-24 03:31:23 +000077
Justin Lebar4765c012016-10-10 19:56:52 +000078 test_iterator Begin, End;
79 Begin = V.begin();
80 End = test_iterator(V.end());
81
82 test_iterator I = Begin;
Chandler Carruth9a6be8b2014-04-24 03:31:23 +000083 for (int i = 0; i < 4; ++i) {
84 EXPECT_EQ(*V[i], *I);
85
86 EXPECT_EQ(I, Begin + i);
87 EXPECT_EQ(I, std::next(Begin, i));
Justin Lebar4765c012016-10-10 19:56:52 +000088 test_iterator J = Begin;
Chandler Carruth9a6be8b2014-04-24 03:31:23 +000089 J += i;
90 EXPECT_EQ(I, J);
91 EXPECT_EQ(*V[i], Begin[i]);
92
93 EXPECT_NE(I, End);
94 EXPECT_GT(End, I);
95 EXPECT_LT(I, End);
96 EXPECT_GE(I, Begin);
97 EXPECT_LE(Begin, I);
98
99 EXPECT_EQ(i, I - Begin);
100 EXPECT_EQ(i, std::distance(Begin, I));
101 EXPECT_EQ(Begin, I - i);
102
Justin Lebar4765c012016-10-10 19:56:52 +0000103 test_iterator K = I++;
Chandler Carruth9a6be8b2014-04-24 03:31:23 +0000104 EXPECT_EQ(K, std::prev(I));
105 }
106 EXPECT_EQ(End, I);
107}
108
Chandler Carruthd5835ee2014-04-24 21:10:35 +0000109TEST(PointeeIteratorTest, SmartPointer) {
110 SmallVector<std::unique_ptr<int>, 4> V;
111 V.push_back(make_unique<int>(1));
112 V.push_back(make_unique<int>(2));
113 V.push_back(make_unique<int>(3));
114 V.push_back(make_unique<int>(4));
115
Justin Lebar4765c012016-10-10 19:56:52 +0000116 typedef pointee_iterator<
Bryant Wong332e6e52017-02-23 23:00:46 +0000117 SmallVectorImpl<std::unique_ptr<int>>::const_iterator>
118 test_iterator;
Chandler Carruthd5835ee2014-04-24 21:10:35 +0000119
Justin Lebar4765c012016-10-10 19:56:52 +0000120 test_iterator Begin, End;
121 Begin = V.begin();
122 End = test_iterator(V.end());
123
124 test_iterator I = Begin;
Chandler Carruthd5835ee2014-04-24 21:10:35 +0000125 for (int i = 0; i < 4; ++i) {
126 EXPECT_EQ(*V[i], *I);
127
128 EXPECT_EQ(I, Begin + i);
129 EXPECT_EQ(I, std::next(Begin, i));
Justin Lebar4765c012016-10-10 19:56:52 +0000130 test_iterator J = Begin;
Chandler Carruthd5835ee2014-04-24 21:10:35 +0000131 J += i;
132 EXPECT_EQ(I, J);
133 EXPECT_EQ(*V[i], Begin[i]);
134
135 EXPECT_NE(I, End);
136 EXPECT_GT(End, I);
137 EXPECT_LT(I, End);
138 EXPECT_GE(I, Begin);
139 EXPECT_LE(Begin, I);
140
141 EXPECT_EQ(i, I - Begin);
142 EXPECT_EQ(i, std::distance(Begin, I));
143 EXPECT_EQ(Begin, I - i);
144
Justin Lebar4765c012016-10-10 19:56:52 +0000145 test_iterator K = I++;
Chandler Carruthd5835ee2014-04-24 21:10:35 +0000146 EXPECT_EQ(K, std::prev(I));
147 }
148 EXPECT_EQ(End, I);
149}
150
Justin Bogner8444d102017-03-27 12:56:12 +0000151TEST(PointeeIteratorTest, Range) {
152 int A[] = {1, 2, 3, 4};
153 SmallVector<int *, 4> V{&A[0], &A[1], &A[2], &A[3]};
154
155 int I = 0;
156 for (int II : make_pointee_range(V))
157 EXPECT_EQ(A[I++], II);
158}
159
Justin Bogner5b451062018-06-27 00:54:36 +0000160TEST(PointeeIteratorTest, PointeeType) {
161 struct S {
162 int X;
163 bool operator==(const S &RHS) const { return X == RHS.X; };
164 };
165 S A[] = {S{0}, S{1}};
166 SmallVector<S *, 2> V{&A[0], &A[1]};
167
168 pointee_iterator<SmallVectorImpl<S *>::const_iterator, const S> I = V.begin();
169 for (int j = 0; j < 2; ++j, ++I) {
170 EXPECT_EQ(*V[j], *I);
171 }
172}
173
Tim Shene78e32a2016-08-12 22:03:28 +0000174TEST(FilterIteratorTest, Lambda) {
175 auto IsOdd = [](int N) { return N % 2 == 1; };
176 int A[] = {0, 1, 2, 3, 4, 5, 6};
177 auto Range = make_filter_range(A, IsOdd);
178 SmallVector<int, 3> Actual(Range.begin(), Range.end());
179 EXPECT_EQ((SmallVector<int, 3>{1, 3, 5}), Actual);
180}
181
182TEST(FilterIteratorTest, CallableObject) {
183 int Counter = 0;
184 struct Callable {
185 int &Counter;
186
187 Callable(int &Counter) : Counter(Counter) {}
188
189 bool operator()(int N) {
190 Counter++;
191 return N % 2 == 1;
192 }
193 };
194 Callable IsOdd(Counter);
195 int A[] = {0, 1, 2, 3, 4, 5, 6};
196 auto Range = make_filter_range(A, IsOdd);
197 EXPECT_EQ(2, Counter);
198 SmallVector<int, 3> Actual(Range.begin(), Range.end());
199 EXPECT_GE(Counter, 7);
200 EXPECT_EQ((SmallVector<int, 3>{1, 3, 5}), Actual);
201}
202
203TEST(FilterIteratorTest, FunctionPointer) {
204 bool (*IsOdd)(int) = [](int N) { return N % 2 == 1; };
205 int A[] = {0, 1, 2, 3, 4, 5, 6};
206 auto Range = make_filter_range(A, IsOdd);
207 SmallVector<int, 3> Actual(Range.begin(), Range.end());
208 EXPECT_EQ((SmallVector<int, 3>{1, 3, 5}), Actual);
209}
210
211TEST(FilterIteratorTest, Composition) {
212 auto IsOdd = [](int N) { return N % 2 == 1; };
213 std::unique_ptr<int> A[] = {make_unique<int>(0), make_unique<int>(1),
214 make_unique<int>(2), make_unique<int>(3),
215 make_unique<int>(4), make_unique<int>(5),
216 make_unique<int>(6)};
217 using PointeeIterator = pointee_iterator<std::unique_ptr<int> *>;
218 auto Range = make_filter_range(
219 make_range(PointeeIterator(std::begin(A)), PointeeIterator(std::end(A))),
220 IsOdd);
221 SmallVector<int, 3> Actual(Range.begin(), Range.end());
222 EXPECT_EQ((SmallVector<int, 3>{1, 3, 5}), Actual);
223}
224
225TEST(FilterIteratorTest, InputIterator) {
226 struct InputIterator
227 : iterator_adaptor_base<InputIterator, int *, std::input_iterator_tag> {
228 using BaseT =
229 iterator_adaptor_base<InputIterator, int *, std::input_iterator_tag>;
230
231 InputIterator(int *It) : BaseT(It) {}
232 };
233
234 auto IsOdd = [](int N) { return N % 2 == 1; };
235 int A[] = {0, 1, 2, 3, 4, 5, 6};
236 auto Range = make_filter_range(
237 make_range(InputIterator(std::begin(A)), InputIterator(std::end(A))),
238 IsOdd);
239 SmallVector<int, 3> Actual(Range.begin(), Range.end());
240 EXPECT_EQ((SmallVector<int, 3>{1, 3, 5}), Actual);
241}
242
Vedant Kumar75fda2e2018-04-25 21:50:09 +0000243TEST(FilterIteratorTest, ReverseFilterRange) {
244 auto IsOdd = [](int N) { return N % 2 == 1; };
245 int A[] = {0, 1, 2, 3, 4, 5, 6};
246
247 // Check basic reversal.
248 auto Range = reverse(make_filter_range(A, IsOdd));
249 SmallVector<int, 3> Actual(Range.begin(), Range.end());
250 EXPECT_EQ((SmallVector<int, 3>{5, 3, 1}), Actual);
251
252 // Check that the reverse of the reverse is the original.
253 auto Range2 = reverse(reverse(make_filter_range(A, IsOdd)));
254 SmallVector<int, 3> Actual2(Range2.begin(), Range2.end());
255 EXPECT_EQ((SmallVector<int, 3>{1, 3, 5}), Actual2);
256
257 // Check empty ranges.
258 auto Range3 = reverse(make_filter_range(ArrayRef<int>(), IsOdd));
259 SmallVector<int, 0> Actual3(Range3.begin(), Range3.end());
260 EXPECT_EQ((SmallVector<int, 0>{}), Actual3);
261
262 // Check that we don't skip the first element, provided it isn't filtered
263 // away.
264 auto IsEven = [](int N) { return N % 2 == 0; };
265 auto Range4 = reverse(make_filter_range(A, IsEven));
266 SmallVector<int, 4> Actual4(Range4.begin(), Range4.end());
267 EXPECT_EQ((SmallVector<int, 4>{6, 4, 2, 0}), Actual4);
268}
269
Tim Shencf03add2016-08-19 21:04:45 +0000270TEST(PointerIterator, Basic) {
271 int A[] = {1, 2, 3, 4};
Justin Lebar4765c012016-10-10 19:56:52 +0000272 pointer_iterator<int *> Begin(std::begin(A)), End(std::end(A));
Tim Shencf03add2016-08-19 21:04:45 +0000273 EXPECT_EQ(A, *Begin);
274 ++Begin;
275 EXPECT_EQ(A + 1, *Begin);
276 ++Begin;
277 EXPECT_EQ(A + 2, *Begin);
278 ++Begin;
279 EXPECT_EQ(A + 3, *Begin);
280 ++Begin;
281 EXPECT_EQ(Begin, End);
282}
283
284TEST(PointerIterator, Const) {
285 int A[] = {1, 2, 3, 4};
Justin Lebar4765c012016-10-10 19:56:52 +0000286 const pointer_iterator<int *> Begin(std::begin(A));
Tim Shencf03add2016-08-19 21:04:45 +0000287 EXPECT_EQ(A, *Begin);
288 EXPECT_EQ(A + 1, std::next(*Begin, 1));
289 EXPECT_EQ(A + 2, std::next(*Begin, 2));
290 EXPECT_EQ(A + 3, std::next(*Begin, 3));
291 EXPECT_EQ(A + 4, std::next(*Begin, 4));
292}
293
Justin Bogner8444d102017-03-27 12:56:12 +0000294TEST(PointerIterator, Range) {
295 int A[] = {1, 2, 3, 4};
296 int I = 0;
297 for (int *P : make_pointer_range(A))
298 EXPECT_EQ(A + I++, P);
299}
300
Mehdi Aminia8515452016-10-19 18:02:21 +0000301TEST(ZipIteratorTest, Basic) {
302 using namespace std;
303 const SmallVector<unsigned, 6> pi{3, 1, 4, 1, 5, 9};
304 SmallVector<bool, 6> odd{1, 1, 0, 1, 1, 1};
305 const char message[] = "yynyyy\0";
306
307 for (auto tup : zip(pi, odd, message)) {
308 EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
309 EXPECT_EQ(get<0>(tup) & 0x01 ? 'y' : 'n', get<2>(tup));
310 }
311
312 // note the rvalue
313 for (auto tup : zip(pi, SmallVector<bool, 0>{1, 1, 0, 1, 1})) {
314 EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
315 }
316}
317
318TEST(ZipIteratorTest, ZipFirstBasic) {
319 using namespace std;
320 const SmallVector<unsigned, 6> pi{3, 1, 4, 1, 5, 9};
321 unsigned iters = 0;
322
323 for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
324 EXPECT_EQ(get<0>(tup), get<1>(tup) & 0x01);
325 iters += 1;
326 }
327
328 EXPECT_EQ(iters, 4u);
329}
330
331TEST(ZipIteratorTest, Mutability) {
332 using namespace std;
333 const SmallVector<unsigned, 4> pi{3, 1, 4, 1, 5, 9};
334 char message[] = "hello zip\0";
335
336 for (auto tup : zip(pi, message, message)) {
337 EXPECT_EQ(get<1>(tup), get<2>(tup));
338 get<2>(tup) = get<0>(tup) & 0x01 ? 'y' : 'n';
339 }
340
341 // note the rvalue
342 for (auto tup : zip(message, "yynyyyzip\0")) {
343 EXPECT_EQ(get<0>(tup), get<1>(tup));
344 }
345}
346
347TEST(ZipIteratorTest, ZipFirstMutability) {
348 using namespace std;
349 vector<unsigned> pi{3, 1, 4, 1, 5, 9};
350 unsigned iters = 0;
351
352 for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
353 get<1>(tup) = get<0>(tup);
354 iters += 1;
355 }
356
357 EXPECT_EQ(iters, 4u);
358
359 for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
360 EXPECT_EQ(get<0>(tup), get<1>(tup));
361 }
362}
363
Bryant Wong332e6e52017-02-23 23:00:46 +0000364TEST(ZipIteratorTest, Filter) {
365 using namespace std;
366 vector<unsigned> pi{3, 1, 4, 1, 5, 9};
367
368 unsigned iters = 0;
369 // pi is length 6, but the zip RHS is length 7.
370 auto zipped = zip_first(pi, vector<bool>{1, 1, 0, 1, 1, 1, 0});
371 for (auto tup : make_filter_range(
372 zipped, [](decltype(zipped)::value_type t) { return get<1>(t); })) {
373 EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
374 get<0>(tup) += 1;
375 iters += 1;
376 }
377
378 // Should have skipped pi[2].
379 EXPECT_EQ(iters, 5u);
380
381 // Ensure that in-place mutation works.
382 EXPECT_TRUE(all_of(pi, [](unsigned n) { return (n & 0x01) == 0; }));
383}
384
385TEST(ZipIteratorTest, Reverse) {
386 using namespace std;
387 vector<unsigned> ascending{0, 1, 2, 3, 4, 5};
388
389 auto zipped = zip_first(ascending, vector<bool>{0, 1, 0, 1, 0, 1});
390 unsigned last = 6;
391 for (auto tup : reverse(zipped)) {
392 // Check that this is in reverse.
393 EXPECT_LT(get<0>(tup), last);
394 last = get<0>(tup);
395 EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
396 }
397
398 auto odds = [](decltype(zipped)::value_type tup) { return get<1>(tup); };
399 last = 6;
400 for (auto tup : make_filter_range(reverse(zipped), odds)) {
401 EXPECT_LT(get<0>(tup), last);
402 last = get<0>(tup);
403 EXPECT_TRUE(get<0>(tup) & 0x01);
404 get<0>(tup) += 1;
405 }
406
407 // Ensure that in-place mutation works.
408 EXPECT_TRUE(all_of(ascending, [](unsigned n) { return (n & 0x01) == 0; }));
409}
410
Vedant Kumare0b5f862018-05-10 23:01:54 +0000411TEST(RangeTest, Distance) {
412 std::vector<int> v1;
413 std::vector<int> v2{1, 2, 3};
414
Vedant Kumar5a0872c2018-05-16 23:20:42 +0000415 EXPECT_EQ(std::distance(v1.begin(), v1.end()), size(v1));
416 EXPECT_EQ(std::distance(v2.begin(), v2.end()), size(v2));
Vedant Kumare0b5f862018-05-10 23:01:54 +0000417}
418
Michael Kruse2cb21992018-06-27 19:39:03 +0000419TEST(IteratorRangeTest, DropBegin) {
420 SmallVector<int, 5> vec{0, 1, 2, 3, 4};
421
422 for (int n = 0; n < 5; ++n) {
423 int i = n;
424 for (auto &v : drop_begin(vec, n)) {
425 EXPECT_EQ(v, i);
426 i += 1;
427 }
428 EXPECT_EQ(i, 5);
429 }
430}
431
Chandler Carruth9a6be8b2014-04-24 03:31:23 +0000432} // anonymous namespace