1 //===- IteratorTest.cpp - Unit tests for iterator utilities ---------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/ADT/ilist.h"
10 #include "llvm/ADT/iterator.h"
11 #include "llvm/ADT/ArrayRef.h"
12 #include "llvm/ADT/STLExtras.h"
13 #include "llvm/ADT/SmallVector.h"
14 #include "gtest/gtest.h"
20 template <int> struct Shadow
;
23 : llvm::iterator_facade_base
<WeirdIter
, std::input_iterator_tag
, Shadow
<0>,
24 Shadow
<1>, Shadow
<2>, Shadow
<3>> {};
26 struct AdaptedIter
: iterator_adaptor_base
<AdaptedIter
, WeirdIter
> {};
28 // Test that iterator_adaptor_base forwards typedefs, if value_type is
30 static_assert(std::is_same
<typename
AdaptedIter::value_type
, Shadow
<0>>::value
,
33 std::is_same
<typename
AdaptedIter::difference_type
, Shadow
<1>>::value
, "");
34 static_assert(std::is_same
<typename
AdaptedIter::pointer
, Shadow
<2>>::value
,
36 static_assert(std::is_same
<typename
AdaptedIter::reference
, Shadow
<3>>::value
,
39 // Ensure that pointe{e,r}_iterator adaptors correctly forward the category of
40 // the underlying iterator.
42 using RandomAccessIter
= SmallVectorImpl
<int*>::iterator
;
43 using BidiIter
= ilist
<int*>::iterator
;
46 using pointee_iterator_defaulted
= pointee_iterator
<T
>;
48 using pointer_iterator_defaulted
= pointer_iterator
<T
>;
50 // Ensures that an iterator and its adaptation have the same iterator_category.
51 template<template<typename
> class A
, typename It
>
52 using IsAdaptedIterCategorySame
=
53 std::is_same
<typename
std::iterator_traits
<It
>::iterator_category
,
54 typename
std::iterator_traits
<A
<It
>>::iterator_category
>;
56 // Check that dereferencing works correctly adapting pointers and proxies.
58 struct PointerWrapper
: public iterator_adaptor_base
<PointerWrapper
<T
>, T
*> {
59 PointerWrapper(T
*I
) : PointerWrapper::iterator_adaptor_base(I
) {}
63 IntProxy(int &I
) : I(I
) {}
64 void operator=(int NewValue
) { I
= NewValue
; }
66 struct ConstIntProxy
{
68 ConstIntProxy(const int &I
) : I(I
) {}
70 template <class T
, class ProxyT
>
71 struct PointerProxyWrapper
72 : public iterator_adaptor_base
<PointerProxyWrapper
<T
, ProxyT
>, T
*,
73 std::random_access_iterator_tag
, T
,
74 ptrdiff_t, T
*, ProxyT
> {
75 PointerProxyWrapper(T
*I
) : PointerProxyWrapper::iterator_adaptor_base(I
) {}
77 using IntIterator
= PointerWrapper
<int>;
78 using ConstIntIterator
= PointerWrapper
<const int>;
79 using IntProxyIterator
= PointerProxyWrapper
<int, IntProxy
>;
80 using ConstIntProxyIterator
= PointerProxyWrapper
<const int, ConstIntProxy
>;
82 // There should only be a single (const-qualified) operator*, operator->, and
83 // operator[]. This test confirms that there isn't a non-const overload. Rather
84 // than adding those, users should double-check that T, PointerT, and ReferenceT
85 // have the right constness, and/or make fields mutable.
86 static_assert(&IntIterator::operator* == &IntIterator::operator*, "");
87 static_assert(&IntIterator::operator-> == &IntIterator::operator->, "");
88 static_assert(&IntIterator::operator[] == &IntIterator::operator[], "");
91 std::enable_if_t
<std::is_assignable
<T
, int>::value
, bool> = false>
92 constexpr bool canAssignFromInt(T
&&) {
96 std::enable_if_t
<!std::is_assignable
<T
, int>::value
, bool> = false>
97 constexpr bool canAssignFromInt(T
&&) {
101 TEST(IteratorAdaptorTest
, Dereference
) {
104 // Construct some iterators and check whether they can be assigned to.
105 IntIterator
I(&Number
);
106 const IntIterator
IC(&Number
);
107 ConstIntIterator
CI(&Number
);
108 const ConstIntIterator
CIC(&Number
);
109 EXPECT_EQ(true, canAssignFromInt(*I
)); // int *
110 EXPECT_EQ(true, canAssignFromInt(*IC
)); // int *const
111 EXPECT_EQ(false, canAssignFromInt(*CI
)); // const int *
112 EXPECT_EQ(false, canAssignFromInt(*CIC
)); // const int *const
114 // Prove that dereference and assignment work.
120 EXPECT_EQ(2, Number
);
122 EXPECT_EQ(3, Number
);
124 // Construct some proxy iterators and check whether they can be assigned to.
125 IntProxyIterator
P(&Number
);
126 const IntProxyIterator
PC(&Number
);
127 ConstIntProxyIterator
CP(&Number
);
128 const ConstIntProxyIterator
CPC(&Number
);
129 EXPECT_EQ(true, canAssignFromInt(*P
)); // int *
130 EXPECT_EQ(true, canAssignFromInt(*PC
)); // int *const
131 EXPECT_EQ(false, canAssignFromInt(*CP
)); // const int *
132 EXPECT_EQ(false, canAssignFromInt(*CPC
)); // const int *const
134 // Prove that dereference and assignment work.
135 EXPECT_EQ(3, (*P
).I
);
136 EXPECT_EQ(3, (*PC
).I
);
137 EXPECT_EQ(3, (*CP
).I
);
138 EXPECT_EQ(3, (*CPC
).I
);
140 EXPECT_EQ(4, Number
);
142 EXPECT_EQ(5, Number
);
146 static_assert(IsAdaptedIterCategorySame
<pointee_iterator_defaulted
,
147 RandomAccessIter
>::value
, "");
148 static_assert(IsAdaptedIterCategorySame
<pointee_iterator_defaulted
,
149 BidiIter
>::value
, "");
151 static_assert(IsAdaptedIterCategorySame
<pointer_iterator_defaulted
,
152 RandomAccessIter
>::value
, "");
153 static_assert(IsAdaptedIterCategorySame
<pointer_iterator_defaulted
,
154 BidiIter
>::value
, "");
156 TEST(PointeeIteratorTest
, Basic
) {
157 int arr
[4] = {1, 2, 3, 4};
158 SmallVector
<int *, 4> V
;
159 V
.push_back(&arr
[0]);
160 V
.push_back(&arr
[1]);
161 V
.push_back(&arr
[2]);
162 V
.push_back(&arr
[3]);
164 typedef pointee_iterator
<SmallVectorImpl
<int *>::const_iterator
>
167 test_iterator Begin
, End
;
169 End
= test_iterator(V
.end());
171 test_iterator I
= Begin
;
172 for (int i
= 0; i
< 4; ++i
) {
173 EXPECT_EQ(*V
[i
], *I
);
175 EXPECT_EQ(I
, Begin
+ i
);
176 EXPECT_EQ(I
, std::next(Begin
, i
));
177 test_iterator J
= Begin
;
180 EXPECT_EQ(*V
[i
], Begin
[i
]);
188 EXPECT_EQ(i
, I
- Begin
);
189 EXPECT_EQ(i
, std::distance(Begin
, I
));
190 EXPECT_EQ(Begin
, I
- i
);
192 test_iterator K
= I
++;
193 EXPECT_EQ(K
, std::prev(I
));
198 TEST(PointeeIteratorTest
, SmartPointer
) {
199 SmallVector
<std::unique_ptr
<int>, 4> V
;
200 V
.push_back(std::make_unique
<int>(1));
201 V
.push_back(std::make_unique
<int>(2));
202 V
.push_back(std::make_unique
<int>(3));
203 V
.push_back(std::make_unique
<int>(4));
205 typedef pointee_iterator
<
206 SmallVectorImpl
<std::unique_ptr
<int>>::const_iterator
>
209 test_iterator Begin
, End
;
211 End
= test_iterator(V
.end());
213 test_iterator I
= Begin
;
214 for (int i
= 0; i
< 4; ++i
) {
215 EXPECT_EQ(*V
[i
], *I
);
217 EXPECT_EQ(I
, Begin
+ i
);
218 EXPECT_EQ(I
, std::next(Begin
, i
));
219 test_iterator J
= Begin
;
222 EXPECT_EQ(*V
[i
], Begin
[i
]);
230 EXPECT_EQ(i
, I
- Begin
);
231 EXPECT_EQ(i
, std::distance(Begin
, I
));
232 EXPECT_EQ(Begin
, I
- i
);
234 test_iterator K
= I
++;
235 EXPECT_EQ(K
, std::prev(I
));
240 TEST(PointeeIteratorTest
, Range
) {
241 int A
[] = {1, 2, 3, 4};
242 SmallVector
<int *, 4> V
{&A
[0], &A
[1], &A
[2], &A
[3]};
245 for (int II
: make_pointee_range(V
))
246 EXPECT_EQ(A
[I
++], II
);
249 TEST(PointeeIteratorTest
, PointeeType
) {
252 bool operator==(const S
&RHS
) const { return X
== RHS
.X
; };
254 S A
[] = {S
{0}, S
{1}};
255 SmallVector
<S
*, 2> V
{&A
[0], &A
[1]};
257 pointee_iterator
<SmallVectorImpl
<S
*>::const_iterator
, const S
> I
= V
.begin();
258 for (int j
= 0; j
< 2; ++j
, ++I
) {
259 EXPECT_EQ(*V
[j
], *I
);
263 TEST(FilterIteratorTest
, Lambda
) {
264 auto IsOdd
= [](int N
) { return N
% 2 == 1; };
265 int A
[] = {0, 1, 2, 3, 4, 5, 6};
266 auto Range
= make_filter_range(A
, IsOdd
);
267 SmallVector
<int, 3> Actual(Range
.begin(), Range
.end());
268 EXPECT_EQ((SmallVector
<int, 3>{1, 3, 5}), Actual
);
271 TEST(FilterIteratorTest
, Enumerate
) {
272 auto IsOdd
= [](auto N
) { return N
.value() % 2 == 1; };
273 int A
[] = {0, 1, 2, 3, 4, 5, 6};
274 auto Enumerate
= llvm::enumerate(A
);
275 SmallVector
<int> Actual
;
276 for (auto IndexedValue
: make_filter_range(Enumerate
, IsOdd
))
277 Actual
.push_back(IndexedValue
.value());
278 EXPECT_EQ((SmallVector
<int, 3>{1, 3, 5}), Actual
);
281 TEST(FilterIteratorTest
, CallableObject
) {
286 Callable(int &Counter
) : Counter(Counter
) {}
288 bool operator()(int N
) {
293 Callable
IsOdd(Counter
);
294 int A
[] = {0, 1, 2, 3, 4, 5, 6};
295 auto Range
= make_filter_range(A
, IsOdd
);
296 EXPECT_EQ(2, Counter
);
297 SmallVector
<int, 3> Actual(Range
.begin(), Range
.end());
298 EXPECT_GE(Counter
, 7);
299 EXPECT_EQ((SmallVector
<int, 3>{1, 3, 5}), Actual
);
302 TEST(FilterIteratorTest
, FunctionPointer
) {
303 bool (*IsOdd
)(int) = [](int N
) { return N
% 2 == 1; };
304 int A
[] = {0, 1, 2, 3, 4, 5, 6};
305 auto Range
= make_filter_range(A
, IsOdd
);
306 SmallVector
<int, 3> Actual(Range
.begin(), Range
.end());
307 EXPECT_EQ((SmallVector
<int, 3>{1, 3, 5}), Actual
);
310 TEST(FilterIteratorTest
, Composition
) {
311 auto IsOdd
= [](int N
) { return N
% 2 == 1; };
312 std::unique_ptr
<int> A
[] = {std::make_unique
<int>(0), std::make_unique
<int>(1),
313 std::make_unique
<int>(2), std::make_unique
<int>(3),
314 std::make_unique
<int>(4), std::make_unique
<int>(5),
315 std::make_unique
<int>(6)};
316 using PointeeIterator
= pointee_iterator
<std::unique_ptr
<int> *>;
317 auto Range
= make_filter_range(
318 make_range(PointeeIterator(std::begin(A
)), PointeeIterator(std::end(A
))),
320 SmallVector
<int, 3> Actual(Range
.begin(), Range
.end());
321 EXPECT_EQ((SmallVector
<int, 3>{1, 3, 5}), Actual
);
324 TEST(FilterIteratorTest
, InputIterator
) {
326 : iterator_adaptor_base
<InputIterator
, int *, std::input_iterator_tag
> {
327 InputIterator(int *It
) : InputIterator::iterator_adaptor_base(It
) {}
330 auto IsOdd
= [](int N
) { return N
% 2 == 1; };
331 int A
[] = {0, 1, 2, 3, 4, 5, 6};
332 auto Range
= make_filter_range(
333 make_range(InputIterator(std::begin(A
)), InputIterator(std::end(A
))),
335 SmallVector
<int, 3> Actual(Range
.begin(), Range
.end());
336 EXPECT_EQ((SmallVector
<int, 3>{1, 3, 5}), Actual
);
339 TEST(FilterIteratorTest
, ReverseFilterRange
) {
340 auto IsOdd
= [](int N
) { return N
% 2 == 1; };
341 int A
[] = {0, 1, 2, 3, 4, 5, 6};
343 // Check basic reversal.
344 auto Range
= reverse(make_filter_range(A
, IsOdd
));
345 SmallVector
<int, 3> Actual(Range
.begin(), Range
.end());
346 EXPECT_EQ((SmallVector
<int, 3>{5, 3, 1}), Actual
);
348 // Check that the reverse of the reverse is the original.
349 auto Range2
= reverse(reverse(make_filter_range(A
, IsOdd
)));
350 SmallVector
<int, 3> Actual2(Range2
.begin(), Range2
.end());
351 EXPECT_EQ((SmallVector
<int, 3>{1, 3, 5}), Actual2
);
353 // Check empty ranges.
354 auto Range3
= reverse(make_filter_range(ArrayRef
<int>(), IsOdd
));
355 SmallVector
<int, 0> Actual3(Range3
.begin(), Range3
.end());
356 EXPECT_EQ((SmallVector
<int, 0>{}), Actual3
);
358 // Check that we don't skip the first element, provided it isn't filtered
360 auto IsEven
= [](int N
) { return N
% 2 == 0; };
361 auto Range4
= reverse(make_filter_range(A
, IsEven
));
362 SmallVector
<int, 4> Actual4(Range4
.begin(), Range4
.end());
363 EXPECT_EQ((SmallVector
<int, 4>{6, 4, 2, 0}), Actual4
);
366 TEST(PointerIterator
, Basic
) {
367 int A
[] = {1, 2, 3, 4};
368 pointer_iterator
<int *> Begin(std::begin(A
)), End(std::end(A
));
369 EXPECT_EQ(A
, *Begin
);
371 EXPECT_EQ(A
+ 1, *Begin
);
373 EXPECT_EQ(A
+ 2, *Begin
);
375 EXPECT_EQ(A
+ 3, *Begin
);
377 EXPECT_EQ(Begin
, End
);
380 TEST(PointerIterator
, Const
) {
381 int A
[] = {1, 2, 3, 4};
382 const pointer_iterator
<int *> Begin(std::begin(A
));
383 EXPECT_EQ(A
, *Begin
);
384 EXPECT_EQ(A
+ 1, std::next(*Begin
, 1));
385 EXPECT_EQ(A
+ 2, std::next(*Begin
, 2));
386 EXPECT_EQ(A
+ 3, std::next(*Begin
, 3));
387 EXPECT_EQ(A
+ 4, std::next(*Begin
, 4));
390 TEST(PointerIterator
, Range
) {
391 int A
[] = {1, 2, 3, 4};
393 for (int *P
: make_pointer_range(A
))
394 EXPECT_EQ(A
+ I
++, P
);
397 TEST(ZipIteratorTest
, Basic
) {
399 const SmallVector
<unsigned, 6> pi
{3, 1, 4, 1, 5, 9};
400 SmallVector
<bool, 6> odd
{1, 1, 0, 1, 1, 1};
401 const char message
[] = "yynyyy\0";
403 for (auto tup
: zip(pi
, odd
, message
)) {
404 EXPECT_EQ(get
<0>(tup
) & 0x01, get
<1>(tup
));
405 EXPECT_EQ(get
<0>(tup
) & 0x01 ? 'y' : 'n', get
<2>(tup
));
409 for (auto tup
: zip(pi
, SmallVector
<bool, 0>{1, 1, 0, 1, 1})) {
410 EXPECT_EQ(get
<0>(tup
) & 0x01, get
<1>(tup
));
414 TEST(ZipIteratorTest
, ZipFirstBasic
) {
416 const SmallVector
<unsigned, 6> pi
{3, 1, 4, 1, 5, 9};
419 for (auto tup
: zip_first(SmallVector
<bool, 0>{1, 1, 0, 1}, pi
)) {
420 EXPECT_EQ(get
<0>(tup
), get
<1>(tup
) & 0x01);
424 EXPECT_EQ(iters
, 4u);
427 TEST(ZipIteratorTest
, ZipLongestBasic
) {
429 const vector
<unsigned> pi
{3, 1, 4, 1, 5, 9};
430 const vector
<StringRef
> e
{"2", "7", "1", "8"};
433 // Check left range longer than right.
434 const vector
<tuple
<Optional
<unsigned>, Optional
<StringRef
>>> expected
{
435 make_tuple(3, StringRef("2")), make_tuple(1, StringRef("7")),
436 make_tuple(4, StringRef("1")), make_tuple(1, StringRef("8")),
437 make_tuple(5, None
), make_tuple(9, None
)};
439 for (auto tup
: zip_longest(pi
, e
)) {
440 EXPECT_EQ(tup
, expected
[iters
]);
443 EXPECT_EQ(iters
, expected
.size());
447 // Check right range longer than left.
448 const vector
<tuple
<Optional
<StringRef
>, Optional
<unsigned>>> expected
{
449 make_tuple(StringRef("2"), 3), make_tuple(StringRef("7"), 1),
450 make_tuple(StringRef("1"), 4), make_tuple(StringRef("8"), 1),
451 make_tuple(None
, 5), make_tuple(None
, 9)};
453 for (auto tup
: zip_longest(e
, pi
)) {
454 EXPECT_EQ(tup
, expected
[iters
]);
457 EXPECT_EQ(iters
, expected
.size());
461 TEST(ZipIteratorTest
, Mutability
) {
463 const SmallVector
<unsigned, 4> pi
{3, 1, 4, 1, 5, 9};
464 char message
[] = "hello zip\0";
466 for (auto tup
: zip(pi
, message
, message
)) {
467 EXPECT_EQ(get
<1>(tup
), get
<2>(tup
));
468 get
<2>(tup
) = get
<0>(tup
) & 0x01 ? 'y' : 'n';
472 for (auto tup
: zip(message
, "yynyyyzip\0")) {
473 EXPECT_EQ(get
<0>(tup
), get
<1>(tup
));
477 TEST(ZipIteratorTest
, ZipFirstMutability
) {
479 vector
<unsigned> pi
{3, 1, 4, 1, 5, 9};
482 for (auto tup
: zip_first(SmallVector
<bool, 0>{1, 1, 0, 1}, pi
)) {
483 get
<1>(tup
) = get
<0>(tup
);
487 EXPECT_EQ(iters
, 4u);
489 for (auto tup
: zip_first(SmallVector
<bool, 0>{1, 1, 0, 1}, pi
)) {
490 EXPECT_EQ(get
<0>(tup
), get
<1>(tup
));
494 TEST(ZipIteratorTest
, Filter
) {
496 vector
<unsigned> pi
{3, 1, 4, 1, 5, 9};
499 // pi is length 6, but the zip RHS is length 7.
500 auto zipped
= zip_first(pi
, vector
<bool>{1, 1, 0, 1, 1, 1, 0});
501 for (auto tup
: make_filter_range(
502 zipped
, [](decltype(zipped
)::value_type t
) { return get
<1>(t
); })) {
503 EXPECT_EQ(get
<0>(tup
) & 0x01, get
<1>(tup
));
508 // Should have skipped pi[2].
509 EXPECT_EQ(iters
, 5u);
511 // Ensure that in-place mutation works.
512 EXPECT_TRUE(all_of(pi
, [](unsigned n
) { return (n
& 0x01) == 0; }));
515 TEST(ZipIteratorTest
, Reverse
) {
517 vector
<unsigned> ascending
{0, 1, 2, 3, 4, 5};
519 auto zipped
= zip_first(ascending
, vector
<bool>{0, 1, 0, 1, 0, 1});
521 for (auto tup
: reverse(zipped
)) {
522 // Check that this is in reverse.
523 EXPECT_LT(get
<0>(tup
), last
);
525 EXPECT_EQ(get
<0>(tup
) & 0x01, get
<1>(tup
));
528 auto odds
= [](decltype(zipped
)::value_type tup
) { return get
<1>(tup
); };
530 for (auto tup
: make_filter_range(reverse(zipped
), odds
)) {
531 EXPECT_LT(get
<0>(tup
), last
);
533 EXPECT_TRUE(get
<0>(tup
) & 0x01);
537 // Ensure that in-place mutation works.
538 EXPECT_TRUE(all_of(ascending
, [](unsigned n
) { return (n
& 0x01) == 0; }));
541 TEST(RangeTest
, Distance
) {
543 std::vector
<int> v2
{1, 2, 3};
545 EXPECT_EQ(std::distance(v1
.begin(), v1
.end()), size(v1
));
546 EXPECT_EQ(std::distance(v2
.begin(), v2
.end()), size(v2
));
549 } // anonymous namespace