blob: 902ddfb49f22a2e21114fd5ff5d0fde37ea61652 [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
Michael Krusef57bfd32018-12-05 00:31:54 +0000331TEST(ZipIteratorTest, ZipLongestBasic) {
332 using namespace std;
333 const vector<unsigned> pi{3, 1, 4, 1, 5, 9};
334 const vector<StringRef> e{"2", "7", "1", "8"};
335
336 {
337 // Check left range longer than right.
338 const vector<tuple<Optional<unsigned>, Optional<StringRef>>> expected{
339 make_tuple(3, StringRef("2")), make_tuple(1, StringRef("7")),
340 make_tuple(4, StringRef("1")), make_tuple(1, StringRef("8")),
341 make_tuple(5, None), make_tuple(9, None)};
342 size_t iters = 0;
343 for (auto tup : zip_longest(pi, e)) {
344 EXPECT_EQ(tup, expected[iters]);
345 iters += 1;
346 }
347 EXPECT_EQ(iters, expected.size());
348 }
349
350 {
351 // Check right range longer than left.
352 const vector<tuple<Optional<StringRef>, Optional<unsigned>>> expected{
353 make_tuple(StringRef("2"), 3), make_tuple(StringRef("7"), 1),
354 make_tuple(StringRef("1"), 4), make_tuple(StringRef("8"), 1),
355 make_tuple(None, 5), make_tuple(None, 9)};
356 size_t iters = 0;
357 for (auto tup : zip_longest(e, pi)) {
358 EXPECT_EQ(tup, expected[iters]);
359 iters += 1;
360 }
361 EXPECT_EQ(iters, expected.size());
362 }
363}
364
Mehdi Aminia8515452016-10-19 18:02:21 +0000365TEST(ZipIteratorTest, Mutability) {
366 using namespace std;
367 const SmallVector<unsigned, 4> pi{3, 1, 4, 1, 5, 9};
368 char message[] = "hello zip\0";
369
370 for (auto tup : zip(pi, message, message)) {
371 EXPECT_EQ(get<1>(tup), get<2>(tup));
372 get<2>(tup) = get<0>(tup) & 0x01 ? 'y' : 'n';
373 }
374
375 // note the rvalue
376 for (auto tup : zip(message, "yynyyyzip\0")) {
377 EXPECT_EQ(get<0>(tup), get<1>(tup));
378 }
379}
380
381TEST(ZipIteratorTest, ZipFirstMutability) {
382 using namespace std;
383 vector<unsigned> pi{3, 1, 4, 1, 5, 9};
384 unsigned iters = 0;
385
386 for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
387 get<1>(tup) = get<0>(tup);
388 iters += 1;
389 }
390
391 EXPECT_EQ(iters, 4u);
392
393 for (auto tup : zip_first(SmallVector<bool, 0>{1, 1, 0, 1}, pi)) {
394 EXPECT_EQ(get<0>(tup), get<1>(tup));
395 }
396}
397
Bryant Wong332e6e52017-02-23 23:00:46 +0000398TEST(ZipIteratorTest, Filter) {
399 using namespace std;
400 vector<unsigned> pi{3, 1, 4, 1, 5, 9};
401
402 unsigned iters = 0;
403 // pi is length 6, but the zip RHS is length 7.
404 auto zipped = zip_first(pi, vector<bool>{1, 1, 0, 1, 1, 1, 0});
405 for (auto tup : make_filter_range(
406 zipped, [](decltype(zipped)::value_type t) { return get<1>(t); })) {
407 EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
408 get<0>(tup) += 1;
409 iters += 1;
410 }
411
412 // Should have skipped pi[2].
413 EXPECT_EQ(iters, 5u);
414
415 // Ensure that in-place mutation works.
416 EXPECT_TRUE(all_of(pi, [](unsigned n) { return (n & 0x01) == 0; }));
417}
418
419TEST(ZipIteratorTest, Reverse) {
420 using namespace std;
421 vector<unsigned> ascending{0, 1, 2, 3, 4, 5};
422
423 auto zipped = zip_first(ascending, vector<bool>{0, 1, 0, 1, 0, 1});
424 unsigned last = 6;
425 for (auto tup : reverse(zipped)) {
426 // Check that this is in reverse.
427 EXPECT_LT(get<0>(tup), last);
428 last = get<0>(tup);
429 EXPECT_EQ(get<0>(tup) & 0x01, get<1>(tup));
430 }
431
432 auto odds = [](decltype(zipped)::value_type tup) { return get<1>(tup); };
433 last = 6;
434 for (auto tup : make_filter_range(reverse(zipped), odds)) {
435 EXPECT_LT(get<0>(tup), last);
436 last = get<0>(tup);
437 EXPECT_TRUE(get<0>(tup) & 0x01);
438 get<0>(tup) += 1;
439 }
440
441 // Ensure that in-place mutation works.
442 EXPECT_TRUE(all_of(ascending, [](unsigned n) { return (n & 0x01) == 0; }));
443}
444
Vedant Kumare0b5f862018-05-10 23:01:54 +0000445TEST(RangeTest, Distance) {
446 std::vector<int> v1;
447 std::vector<int> v2{1, 2, 3};
448
Vedant Kumar5a0872c2018-05-16 23:20:42 +0000449 EXPECT_EQ(std::distance(v1.begin(), v1.end()), size(v1));
450 EXPECT_EQ(std::distance(v2.begin(), v2.end()), size(v2));
Vedant Kumare0b5f862018-05-10 23:01:54 +0000451}
452
Michael Kruse2cb21992018-06-27 19:39:03 +0000453TEST(IteratorRangeTest, DropBegin) {
454 SmallVector<int, 5> vec{0, 1, 2, 3, 4};
455
456 for (int n = 0; n < 5; ++n) {
457 int i = n;
458 for (auto &v : drop_begin(vec, n)) {
459 EXPECT_EQ(v, i);
460 i += 1;
461 }
462 EXPECT_EQ(i, 5);
463 }
464}
465
Chandler Carruth9a6be8b2014-04-24 03:31:23 +0000466} // anonymous namespace