LLVM 24.0.0git
Sequence.h
Go to the documentation of this file.
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/ADT/STLForwardCompat.h" // llvm::to_underlying
90#include "llvm/Support/Error.h" // llvm_unreachable
91#include "llvm/Support/MathExtras.h" // AddOverflow / SubOverflow
92
93namespace llvm {
94
95// Enum traits that marks enums as safe or unsafe to iterate over.
96// By default, enum types are *not* considered safe for iteration.
97// To allow iteration for your enum type, provide a specialization with
98// `is_iterable` set to `true` in the `llvm` namespace.
99// Alternatively, you can pass the `force_iteration_on_noniterable_enum` tag
100// to `enum_seq` or `enum_seq_inclusive`.
101template <typename EnumT> struct enum_iteration_traits {
102 static constexpr bool is_iterable = false;
103};
104
108
111
112namespace detail {
113
114// Returns whether a value of type U can be represented with type T.
115template <typename T, typename U>
116constexpr bool canTypeFitValue(const U Value) {
117 const intmax_t BotT = intmax_t(std::numeric_limits<T>::min());
118 const intmax_t BotU = intmax_t(std::numeric_limits<U>::min());
119 const uintmax_t TopT = uintmax_t(std::numeric_limits<T>::max());
120 const uintmax_t TopU = uintmax_t(std::numeric_limits<U>::max());
121 return !((BotT > BotU && Value < static_cast<U>(BotT)) ||
122 (TopT < TopU && Value > static_cast<U>(TopT)));
123}
124
125// An integer type that asserts when:
126// - constructed from a value that doesn't fit into intmax_t,
127// - casted to a type that cannot hold the current value,
128// - its internal representation overflows.
130 // Integral constructor, asserts if Value cannot be represented as intmax_t.
131 template <typename Integral,
132 std::enable_if_t<std::is_integral<Integral>::value, bool> = 0>
133 static constexpr CheckedInt from(Integral FromValue) {
134 if (!canTypeFitValue<intmax_t>(FromValue))
135 assertOutOfBounds();
136 CheckedInt Result;
137 Result.Value = static_cast<intmax_t>(FromValue);
138 return Result;
139 }
140
141 // Enum constructor, asserts if Value cannot be represented as intmax_t.
142 template <typename Enum,
143 std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
144 static constexpr CheckedInt from(Enum FromValue) {
145 return from(llvm::to_underlying(FromValue));
146 }
147
148 // Equality
149 constexpr bool operator==(const CheckedInt &O) const {
150 return Value == O.Value;
151 }
152 constexpr bool operator!=(const CheckedInt &O) const {
153 return Value != O.Value;
154 }
155
156 constexpr CheckedInt operator+(intmax_t Offset) const {
157 auto [Result, Overflow] = AddOverflow(Value, Offset);
158 if (Overflow)
159 assertOutOfBounds();
160 return CheckedInt::from(Result);
161 }
162
163 constexpr intmax_t operator-(CheckedInt Other) const {
164 auto [Result, Overflow] = SubOverflow(Value, Other.Value);
165 if (Overflow)
166 assertOutOfBounds();
167 return Result;
168 }
169
170 // Convert to integral, asserts if Value cannot be represented as Integral.
171 template <typename Integral,
172 std::enable_if_t<std::is_integral<Integral>::value, bool> = 0>
173 constexpr Integral to() const {
174 if (!canTypeFitValue<Integral>(Value))
175 assertOutOfBounds();
176 return static_cast<Integral>(Value);
177 }
178
179 // Convert to enum, asserts if Value cannot be represented as Enum's
180 // underlying type.
181 template <typename Enum,
182 std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
183 constexpr Enum to() const {
184 using type = std::underlying_type_t<Enum>;
185 return Enum(to<type>());
186 }
187
188private:
189#ifndef NDEBUG
190 [[noreturn]] static void assertOutOfBounds() {
191 llvm_unreachable("Out of bounds");
192 }
193#else
194 static constexpr void assertOutOfBounds() {}
195#endif
196
197 intmax_t Value = 0;
198};
199
200template <typename T, bool IsReverse> struct SafeIntIterator {
201 using iterator_category = std::random_access_iterator_tag;
202 using value_type = T;
203 using difference_type = intmax_t;
204 using pointer = T *;
205 using reference = value_type; // The iterator does not reference memory.
206
207 // Construct from T.
208 explicit constexpr SafeIntIterator(T Value)
209 : SI(CheckedInt::from<T>(Value)) {}
210 // Construct from other direction.
212 : SI(O.SI) {}
213
214 // Dereference
215 constexpr reference operator*() const { return SI.to<T>(); }
216 // Indexing
217 constexpr reference operator[](intmax_t Offset) const {
218 return *(*this + Offset);
219 }
220
221 // Can be compared for equivalence using the equality/inequality operators.
222 constexpr bool operator==(const SafeIntIterator &O) const {
223 return SI == O.SI;
224 }
225 constexpr bool operator!=(const SafeIntIterator &O) const {
226 return SI != O.SI;
227 }
228 // Comparison
229 constexpr bool operator<(const SafeIntIterator &O) const {
230 return (*this - O) < 0;
231 }
232 constexpr bool operator>(const SafeIntIterator &O) const {
233 return (*this - O) > 0;
234 }
235 constexpr bool operator<=(const SafeIntIterator &O) const {
236 return (*this - O) <= 0;
237 }
238 constexpr bool operator>=(const SafeIntIterator &O) const {
239 return (*this - O) >= 0;
240 }
241
242 // Pre Increment/Decrement
243 constexpr void operator++() { offset(1); }
244 constexpr void operator--() { offset(-1); }
245
246 // Post Increment/Decrement
248 const auto Copy = *this;
249 ++*this;
250 return Copy;
251 }
253 const auto Copy = *this;
254 --*this;
255 return Copy;
256 }
257
258 // Compound assignment operators
259 constexpr void operator+=(intmax_t Offset) { offset(Offset); }
260 constexpr void operator-=(intmax_t Offset) { offset(-Offset); }
261
262 // Arithmetic
263 constexpr SafeIntIterator operator+(intmax_t Offset) const {
264 return add(Offset);
265 }
266 constexpr SafeIntIterator operator-(intmax_t Offset) const {
267 return add(-Offset);
268 }
269
270 // Difference
271 constexpr intmax_t operator-(const SafeIntIterator &O) const {
272 return IsReverse ? O.SI - SI : SI - O.SI;
273 }
274
275private:
276 constexpr SafeIntIterator(const CheckedInt &SI) : SI(SI) {}
277
278 static constexpr intmax_t getOffset(intmax_t Offset) {
279 return IsReverse ? -Offset : Offset;
280 }
281
282 constexpr CheckedInt add(intmax_t Offset) const {
283 return SI + getOffset(Offset);
284 }
285
286 constexpr void offset(intmax_t Offset) { SI = SI + getOffset(Offset); }
287
288 CheckedInt SI;
289
290 // To allow construction from the other direction.
291 template <typename, bool> friend struct SafeIntIterator;
292};
293
294} // namespace detail
295
296template <typename T> struct iota_range {
297 using value_type = T;
298 using reference = T &;
299 using const_reference = const T &;
304 using difference_type = intmax_t;
305 using size_type = std::size_t;
306
307 explicit constexpr iota_range(T Begin, T End, bool Inclusive)
308 : BeginValue(Begin), PastEndValue(End) {
309 assert(Begin <= End && "Begin must be less or equal to End.");
310 if (Inclusive)
311 ++PastEndValue;
312 }
313
314 constexpr size_t size() const { return PastEndValue - BeginValue; }
315 constexpr bool empty() const { return BeginValue == PastEndValue; }
316
317 constexpr auto begin() const { return const_iterator(BeginValue); }
318 constexpr auto end() const { return const_iterator(PastEndValue); }
319
320 constexpr auto rbegin() const {
321 return const_reverse_iterator(PastEndValue - 1);
322 }
323 constexpr auto rend() const { return const_reverse_iterator(BeginValue - 1); }
324
325private:
326 static_assert(std::is_integral<T>::value || std::is_enum<T>::value,
327 "T must be an integral or enum type");
328 static_assert(std::is_same<T, std::remove_cv_t<T>>::value,
329 "T must not be const nor volatile");
330
331 iterator BeginValue;
332 iterator PastEndValue;
333};
334
335/// Iterate over an integral type from Begin up to - but not including - End.
336/// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
337/// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
338/// iteration).
339template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
340 !std::is_enum<T>::value>>
341constexpr auto seq(T Begin, T End) {
342 return iota_range<T>(Begin, End, false);
343}
344
345/// Iterate over an integral type from 0 up to - but not including - Size.
346/// Note: Size value has to be within [INTMAX_MIN, INTMAX_MAX - 1] for
347/// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
348/// iteration).
349template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
350 !std::is_enum<T>::value>>
351constexpr auto seq(T Size) {
352 return seq<T>(0, Size);
353}
354
355/// Iterate over an integral type from Begin to End inclusive.
356/// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
357/// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
358/// iteration).
359template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
360 !std::is_enum<T>::value>>
361constexpr auto seq_inclusive(T Begin, T End) {
362 return iota_range<T>(Begin, End, true);
363}
364
365/// Iterate over an enum type from Begin up to - but not including - End.
366/// Note: `enum_seq` will generate each consecutive value, even if no
367/// enumerator with that value exists.
368/// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
369/// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
370/// iteration).
371template <typename EnumT,
372 typename = std::enable_if_t<std::is_enum<EnumT>::value>>
373constexpr auto enum_seq(EnumT Begin, EnumT End) {
375 "Enum type is not marked as iterable.");
376 return iota_range<EnumT>(Begin, End, false);
377}
378
379/// Iterate over an enum type from Begin up to - but not including - End, even
380/// when `EnumT` is not marked as safely iterable by `enum_iteration_traits`.
381/// Note: `enum_seq` will generate each consecutive value, even if no
382/// enumerator with that value exists.
383/// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
384/// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
385/// iteration).
386template <typename EnumT,
387 typename = std::enable_if_t<std::is_enum<EnumT>::value>>
388constexpr auto enum_seq(EnumT Begin, EnumT End,
390 return iota_range<EnumT>(Begin, End, false);
391}
392
393/// Iterate over an enum type from Begin to End inclusive.
394/// Note: `enum_seq_inclusive` will generate each consecutive value, even if no
395/// enumerator with that value exists.
396/// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
397/// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
398/// iteration).
399template <typename EnumT,
400 typename = std::enable_if_t<std::is_enum<EnumT>::value>>
401constexpr auto enum_seq_inclusive(EnumT Begin, EnumT End) {
403 "Enum type is not marked as iterable.");
404 return iota_range<EnumT>(Begin, End, true);
405}
406
407/// Iterate over an enum type from Begin to End inclusive, even when `EnumT`
408/// is not marked as safely iterable by `enum_iteration_traits`.
409/// Note: `enum_seq_inclusive` will generate each consecutive value, even if no
410/// enumerator with that value exists.
411/// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
412/// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
413/// iteration).
414template <typename EnumT,
415 typename = std::enable_if_t<std::is_enum<EnumT>::value>>
416constexpr auto enum_seq_inclusive(EnumT Begin, EnumT End,
418 return iota_range<EnumT>(Begin, End, true);
419}
420
421} // end namespace llvm
422
423#endif // LLVM_ADT_SEQUENCE_H
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
#define T
StandardInstrumentations SI(Mod->getContext(), Debug, VerifyEach)
static std::optional< int32_t > getOffset(ArrayRef< int32_t > Offsets, size_t Idx)
This file contains library features backported from future STL versions.
LLVM Value Representation.
Definition Value.h:75
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr bool canTypeFitValue(const U Value)
Definition Sequence.h:116
This is an optimization pass for GlobalISel generic memory operations.
@ Offset
Definition DWP.cpp:578
constexpr auto seq_inclusive(T Begin, T End)
Iterate over an integral type from Begin to End inclusive.
Definition Sequence.h:361
constexpr force_iteration_on_noniterable_enum_t force_iteration_on_noniterable_enum
Definition Sequence.h:110
constexpr std::enable_if_t< std::is_signed_v< T >, std::pair< T, bool > > AddOverflow(T X, T Y)
Add two signed integers, computing the two's complement truncated result, returning a pair {result,...
Definition MathExtras.h:704
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
Definition InstrProf.h:143
static Error getOffset(const SymbolRef &Sym, SectionRef Sec, uint64_t &Result)
constexpr std::enable_if_t< std::is_signed_v< T >, std::pair< T, bool > > SubOverflow(T X, T Y)
Subtract two signed integers, computing the two's complement truncated result, returning a pair {resu...
Definition MathExtras.h:741
constexpr auto enum_seq(EnumT Begin, EnumT End)
Iterate over an enum type from Begin up to - but not including - End.
Definition Sequence.h:373
constexpr std::underlying_type_t< Enum > to_underlying(Enum E)
Returns underlying integer value of an enum.
constexpr auto enum_seq_inclusive(EnumT Begin, EnumT End)
Iterate over an enum type from Begin to End inclusive.
Definition Sequence.h:401
@ Other
Any other memory.
Definition ModRef.h:68
constexpr auto seq(T Begin, T End)
Iterate over an integral type from Begin up to - but not including - End.
Definition Sequence.h:341
static constexpr CheckedInt from(Enum FromValue)
Definition Sequence.h:144
constexpr bool operator!=(const CheckedInt &O) const
Definition Sequence.h:152
constexpr Integral to() const
Definition Sequence.h:173
static constexpr CheckedInt from(Integral FromValue)
Definition Sequence.h:133
constexpr CheckedInt operator+(intmax_t Offset) const
Definition Sequence.h:156
constexpr intmax_t operator-(CheckedInt Other) const
Definition Sequence.h:163
constexpr Enum to() const
Definition Sequence.h:183
constexpr bool operator==(const CheckedInt &O) const
Definition Sequence.h:149
constexpr bool operator>=(const SafeIntIterator &O) const
Definition Sequence.h:238
constexpr SafeIntIterator operator++(int)
Definition Sequence.h:247
constexpr bool operator==(const SafeIntIterator &O) const
Definition Sequence.h:222
constexpr SafeIntIterator operator+(intmax_t Offset) const
Definition Sequence.h:263
constexpr bool operator>(const SafeIntIterator &O) const
Definition Sequence.h:232
constexpr void operator-=(intmax_t Offset)
Definition Sequence.h:260
constexpr SafeIntIterator operator--(int)
Definition Sequence.h:252
constexpr SafeIntIterator(T Value)
Definition Sequence.h:208
constexpr bool operator<=(const SafeIntIterator &O) const
Definition Sequence.h:235
constexpr reference operator*() const
Definition Sequence.h:215
constexpr void operator++()
Definition Sequence.h:243
constexpr bool operator!=(const SafeIntIterator &O) const
Definition Sequence.h:225
constexpr void operator--()
Definition Sequence.h:244
constexpr void operator+=(intmax_t Offset)
Definition Sequence.h:259
constexpr bool operator<(const SafeIntIterator &O) const
Definition Sequence.h:229
friend struct SafeIntIterator
Definition Sequence.h:291
constexpr intmax_t operator-(const SafeIntIterator &O) const
Definition Sequence.h:271
constexpr SafeIntIterator operator-(intmax_t Offset) const
Definition Sequence.h:266
std::random_access_iterator_tag iterator_category
Definition Sequence.h:201
constexpr SafeIntIterator(const SafeIntIterator< T, !IsReverse > &O)
Definition Sequence.h:211
constexpr reference operator[](intmax_t Offset) const
Definition Sequence.h:217
static constexpr bool is_iterable
Definition Sequence.h:102
constexpr force_iteration_on_noniterable_enum_t()=default
constexpr auto end() const
Definition Sequence.h:318
constexpr iota_range(T Begin, T End, bool Inclusive)
Definition Sequence.h:307
iterator const_iterator
Definition Sequence.h:301
constexpr auto begin() const
Definition Sequence.h:317
reverse_iterator const_reverse_iterator
Definition Sequence.h:303
detail::SafeIntIterator< value_type, false > iterator
Definition Sequence.h:300
std::size_t size_type
Definition Sequence.h:305
detail::SafeIntIterator< value_type, true > reverse_iterator
Definition Sequence.h:302
constexpr size_t size() const
Definition Sequence.h:314
intmax_t difference_type
Definition Sequence.h:304
constexpr auto rbegin() const
Definition Sequence.h:320
constexpr bool empty() const
Definition Sequence.h:315
constexpr auto rend() const
Definition Sequence.h:323
const T & const_reference
Definition Sequence.h:299