1 //===- RangeAdapterTest.cpp - Unit tests for range adapters --------------===//
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 #include <iterator>
13 #include <list>
14 #include <vector>
15
16 using namespace llvm;
17
18 namespace {
19
20 // A wrapper around vector which exposes rbegin(), rend().
21 class ReverseOnlyVector {
22 std::vector<int> Vec;
23
24 public:
ReverseOnlyVector(std::initializer_list<int> list)25 ReverseOnlyVector(std::initializer_list<int> list) : Vec(list) {}
26
27 typedef std::vector<int>::reverse_iterator reverse_iterator;
28 typedef std::vector<int>::const_reverse_iterator const_reverse_iterator;
rbegin()29 reverse_iterator rbegin() { return Vec.rbegin(); }
rend()30 reverse_iterator rend() { return Vec.rend(); }
rbegin() const31 const_reverse_iterator rbegin() const { return Vec.rbegin(); }
rend() const32 const_reverse_iterator rend() const { return Vec.rend(); }
33 };
34
35 // A wrapper around vector which exposes begin(), end(), rbegin() and rend().
36 // begin() and end() don't have implementations as this ensures that we will
37 // get a linker error if reverse() chooses begin()/end() over rbegin(), rend().
38 class BidirectionalVector {
39 mutable std::vector<int> Vec;
40
41 public:
BidirectionalVector(std::initializer_list<int> list)42 BidirectionalVector(std::initializer_list<int> list) : Vec(list) {}
43
44 typedef std::vector<int>::iterator iterator;
45 iterator begin() const;
46 iterator end() const;
47
48 typedef std::vector<int>::reverse_iterator reverse_iterator;
rbegin() const49 reverse_iterator rbegin() const { return Vec.rbegin(); }
rend() const50 reverse_iterator rend() const { return Vec.rend(); }
51 };
52
53 /// This is the same as BidirectionalVector but with the addition of const
54 /// begin/rbegin methods to ensure that the type traits for has_rbegin works.
55 class BidirectionalVectorConsts {
56 std::vector<int> Vec;
57
58 public:
BidirectionalVectorConsts(std::initializer_list<int> list)59 BidirectionalVectorConsts(std::initializer_list<int> list) : Vec(list) {}
60
61 typedef std::vector<int>::iterator iterator;
62 typedef std::vector<int>::const_iterator const_iterator;
63 iterator begin();
64 iterator end();
65 const_iterator begin() const;
66 const_iterator end() const;
67
68 typedef std::vector<int>::reverse_iterator reverse_iterator;
69 typedef std::vector<int>::const_reverse_iterator const_reverse_iterator;
rbegin()70 reverse_iterator rbegin() { return Vec.rbegin(); }
rend()71 reverse_iterator rend() { return Vec.rend(); }
rbegin() const72 const_reverse_iterator rbegin() const { return Vec.rbegin(); }
rend() const73 const_reverse_iterator rend() const { return Vec.rend(); }
74 };
75
76 /// Check that types with custom iterators work.
77 class CustomIteratorVector {
78 mutable std::vector<int> V;
79
80 public:
CustomIteratorVector(std::initializer_list<int> list)81 CustomIteratorVector(std::initializer_list<int> list) : V(list) {}
82
83 typedef std::vector<int>::iterator iterator;
84 class reverse_iterator {
85 std::vector<int>::iterator I;
86
87 public:
88 reverse_iterator() = default;
89 reverse_iterator(const reverse_iterator &) = default;
90 reverse_iterator &operator=(const reverse_iterator &) = default;
91
reverse_iterator(std::vector<int>::iterator I)92 explicit reverse_iterator(std::vector<int>::iterator I) : I(I) {}
93
operator ++()94 reverse_iterator &operator++() {
95 --I;
96 return *this;
97 }
operator --()98 reverse_iterator &operator--() {
99 ++I;
100 return *this;
101 }
operator *() const102 int &operator*() const { return *std::prev(I); }
operator ->() const103 int *operator->() const { return &*std::prev(I); }
operator ==(const reverse_iterator & L,const reverse_iterator & R)104 friend bool operator==(const reverse_iterator &L,
105 const reverse_iterator &R) {
106 return L.I == R.I;
107 }
operator !=(const reverse_iterator & L,const reverse_iterator & R)108 friend bool operator!=(const reverse_iterator &L,
109 const reverse_iterator &R) {
110 return !(L == R);
111 }
112 };
113
begin() const114 iterator begin() const { return V.begin(); }
end() const115 iterator end() const { return V.end(); }
rbegin() const116 reverse_iterator rbegin() const { return reverse_iterator(V.end()); }
rend() const117 reverse_iterator rend() const { return reverse_iterator(V.begin()); }
118 };
119
TestRev(const R & r)120 template <typename R> void TestRev(const R &r) {
121 int counter = 3;
122 for (int i : r)
123 EXPECT_EQ(i, counter--);
124 }
125
126 // Test fixture
127 template <typename T> class RangeAdapterLValueTest : public ::testing::Test {};
128
129 typedef ::testing::Types<std::vector<int>, std::list<int>, int[4]>
130 RangeAdapterLValueTestTypes;
131 TYPED_TEST_SUITE(RangeAdapterLValueTest, RangeAdapterLValueTestTypes, );
132
TYPED_TEST(RangeAdapterLValueTest,TrivialOperation)133 TYPED_TEST(RangeAdapterLValueTest, TrivialOperation) {
134 TypeParam v = {0, 1, 2, 3};
135 TestRev(reverse(v));
136
137 const TypeParam c = {0, 1, 2, 3};
138 TestRev(reverse(c));
139 }
140
141 template <typename T> struct RangeAdapterRValueTest : testing::Test {};
142
143 typedef ::testing::Types<std::vector<int>, std::list<int>, CustomIteratorVector,
144 ReverseOnlyVector, BidirectionalVector,
145 BidirectionalVectorConsts>
146 RangeAdapterRValueTestTypes;
147 TYPED_TEST_SUITE(RangeAdapterRValueTest, RangeAdapterRValueTestTypes, );
148
TYPED_TEST(RangeAdapterRValueTest,TrivialOperation)149 TYPED_TEST(RangeAdapterRValueTest, TrivialOperation) {
150 TestRev(reverse(TypeParam({0, 1, 2, 3})));
151 }
152
TYPED_TEST(RangeAdapterRValueTest,RangeType)153 TYPED_TEST(RangeAdapterRValueTest, RangeType) {
154 static_assert(
155 std::is_same_v<decltype(reverse(std::declval<TypeParam>()).begin()),
156 decltype(std::declval<TypeParam>().rbegin())>,
157 "reverse().begin() should have the same type as rbegin()");
158 static_assert(
159 std::is_same_v<decltype(reverse(std::declval<const TypeParam>()).begin()),
160 decltype(std::declval<const TypeParam>().rbegin())>,
161 "reverse().begin() should have the same type as rbegin() [const]");
162 }
163
164 } // anonymous namespace
165