xref: /llvm-project/llvm/unittests/ADT/RangeAdapterTest.cpp (revision c8f3d211fc428dd6075440ac22f48641436545d0)
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