1 //===- Sequence.h - Utility for producing sequences of values ---*- C++ -*-===//
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 /// \file
9 /// Provides some synthesis utilities to produce sequences of values. The names
10 /// are intentionally kept very short as they tend to occur in common and
11 /// widely used contexts.
12 ///
13 /// The `seq(A, B)` function produces a sequence of values from `A` to up to
14 /// (but not including) `B`, i.e., [`A`, `B`), that can be safely iterated over.
15 /// `seq` supports both integral (e.g., `int`, `char`, `uint32_t`) and enum
16 /// types. `seq_inclusive(A, B)` produces a sequence of values from `A` to `B`,
17 /// including `B`.
18 ///
19 /// Examples with integral types:
20 /// ```
21 /// for (int x : seq(0, 3))
22 /// outs() << x << " ";
23 /// ```
24 ///
25 /// Prints: `0 1 2 `.
26 ///
27 /// ```
28 /// for (int x : seq_inclusive(0, 3))
29 /// outs() << x << " ";
30 /// ```
31 ///
32 /// Prints: `0 1 2 3 `.
33 ///
34 /// Similar to `seq` and `seq_inclusive`, the `enum_seq` and
35 /// `enum_seq_inclusive` functions produce sequences of enum values that can be
36 /// iterated over.
37 /// To enable iteration with enum types, you need to either mark enums as safe
38 /// to iterate on by specializing `enum_iteration_traits`, or opt into
39 /// potentially unsafe iteration at every callsite by passing
40 /// `force_iteration_on_noniterable_enum`.
41 ///
42 /// Examples with enum types:
43 /// ```
44 /// namespace X {
45 /// enum class MyEnum : unsigned {A = 0, B, C};
46 /// } // namespace X
47 ///
48 /// template <> struct enum_iteration_traits<X::MyEnum> {
49 /// static contexpr bool is_iterable = true;
50 /// };
51 ///
52 /// class MyClass {
53 /// public:
54 /// enum Safe { D = 3, E, F };
55 /// enum MaybeUnsafe { G = 1, H = 2, I = 4 };
56 /// };
57 ///
58 /// template <> struct enum_iteration_traits<MyClass::Safe> {
59 /// static contexpr bool is_iterable = true;
60 /// };
61 /// ```
62 ///
63 /// ```
64 /// for (auto v : enum_seq(MyClass::Safe::D, MyClass::Safe::F))
65 /// outs() << int(v) << " ";
66 /// ```
67 ///
68 /// Prints: `3 4 `.
69 ///
70 /// ```
71 /// for (auto v : enum_seq(MyClass::MaybeUnsafe::H, MyClass::MaybeUnsafe::I,
72 /// force_iteration_on_noniterable_enum))
73 /// outs() << int(v) << " ";
74 /// ```
75 ///
76 /// Prints: `2 3 `.
77 ///
78 //===----------------------------------------------------------------------===//
79
80 #ifndef LLVM_ADT_SEQUENCE_H
81 #define LLVM_ADT_SEQUENCE_H
82
83 #include <cassert> // assert
84 #include <iterator> // std::random_access_iterator_tag
85 #include <limits> // std::numeric_limits
86 #include <type_traits> // std::is_integral, std::is_enum, std::underlying_type,
87 // std::enable_if
88
89 #include "llvm/Support/MathExtras.h" // AddOverflow / SubOverflow
90
91 namespace llvm {
92
93 // Enum traits that marks enums as safe or unsafe to iterate over.
94 // By default, enum types are *not* considered safe for iteration.
95 // To allow iteration for your enum type, provide a specialization with
96 // `is_iterable` set to `true` in the `llvm` namespace.
97 // Alternatively, you can pass the `force_iteration_on_noniterable_enum` tag
98 // to `enum_seq` or `enum_seq_inclusive`.
99 template <typename EnumT> struct enum_iteration_traits {
100 static constexpr bool is_iterable = false;
101 };
102
103 struct force_iteration_on_noniterable_enum_t {
104 explicit force_iteration_on_noniterable_enum_t() = default;
105 };
106
107 // TODO: Make this `inline` once we update to C++17 to avoid ORD violations.
108 constexpr force_iteration_on_noniterable_enum_t
109 force_iteration_on_noniterable_enum;
110
111 namespace detail {
112
113 // Returns whether a value of type U can be represented with type T.
canTypeFitValue(const U Value)114 template <typename T, typename U> bool canTypeFitValue(const U Value) {
115 const intmax_t BotT = intmax_t(std::numeric_limits<T>::min());
116 const intmax_t BotU = intmax_t(std::numeric_limits<U>::min());
117 const uintmax_t TopT = uintmax_t(std::numeric_limits<T>::max());
118 const uintmax_t TopU = uintmax_t(std::numeric_limits<U>::max());
119 return !((BotT > BotU && Value < static_cast<U>(BotT)) ||
120 (TopT < TopU && Value > static_cast<U>(TopT)));
121 }
122
123 // An integer type that asserts when:
124 // - constructed from a value that doesn't fit into intmax_t,
125 // - casted to a type that cannot hold the current value,
126 // - its internal representation overflows.
127 struct CheckedInt {
128 // Integral constructor, asserts if Value cannot be represented as intmax_t.
129 template <typename Integral, typename std::enable_if_t<
130 std::is_integral<Integral>::value, bool> = 0>
fromCheckedInt131 static CheckedInt from(Integral FromValue) {
132 if (!canTypeFitValue<intmax_t>(FromValue))
133 assertOutOfBounds();
134 CheckedInt Result;
135 Result.Value = static_cast<intmax_t>(FromValue);
136 return Result;
137 }
138
139 // Enum constructor, asserts if Value cannot be represented as intmax_t.
140 template <typename Enum,
141 typename std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
fromCheckedInt142 static CheckedInt from(Enum FromValue) {
143 using type = typename std::underlying_type<Enum>::type;
144 return from<type>(static_cast<type>(FromValue));
145 }
146
147 // Equality
148 bool operator==(const CheckedInt &O) const { return Value == O.Value; }
149 bool operator!=(const CheckedInt &O) const { return Value != O.Value; }
150
151 CheckedInt operator+(intmax_t Offset) const {
152 CheckedInt Result;
153 if (AddOverflow(Value, Offset, Result.Value))
154 assertOutOfBounds();
155 return Result;
156 }
157
158 intmax_t operator-(CheckedInt Other) const {
159 intmax_t Result;
160 if (SubOverflow(Value, Other.Value, Result))
161 assertOutOfBounds();
162 return Result;
163 }
164
165 // Convert to integral, asserts if Value cannot be represented as Integral.
166 template <typename Integral, typename std::enable_if_t<
167 std::is_integral<Integral>::value, bool> = 0>
toCheckedInt168 Integral to() const {
169 if (!canTypeFitValue<Integral>(Value))
170 assertOutOfBounds();
171 return static_cast<Integral>(Value);
172 }
173
174 // Convert to enum, asserts if Value cannot be represented as Enum's
175 // underlying type.
176 template <typename Enum,
177 typename std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
toCheckedInt178 Enum to() const {
179 using type = typename std::underlying_type<Enum>::type;
180 return Enum(to<type>());
181 }
182
183 private:
assertOutOfBoundsCheckedInt184 static void assertOutOfBounds() { assert(false && "Out of bounds"); }
185
186 intmax_t Value;
187 };
188
189 template <typename T, bool IsReverse> struct SafeIntIterator {
190 using iterator_category = std::random_access_iterator_tag;
191 using value_type = T;
192 using difference_type = intmax_t;
193 using pointer = T *;
194 using reference = T &;
195
196 // Construct from T.
SafeIntIteratorSafeIntIterator197 explicit SafeIntIterator(T Value) : SI(CheckedInt::from<T>(Value)) {}
198 // Construct from other direction.
SafeIntIteratorSafeIntIterator199 SafeIntIterator(const SafeIntIterator<T, !IsReverse> &O) : SI(O.SI) {}
200
201 // Dereference
202 value_type operator*() const { return SI.to<T>(); }
203 // Indexing
204 value_type operator[](intmax_t Offset) const { return *(*this + Offset); }
205
206 // Can be compared for equivalence using the equality/inequality operators.
207 bool operator==(const SafeIntIterator &O) const { return SI == O.SI; }
208 bool operator!=(const SafeIntIterator &O) const { return SI != O.SI; }
209 // Comparison
210 bool operator<(const SafeIntIterator &O) const { return (*this - O) < 0; }
211 bool operator>(const SafeIntIterator &O) const { return (*this - O) > 0; }
212 bool operator<=(const SafeIntIterator &O) const { return (*this - O) <= 0; }
213 bool operator>=(const SafeIntIterator &O) const { return (*this - O) >= 0; }
214
215 // Pre Increment/Decrement
216 void operator++() { offset(1); }
217 void operator--() { offset(-1); }
218
219 // Post Increment/Decrement
220 SafeIntIterator operator++(int) {
221 const auto Copy = *this;
222 ++*this;
223 return Copy;
224 }
225 SafeIntIterator operator--(int) {
226 const auto Copy = *this;
227 --*this;
228 return Copy;
229 }
230
231 // Compound assignment operators
232 void operator+=(intmax_t Offset) { offset(Offset); }
233 void operator-=(intmax_t Offset) { offset(-Offset); }
234
235 // Arithmetic
236 SafeIntIterator operator+(intmax_t Offset) const { return add(Offset); }
237 SafeIntIterator operator-(intmax_t Offset) const { return add(-Offset); }
238
239 // Difference
240 intmax_t operator-(const SafeIntIterator &O) const {
241 return IsReverse ? O.SI - SI : SI - O.SI;
242 }
243
244 private:
SafeIntIteratorSafeIntIterator245 SafeIntIterator(const CheckedInt &SI) : SI(SI) {}
246
getOffsetSafeIntIterator247 static intmax_t getOffset(intmax_t Offset) {
248 return IsReverse ? -Offset : Offset;
249 }
250
addSafeIntIterator251 CheckedInt add(intmax_t Offset) const { return SI + getOffset(Offset); }
252
offsetSafeIntIterator253 void offset(intmax_t Offset) { SI = SI + getOffset(Offset); }
254
255 CheckedInt SI;
256
257 // To allow construction from the other direction.
258 template <typename, bool> friend struct SafeIntIterator;
259 };
260
261 } // namespace detail
262
263 template <typename T> struct iota_range {
264 using value_type = T;
265 using reference = T &;
266 using const_reference = const T &;
267 using iterator = detail::SafeIntIterator<value_type, false>;
268 using const_iterator = iterator;
269 using reverse_iterator = detail::SafeIntIterator<value_type, true>;
270 using const_reverse_iterator = reverse_iterator;
271 using difference_type = intmax_t;
272 using size_type = std::size_t;
273
iota_rangeiota_range274 explicit iota_range(T Begin, T End, bool Inclusive)
275 : BeginValue(Begin), PastEndValue(End) {
276 assert(Begin <= End && "Begin must be less or equal to End.");
277 if (Inclusive)
278 ++PastEndValue;
279 }
280
sizeiota_range281 size_t size() const { return PastEndValue - BeginValue; }
emptyiota_range282 bool empty() const { return BeginValue == PastEndValue; }
283
beginiota_range284 auto begin() const { return const_iterator(BeginValue); }
endiota_range285 auto end() const { return const_iterator(PastEndValue); }
286
rbeginiota_range287 auto rbegin() const { return const_reverse_iterator(PastEndValue - 1); }
rendiota_range288 auto rend() const { return const_reverse_iterator(BeginValue - 1); }
289
290 private:
291 static_assert(std::is_integral<T>::value || std::is_enum<T>::value,
292 "T must be an integral or enum type");
293 static_assert(std::is_same<T, std::remove_cv_t<T>>::value,
294 "T must not be const nor volatile");
295
296 iterator BeginValue;
297 iterator PastEndValue;
298 };
299
300 /// Iterate over an integral type from Begin up to - but not including - End.
301 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
302 /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
303 /// iteration).
304 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
305 !std::is_enum<T>::value>>
seq(T Begin,T End)306 auto seq(T Begin, T End) {
307 return iota_range<T>(Begin, End, false);
308 }
309
310 /// Iterate over an integral type from Begin to End inclusive.
311 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
312 /// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
313 /// iteration).
314 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
315 !std::is_enum<T>::value>>
seq_inclusive(T Begin,T End)316 auto seq_inclusive(T Begin, T End) {
317 return iota_range<T>(Begin, End, true);
318 }
319
320 /// Iterate over an enum type from Begin up to - but not including - End.
321 /// Note: `enum_seq` will generate each consecutive value, even if no
322 /// enumerator with that value exists.
323 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
324 /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
325 /// iteration).
326 template <typename EnumT,
327 typename = std::enable_if_t<std::is_enum<EnumT>::value>>
enum_seq(EnumT Begin,EnumT End)328 auto enum_seq(EnumT Begin, EnumT End) {
329 static_assert(enum_iteration_traits<EnumT>::is_iterable,
330 "Enum type is not marked as iterable.");
331 return iota_range<EnumT>(Begin, End, false);
332 }
333
334 /// Iterate over an enum type from Begin up to - but not including - End, even
335 /// when `EnumT` is not marked as safely iterable by `enum_iteration_traits`.
336 /// Note: `enum_seq` will generate each consecutive value, even if no
337 /// enumerator with that value exists.
338 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
339 /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
340 /// iteration).
341 template <typename EnumT,
342 typename = std::enable_if_t<std::is_enum<EnumT>::value>>
enum_seq(EnumT Begin,EnumT End,force_iteration_on_noniterable_enum_t)343 auto enum_seq(EnumT Begin, EnumT End, force_iteration_on_noniterable_enum_t) {
344 return iota_range<EnumT>(Begin, End, false);
345 }
346
347 /// Iterate over an enum type from Begin to End inclusive.
348 /// Note: `enum_seq_inclusive` will generate each consecutive value, even if no
349 /// enumerator with that value exists.
350 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
351 /// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
352 /// iteration).
353 template <typename EnumT,
354 typename = std::enable_if_t<std::is_enum<EnumT>::value>>
enum_seq_inclusive(EnumT Begin,EnumT End)355 auto enum_seq_inclusive(EnumT Begin, EnumT End) {
356 static_assert(enum_iteration_traits<EnumT>::is_iterable,
357 "Enum type is not marked as iterable.");
358 return iota_range<EnumT>(Begin, End, true);
359 }
360
361 /// Iterate over an enum type from Begin to End inclusive, even when `EnumT`
362 /// is not marked as safely iterable by `enum_iteration_traits`.
363 /// Note: `enum_seq_inclusive` will generate each consecutive value, even if no
364 /// enumerator with that value exists.
365 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
366 /// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
367 /// iteration).
368 template <typename EnumT,
369 typename = std::enable_if_t<std::is_enum<EnumT>::value>>
enum_seq_inclusive(EnumT Begin,EnumT End,force_iteration_on_noniterable_enum_t)370 auto enum_seq_inclusive(EnumT Begin, EnumT End,
371 force_iteration_on_noniterable_enum_t) {
372 return iota_range<EnumT>(Begin, End, true);
373 }
374
375 } // end namespace llvm
376
377 #endif // LLVM_ADT_SEQUENCE_H
378