xref: /llvm-project/llvm/unittests/ADT/SequenceTest.cpp (revision bff3682e9ede6c317bbfb666e64a7d4927ba9055)
1 //===- SequenceTest.cpp - Unit tests for a sequence abstraciton -----------===//
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/Sequence.h"
10 #include "llvm/ADT/STLExtras.h"
11 #include "gmock/gmock.h"
12 #include "gtest/gtest.h"
13 
14 #include <algorithm>
15 #include <numeric>
16 
17 using namespace llvm;
18 
19 using testing::ElementsAre;
20 using testing::IsEmpty;
21 
22 namespace {
23 
24 using detail::canTypeFitValue;
25 using detail::CheckedInt;
26 
27 using IntegralTypes = testing::Types<uint8_t,   // 0
28                                      uint16_t,  // 1
29                                      uint32_t,  // 2
30                                      uint64_t,  // 3
31                                      uintmax_t, // 4
32                                      int8_t,    // 5
33                                      int16_t,   // 6
34                                      int32_t,   // 7
35                                      int64_t,   // 8
36                                      intmax_t   // 9
37                                      >;
38 
39 template <class T> class StrongIntTest : public testing::Test {};
40 TYPED_TEST_SUITE(StrongIntTest, IntegralTypes, );
41 TYPED_TEST(StrongIntTest, Operations) {
42   using T = TypeParam;
43   auto Max = std::numeric_limits<T>::max();
44   auto Min = std::numeric_limits<T>::min();
45 
46   // We bail out for types that are not entirely representable within intmax_t.
47   if (!canTypeFitValue<intmax_t>(Max) || !canTypeFitValue<intmax_t>(Min))
48     return;
49 
50   // All representable values convert back and forth.
51   EXPECT_EQ(CheckedInt::from(Min).template to<T>(), Min);
52   EXPECT_EQ(CheckedInt::from(Max).template to<T>(), Max);
53 
54   // Addition -2, -1, 0, 1, 2.
55   const T Expected = Max / 2;
56   const CheckedInt Actual = CheckedInt::from(Expected);
57   EXPECT_EQ((Actual + -2).template to<T>(), Expected - 2);
58   EXPECT_EQ((Actual + -1).template to<T>(), Expected - 1);
59   EXPECT_EQ((Actual + 0).template to<T>(), Expected);
60   EXPECT_EQ((Actual + 1).template to<T>(), Expected + 1);
61   EXPECT_EQ((Actual + 2).template to<T>(), Expected + 2);
62 
63   // EQ/NEQ
64   EXPECT_EQ(Actual, Actual);
65   EXPECT_NE(Actual, Actual + 1);
66 
67   // Difference
68   EXPECT_EQ(Actual - Actual, 0);
69   EXPECT_EQ((Actual + 1) - Actual, 1);
70   EXPECT_EQ(Actual - (Actual + 2), -2);
71 }
72 
73 #if defined(GTEST_HAS_DEATH_TEST) && !defined(NDEBUG)
74 TEST(StrongIntDeathTest, OutOfBounds) {
75   // Values above 'INTMAX_MAX' are not representable.
76   EXPECT_DEATH(CheckedInt::from<uintmax_t>(INTMAX_MAX + 1ULL), "Out of bounds");
77   EXPECT_DEATH(CheckedInt::from<uintmax_t>(UINTMAX_MAX), "Out of bounds");
78   // Casting to narrower type asserts when out of bounds.
79   EXPECT_DEATH(CheckedInt::from(-1).to<uint8_t>(), "Out of bounds");
80   EXPECT_DEATH(CheckedInt::from(256).to<uint8_t>(), "Out of bounds");
81   // Operations leading to intmax_t overflow assert.
82   EXPECT_DEATH(CheckedInt::from(INTMAX_MAX) + 1, "Out of bounds");
83   EXPECT_DEATH(CheckedInt::from(INTMAX_MIN) + -1, "Out of bounds");
84   EXPECT_DEATH(CheckedInt::from(INTMAX_MIN) - CheckedInt::from(INTMAX_MAX),
85                "Out of bounds");
86 }
87 #endif
88 
89 TEST(SafeIntIteratorTest, Operations) {
90   detail::SafeIntIterator<int, false> Forward(0);
91   detail::SafeIntIterator<int, true> Reverse(0);
92 
93   const auto SetToZero = [&]() {
94     Forward = detail::SafeIntIterator<int, false>(0);
95     Reverse = detail::SafeIntIterator<int, true>(0);
96   };
97 
98   // Equality / Comparisons
99   SetToZero();
100   EXPECT_EQ(Forward, Forward);
101   EXPECT_LT(Forward - 1, Forward);
102   EXPECT_LE(Forward, Forward);
103   EXPECT_LE(Forward - 1, Forward);
104   EXPECT_GT(Forward + 1, Forward);
105   EXPECT_GE(Forward, Forward);
106   EXPECT_GE(Forward + 1, Forward);
107 
108   EXPECT_EQ(Reverse, Reverse);
109   EXPECT_LT(Reverse - 1, Reverse);
110   EXPECT_LE(Reverse, Reverse);
111   EXPECT_LE(Reverse - 1, Reverse);
112   EXPECT_GT(Reverse + 1, Reverse);
113   EXPECT_GE(Reverse, Reverse);
114   EXPECT_GE(Reverse + 1, Reverse);
115 
116   // Dereference
117   SetToZero();
118   EXPECT_EQ(*Forward, 0);
119   EXPECT_EQ(*Reverse, 0);
120 
121   // Indexing
122   SetToZero();
123   EXPECT_EQ(Forward[2], 2);
124   EXPECT_EQ(Reverse[2], -2);
125 
126   // Pre-increment
127   SetToZero();
128   ++Forward;
129   EXPECT_EQ(*Forward, 1);
130   ++Reverse;
131   EXPECT_EQ(*Reverse, -1);
132 
133   // Pre-decrement
134   SetToZero();
135   --Forward;
136   EXPECT_EQ(*Forward, -1);
137   --Reverse;
138   EXPECT_EQ(*Reverse, 1);
139 
140   // Post-increment
141   SetToZero();
142   EXPECT_EQ(*(Forward++), 0);
143   EXPECT_EQ(*Forward, 1);
144   EXPECT_EQ(*(Reverse++), 0);
145   EXPECT_EQ(*Reverse, -1);
146 
147   // Post-decrement
148   SetToZero();
149   EXPECT_EQ(*(Forward--), 0);
150   EXPECT_EQ(*Forward, -1);
151   EXPECT_EQ(*(Reverse--), 0);
152   EXPECT_EQ(*Reverse, 1);
153 
154   // Compound assignment operators
155   SetToZero();
156   Forward += 1;
157   EXPECT_EQ(*Forward, 1);
158   Reverse += 1;
159   EXPECT_EQ(*Reverse, -1);
160   SetToZero();
161   Forward -= 2;
162   EXPECT_EQ(*Forward, -2);
163   Reverse -= 2;
164   EXPECT_EQ(*Reverse, 2);
165 
166   // Arithmetic
167   SetToZero();
168   EXPECT_EQ(*(Forward + 3), 3);
169   EXPECT_EQ(*(Reverse + 3), -3);
170   SetToZero();
171   EXPECT_EQ(*(Forward - 4), -4);
172   EXPECT_EQ(*(Reverse - 4), 4);
173 
174   // Difference
175   SetToZero();
176   EXPECT_EQ(Forward - Forward, 0);
177   EXPECT_EQ(Reverse - Reverse, 0);
178   EXPECT_EQ((Forward + 1) - Forward, 1);
179   EXPECT_EQ(Forward - (Forward + 1), -1);
180   EXPECT_EQ((Reverse + 1) - Reverse, 1);
181   EXPECT_EQ(Reverse - (Reverse + 1), -1);
182 }
183 
184 TEST(SequenceTest, Iteration) {
185   EXPECT_THAT(seq(-4, 5), ElementsAre(-4, -3, -2, -1, 0, 1, 2, 3, 4));
186   EXPECT_THAT(reverse(seq(-4, 5)), ElementsAre(4, 3, 2, 1, 0, -1, -2, -3, -4));
187 
188   EXPECT_THAT(seq_inclusive(-4, 5),
189               ElementsAre(-4, -3, -2, -1, 0, 1, 2, 3, 4, 5));
190   EXPECT_THAT(reverse(seq_inclusive(-4, 5)),
191               ElementsAre(5, 4, 3, 2, 1, 0, -1, -2, -3, -4));
192 }
193 
194 TEST(SequenceTest, Distance) {
195   const auto Forward = seq(0, 10);
196   EXPECT_EQ(std::distance(Forward.begin(), Forward.end()), 10);
197   EXPECT_EQ(std::distance(Forward.rbegin(), Forward.rend()), 10);
198 }
199 
200 TEST(SequenceTest, Dereference) {
201   const auto Forward = seq(0, 10).begin();
202   EXPECT_EQ(Forward[0], 0);
203   EXPECT_EQ(Forward[2], 2);
204   const auto Backward = seq(0, 10).rbegin();
205   EXPECT_EQ(Backward[0], 9);
206   EXPECT_EQ(Backward[2], 7);
207 }
208 
209 enum UntypedEnum { A = 3 };
210 enum TypedEnum : uint32_t { B = 3 };
211 
212 namespace X {
213 enum class ScopedEnum : uint16_t { C = 3 };
214 } // namespace X
215 
216 struct S {
217   enum NestedEnum { D = 4 };
218   enum NestedEnum2 { E = 5 };
219 
220 private:
221   enum NestedEnum3 { F = 6 };
222   friend struct llvm::enum_iteration_traits<NestedEnum3>;
223 
224 public:
225   static auto getNestedEnum3() { return NestedEnum3::F; }
226 };
227 
228 } // namespace
229 
230 namespace llvm {
231 
232 template <> struct enum_iteration_traits<UntypedEnum> {
233   static constexpr bool is_iterable = true;
234 };
235 
236 template <> struct enum_iteration_traits<TypedEnum> {
237   static constexpr bool is_iterable = true;
238 };
239 
240 template <> struct enum_iteration_traits<X::ScopedEnum> {
241   static constexpr bool is_iterable = true;
242 };
243 
244 template <> struct enum_iteration_traits<S::NestedEnum> {
245   static constexpr bool is_iterable = true;
246 };
247 
248 template <> struct enum_iteration_traits<S::NestedEnum3> {
249   static constexpr bool is_iterable = true;
250 };
251 
252 } // namespace llvm
253 
254 namespace {
255 
256 TEST(StrongIntTest, Enums) {
257   EXPECT_EQ(CheckedInt::from(A).to<UntypedEnum>(), A);
258   EXPECT_EQ(CheckedInt::from(B).to<TypedEnum>(), B);
259   EXPECT_EQ(CheckedInt::from(X::ScopedEnum::C).to<X::ScopedEnum>(),
260             X::ScopedEnum::C);
261 }
262 
263 TEST(SequenceTest, IterableEnums) {
264   EXPECT_THAT(enum_seq(UntypedEnum::A, UntypedEnum::A), IsEmpty());
265   EXPECT_THAT(enum_seq_inclusive(UntypedEnum::A, UntypedEnum::A),
266               ElementsAre(UntypedEnum::A));
267 
268   EXPECT_THAT(enum_seq(TypedEnum::B, TypedEnum::B), IsEmpty());
269   EXPECT_THAT(enum_seq_inclusive(TypedEnum::B, TypedEnum::B),
270               ElementsAre(TypedEnum::B));
271 
272   EXPECT_THAT(enum_seq(X::ScopedEnum::C, X::ScopedEnum::C), IsEmpty());
273   EXPECT_THAT(enum_seq_inclusive(X::ScopedEnum::C, X::ScopedEnum::C),
274               ElementsAre(X::ScopedEnum::C));
275 
276   EXPECT_THAT(enum_seq_inclusive(S::NestedEnum::D, S::NestedEnum::D),
277               ElementsAre(S::NestedEnum::D));
278   EXPECT_THAT(enum_seq_inclusive(S::getNestedEnum3(), S::getNestedEnum3()),
279               ElementsAre(S::getNestedEnum3()));
280 }
281 
282 TEST(SequenceTest, NonIterableEnums) {
283   EXPECT_THAT(enum_seq(S::NestedEnum2::E, S::NestedEnum2::E,
284                        force_iteration_on_noniterable_enum),
285               IsEmpty());
286   EXPECT_THAT(enum_seq_inclusive(S::NestedEnum2::E, S::NestedEnum2::E,
287                                  force_iteration_on_noniterable_enum),
288               ElementsAre(S::NestedEnum2::E));
289 
290   // Check that this also works with enums marked as iterable.
291   EXPECT_THAT(enum_seq(UntypedEnum::A, UntypedEnum::A,
292                        force_iteration_on_noniterable_enum),
293               IsEmpty());
294   EXPECT_THAT(enum_seq_inclusive(UntypedEnum::A, UntypedEnum::A,
295                                  force_iteration_on_noniterable_enum),
296               ElementsAre(UntypedEnum::A));
297 }
298 
299 // Reproducer for https://github.com/llvm/llvm-project/issues/61122
300 TEST(SequenceTest, CorrectReferenceType) {
301   std::vector<int> vals = {1, 2, 3};
302   detail::SafeIntIterator<int, false> begin(4);
303   detail::SafeIntIterator<int, false> end(6);
304   vals.insert(vals.end(), begin, end);
305   EXPECT_THAT(vals, ElementsAre(1, 2, 3, 4, 5));
306 }
307 
308 } // namespace
309