Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-05-10 08:43:07

0001 //===- Sequence.h - Utility for producing sequences of values ---*- C++ -*-===//
0002 //
0003 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
0004 // See https://llvm.org/LICENSE.txt for license information.
0005 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
0006 //
0007 //===----------------------------------------------------------------------===//
0008 /// \file
0009 /// Provides some synthesis utilities to produce sequences of values. The names
0010 /// are intentionally kept very short as they tend to occur in common and
0011 /// widely used contexts.
0012 ///
0013 /// The `seq(A, B)` function produces a sequence of values from `A` to up to
0014 /// (but not including) `B`, i.e., [`A`, `B`), that can be safely iterated over.
0015 /// `seq` supports both integral (e.g., `int`, `char`, `uint32_t`) and enum
0016 /// types. `seq_inclusive(A, B)` produces a sequence of values from `A` to `B`,
0017 /// including `B`.
0018 ///
0019 /// Examples with integral types:
0020 /// ```
0021 /// for (int x : seq(0, 3))
0022 ///   outs() << x << " ";
0023 /// ```
0024 ///
0025 /// Prints: `0 1 2 `.
0026 ///
0027 /// ```
0028 /// for (int x : seq_inclusive(0, 3))
0029 ///   outs() << x << " ";
0030 /// ```
0031 ///
0032 /// Prints: `0 1 2 3 `.
0033 ///
0034 /// Similar to `seq` and `seq_inclusive`, the `enum_seq` and
0035 /// `enum_seq_inclusive` functions produce sequences of enum values that can be
0036 /// iterated over.
0037 /// To enable iteration with enum types, you need to either mark enums as safe
0038 /// to iterate on by specializing `enum_iteration_traits`, or opt into
0039 /// potentially unsafe iteration at every callsite by passing
0040 /// `force_iteration_on_noniterable_enum`.
0041 ///
0042 /// Examples with enum types:
0043 /// ```
0044 /// namespace X {
0045 ///   enum class MyEnum : unsigned {A = 0, B, C};
0046 /// } // namespace X
0047 ///
0048 /// template <> struct enum_iteration_traits<X::MyEnum> {
0049 ///   static contexpr bool is_iterable = true;
0050 /// };
0051 ///
0052 /// class MyClass {
0053 /// public:
0054 ///   enum Safe { D = 3, E, F };
0055 ///   enum MaybeUnsafe { G = 1, H = 2, I = 4 };
0056 /// };
0057 ///
0058 /// template <> struct enum_iteration_traits<MyClass::Safe> {
0059 ///   static contexpr bool is_iterable = true;
0060 /// };
0061 /// ```
0062 ///
0063 /// ```
0064 ///   for (auto v : enum_seq(MyClass::Safe::D, MyClass::Safe::F))
0065 ///     outs() << int(v) << " ";
0066 /// ```
0067 ///
0068 /// Prints: `3 4 `.
0069 ///
0070 /// ```
0071 ///   for (auto v : enum_seq(MyClass::MaybeUnsafe::H, MyClass::MaybeUnsafe::I,
0072 ///                          force_iteration_on_noniterable_enum))
0073 ///     outs() << int(v) << " ";
0074 /// ```
0075 ///
0076 /// Prints: `2 3 `.
0077 ///
0078 //===----------------------------------------------------------------------===//
0079 
0080 #ifndef LLVM_ADT_SEQUENCE_H
0081 #define LLVM_ADT_SEQUENCE_H
0082 
0083 #include <cassert>     // assert
0084 #include <iterator>    // std::random_access_iterator_tag
0085 #include <limits>      // std::numeric_limits
0086 #include <type_traits> // std::is_integral, std::is_enum, std::underlying_type,
0087                        // std::enable_if
0088 
0089 #include "llvm/Support/MathExtras.h" // AddOverflow / SubOverflow
0090 
0091 namespace llvm {
0092 
0093 // Enum traits that marks enums as safe or unsafe to iterate over.
0094 // By default, enum types are *not* considered safe for iteration.
0095 // To allow iteration for your enum type, provide a specialization with
0096 // `is_iterable` set to `true` in the `llvm` namespace.
0097 // Alternatively, you can pass the `force_iteration_on_noniterable_enum` tag
0098 // to `enum_seq` or `enum_seq_inclusive`.
0099 template <typename EnumT> struct enum_iteration_traits {
0100   static constexpr bool is_iterable = false;
0101 };
0102 
0103 struct force_iteration_on_noniterable_enum_t {
0104   explicit force_iteration_on_noniterable_enum_t() = default;
0105 };
0106 
0107 inline constexpr force_iteration_on_noniterable_enum_t
0108     force_iteration_on_noniterable_enum;
0109 
0110 namespace detail {
0111 
0112 // Returns whether a value of type U can be represented with type T.
0113 template <typename T, typename U> bool canTypeFitValue(const U Value) {
0114   const intmax_t BotT = intmax_t(std::numeric_limits<T>::min());
0115   const intmax_t BotU = intmax_t(std::numeric_limits<U>::min());
0116   const uintmax_t TopT = uintmax_t(std::numeric_limits<T>::max());
0117   const uintmax_t TopU = uintmax_t(std::numeric_limits<U>::max());
0118   return !((BotT > BotU && Value < static_cast<U>(BotT)) ||
0119            (TopT < TopU && Value > static_cast<U>(TopT)));
0120 }
0121 
0122 // An integer type that asserts when:
0123 // - constructed from a value that doesn't fit into intmax_t,
0124 // - casted to a type that cannot hold the current value,
0125 // - its internal representation overflows.
0126 struct CheckedInt {
0127   // Integral constructor, asserts if Value cannot be represented as intmax_t.
0128   template <typename Integral,
0129             std::enable_if_t<std::is_integral<Integral>::value, bool> = 0>
0130   static CheckedInt from(Integral FromValue) {
0131     if (!canTypeFitValue<intmax_t>(FromValue))
0132       assertOutOfBounds();
0133     CheckedInt Result;
0134     Result.Value = static_cast<intmax_t>(FromValue);
0135     return Result;
0136   }
0137 
0138   // Enum constructor, asserts if Value cannot be represented as intmax_t.
0139   template <typename Enum,
0140             std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
0141   static CheckedInt from(Enum FromValue) {
0142     using type = std::underlying_type_t<Enum>;
0143     return from<type>(static_cast<type>(FromValue));
0144   }
0145 
0146   // Equality
0147   bool operator==(const CheckedInt &O) const { return Value == O.Value; }
0148   bool operator!=(const CheckedInt &O) const { return Value != O.Value; }
0149 
0150   CheckedInt operator+(intmax_t Offset) const {
0151     CheckedInt Result;
0152     if (AddOverflow(Value, Offset, Result.Value))
0153       assertOutOfBounds();
0154     return Result;
0155   }
0156 
0157   intmax_t operator-(CheckedInt Other) const {
0158     intmax_t Result;
0159     if (SubOverflow(Value, Other.Value, Result))
0160       assertOutOfBounds();
0161     return Result;
0162   }
0163 
0164   // Convert to integral, asserts if Value cannot be represented as Integral.
0165   template <typename Integral,
0166             std::enable_if_t<std::is_integral<Integral>::value, bool> = 0>
0167   Integral to() const {
0168     if (!canTypeFitValue<Integral>(Value))
0169       assertOutOfBounds();
0170     return static_cast<Integral>(Value);
0171   }
0172 
0173   // Convert to enum, asserts if Value cannot be represented as Enum's
0174   // underlying type.
0175   template <typename Enum,
0176             std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
0177   Enum to() const {
0178     using type = std::underlying_type_t<Enum>;
0179     return Enum(to<type>());
0180   }
0181 
0182 private:
0183   static void assertOutOfBounds() { assert(false && "Out of bounds"); }
0184 
0185   intmax_t Value;
0186 };
0187 
0188 template <typename T, bool IsReverse> struct SafeIntIterator {
0189   using iterator_category = std::random_access_iterator_tag;
0190   using value_type = T;
0191   using difference_type = intmax_t;
0192   using pointer = T *;
0193   using reference = value_type; // The iterator does not reference memory.
0194 
0195   // Construct from T.
0196   explicit SafeIntIterator(T Value) : SI(CheckedInt::from<T>(Value)) {}
0197   // Construct from other direction.
0198   SafeIntIterator(const SafeIntIterator<T, !IsReverse> &O) : SI(O.SI) {}
0199 
0200   // Dereference
0201   reference operator*() const { return SI.to<T>(); }
0202   // Indexing
0203   reference operator[](intmax_t Offset) const { return *(*this + Offset); }
0204 
0205   // Can be compared for equivalence using the equality/inequality operators.
0206   bool operator==(const SafeIntIterator &O) const { return SI == O.SI; }
0207   bool operator!=(const SafeIntIterator &O) const { return SI != O.SI; }
0208   // Comparison
0209   bool operator<(const SafeIntIterator &O) const { return (*this - O) < 0; }
0210   bool operator>(const SafeIntIterator &O) const { return (*this - O) > 0; }
0211   bool operator<=(const SafeIntIterator &O) const { return (*this - O) <= 0; }
0212   bool operator>=(const SafeIntIterator &O) const { return (*this - O) >= 0; }
0213 
0214   // Pre Increment/Decrement
0215   void operator++() { offset(1); }
0216   void operator--() { offset(-1); }
0217 
0218   // Post Increment/Decrement
0219   SafeIntIterator operator++(int) {
0220     const auto Copy = *this;
0221     ++*this;
0222     return Copy;
0223   }
0224   SafeIntIterator operator--(int) {
0225     const auto Copy = *this;
0226     --*this;
0227     return Copy;
0228   }
0229 
0230   // Compound assignment operators
0231   void operator+=(intmax_t Offset) { offset(Offset); }
0232   void operator-=(intmax_t Offset) { offset(-Offset); }
0233 
0234   // Arithmetic
0235   SafeIntIterator operator+(intmax_t Offset) const { return add(Offset); }
0236   SafeIntIterator operator-(intmax_t Offset) const { return add(-Offset); }
0237 
0238   // Difference
0239   intmax_t operator-(const SafeIntIterator &O) const {
0240     return IsReverse ? O.SI - SI : SI - O.SI;
0241   }
0242 
0243 private:
0244   SafeIntIterator(const CheckedInt &SI) : SI(SI) {}
0245 
0246   static intmax_t getOffset(intmax_t Offset) {
0247     return IsReverse ? -Offset : Offset;
0248   }
0249 
0250   CheckedInt add(intmax_t Offset) const { return SI + getOffset(Offset); }
0251 
0252   void offset(intmax_t Offset) { SI = SI + getOffset(Offset); }
0253 
0254   CheckedInt SI;
0255 
0256   // To allow construction from the other direction.
0257   template <typename, bool> friend struct SafeIntIterator;
0258 };
0259 
0260 } // namespace detail
0261 
0262 template <typename T> struct iota_range {
0263   using value_type = T;
0264   using reference = T &;
0265   using const_reference = const T &;
0266   using iterator = detail::SafeIntIterator<value_type, false>;
0267   using const_iterator = iterator;
0268   using reverse_iterator = detail::SafeIntIterator<value_type, true>;
0269   using const_reverse_iterator = reverse_iterator;
0270   using difference_type = intmax_t;
0271   using size_type = std::size_t;
0272 
0273   explicit iota_range(T Begin, T End, bool Inclusive)
0274       : BeginValue(Begin), PastEndValue(End) {
0275     assert(Begin <= End && "Begin must be less or equal to End.");
0276     if (Inclusive)
0277       ++PastEndValue;
0278   }
0279 
0280   size_t size() const { return PastEndValue - BeginValue; }
0281   bool empty() const { return BeginValue == PastEndValue; }
0282 
0283   auto begin() const { return const_iterator(BeginValue); }
0284   auto end() const { return const_iterator(PastEndValue); }
0285 
0286   auto rbegin() const { return const_reverse_iterator(PastEndValue - 1); }
0287   auto rend() const { return const_reverse_iterator(BeginValue - 1); }
0288 
0289 private:
0290   static_assert(std::is_integral<T>::value || std::is_enum<T>::value,
0291                 "T must be an integral or enum type");
0292   static_assert(std::is_same<T, std::remove_cv_t<T>>::value,
0293                 "T must not be const nor volatile");
0294 
0295   iterator BeginValue;
0296   iterator PastEndValue;
0297 };
0298 
0299 /// Iterate over an integral type from Begin up to - but not including - End.
0300 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
0301 /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
0302 /// iteration).
0303 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
0304                                                   !std::is_enum<T>::value>>
0305 auto seq(T Begin, T End) {
0306   return iota_range<T>(Begin, End, false);
0307 }
0308 
0309 /// Iterate over an integral type from 0 up to - but not including - Size.
0310 /// Note: Size value has to be within [INTMAX_MIN, INTMAX_MAX - 1] for
0311 /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
0312 /// iteration).
0313 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
0314                                                   !std::is_enum<T>::value>>
0315 auto seq(T Size) {
0316   return seq<T>(0, Size);
0317 }
0318 
0319 /// Iterate over an integral type from Begin to End inclusive.
0320 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
0321 /// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
0322 /// iteration).
0323 template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
0324                                                   !std::is_enum<T>::value>>
0325 auto seq_inclusive(T Begin, T End) {
0326   return iota_range<T>(Begin, End, true);
0327 }
0328 
0329 /// Iterate over an enum type from Begin up to - but not including - End.
0330 /// Note: `enum_seq` will generate each consecutive value, even if no
0331 /// enumerator with that value exists.
0332 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
0333 /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
0334 /// iteration).
0335 template <typename EnumT,
0336           typename = std::enable_if_t<std::is_enum<EnumT>::value>>
0337 auto enum_seq(EnumT Begin, EnumT End) {
0338   static_assert(enum_iteration_traits<EnumT>::is_iterable,
0339                 "Enum type is not marked as iterable.");
0340   return iota_range<EnumT>(Begin, End, false);
0341 }
0342 
0343 /// Iterate over an enum type from Begin up to - but not including - End, even
0344 /// when `EnumT` is not marked as safely iterable by `enum_iteration_traits`.
0345 /// Note: `enum_seq` will generate each consecutive value, even if no
0346 /// enumerator with that value exists.
0347 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
0348 /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
0349 /// iteration).
0350 template <typename EnumT,
0351           typename = std::enable_if_t<std::is_enum<EnumT>::value>>
0352 auto enum_seq(EnumT Begin, EnumT End, force_iteration_on_noniterable_enum_t) {
0353   return iota_range<EnumT>(Begin, End, false);
0354 }
0355 
0356 /// Iterate over an enum type from Begin to End inclusive.
0357 /// Note: `enum_seq_inclusive` will generate each consecutive value, even if no
0358 /// enumerator with that value exists.
0359 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
0360 /// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
0361 /// iteration).
0362 template <typename EnumT,
0363           typename = std::enable_if_t<std::is_enum<EnumT>::value>>
0364 auto enum_seq_inclusive(EnumT Begin, EnumT End) {
0365   static_assert(enum_iteration_traits<EnumT>::is_iterable,
0366                 "Enum type is not marked as iterable.");
0367   return iota_range<EnumT>(Begin, End, true);
0368 }
0369 
0370 /// Iterate over an enum type from Begin to End inclusive, even when `EnumT`
0371 /// is not marked as safely iterable by `enum_iteration_traits`.
0372 /// Note: `enum_seq_inclusive` will generate each consecutive value, even if no
0373 /// enumerator with that value exists.
0374 /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
0375 /// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
0376 /// iteration).
0377 template <typename EnumT,
0378           typename = std::enable_if_t<std::is_enum<EnumT>::value>>
0379 auto enum_seq_inclusive(EnumT Begin, EnumT End,
0380                         force_iteration_on_noniterable_enum_t) {
0381   return iota_range<EnumT>(Begin, End, true);
0382 }
0383 
0384 } // end namespace llvm
0385 
0386 #endif // LLVM_ADT_SEQUENCE_H