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: |
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; |
29 | reverse_iterator rbegin() { return Vec.rbegin(); } |
30 | reverse_iterator rend() { return Vec.rend(); } |
31 | const_reverse_iterator rbegin() const { return Vec.rbegin(); } |
32 | 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: |
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; |
49 | reverse_iterator rbegin() const { return Vec.rbegin(); } |
50 | 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: |
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; |
70 | reverse_iterator rbegin() { return Vec.rbegin(); } |
71 | reverse_iterator rend() { return Vec.rend(); } |
72 | const_reverse_iterator rbegin() const { return Vec.rbegin(); } |
73 | 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: |
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 | |
92 | explicit reverse_iterator(std::vector<int>::iterator I) : I(I) {} |
93 | |
94 | reverse_iterator &operator++() { |
95 | --I; |
96 | return *this; |
97 | } |
98 | reverse_iterator &operator--() { |
99 | ++I; |
100 | return *this; |
101 | } |
102 | int &operator*() const { return *std::prev(x: I); } |
103 | int *operator->() const { return &*std::prev(x: I); } |
104 | friend bool operator==(const reverse_iterator &L, |
105 | const reverse_iterator &R) { |
106 | return L.I == R.I; |
107 | } |
108 | friend bool operator!=(const reverse_iterator &L, |
109 | const reverse_iterator &R) { |
110 | return !(L == R); |
111 | } |
112 | }; |
113 | |
114 | iterator begin() const { return V.begin(); } |
115 | iterator end() const { return V.end(); } |
116 | reverse_iterator rbegin() const { return reverse_iterator(V.end()); } |
117 | reverse_iterator rend() const { return reverse_iterator(V.begin()); } |
118 | }; |
119 | |
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 | |
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 | |
149 | TYPED_TEST(RangeAdapterRValueTest, TrivialOperation) { |
150 | TestRev(reverse(TypeParam({0, 1, 2, 3}))); |
151 | } |
152 | |
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 | |