Subversion Repositories QNX 8.QNX8 LLVM/Clang compiler suite

Rev

Blame | Last modification | View Log | Download | RSS feed

  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. inline constexpr force_iteration_on_noniterable_enum_t
  108.     force_iteration_on_noniterable_enum;
  109.  
  110. namespace detail {
  111.  
  112. // Returns whether a value of type U can be represented with type T.
  113. template <typename T, typename U> bool canTypeFitValue(const U Value) {
  114.   const intmax_t BotT = intmax_t(std::numeric_limits<T>::min());
  115.   const intmax_t BotU = intmax_t(std::numeric_limits<U>::min());
  116.   const uintmax_t TopT = uintmax_t(std::numeric_limits<T>::max());
  117.   const uintmax_t TopU = uintmax_t(std::numeric_limits<U>::max());
  118.   return !((BotT > BotU && Value < static_cast<U>(BotT)) ||
  119.            (TopT < TopU && Value > static_cast<U>(TopT)));
  120. }
  121.  
  122. // An integer type that asserts when:
  123. // - constructed from a value that doesn't fit into intmax_t,
  124. // - casted to a type that cannot hold the current value,
  125. // - its internal representation overflows.
  126. struct CheckedInt {
  127.   // Integral constructor, asserts if Value cannot be represented as intmax_t.
  128.   template <typename Integral,
  129.             std::enable_if_t<std::is_integral<Integral>::value, bool> = 0>
  130.   static CheckedInt from(Integral FromValue) {
  131.     if (!canTypeFitValue<intmax_t>(FromValue))
  132.       assertOutOfBounds();
  133.     CheckedInt Result;
  134.     Result.Value = static_cast<intmax_t>(FromValue);
  135.     return Result;
  136.   }
  137.  
  138.   // Enum constructor, asserts if Value cannot be represented as intmax_t.
  139.   template <typename Enum,
  140.             std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
  141.   static CheckedInt from(Enum FromValue) {
  142.     using type = std::underlying_type_t<Enum>;
  143.     return from<type>(static_cast<type>(FromValue));
  144.   }
  145.  
  146.   // Equality
  147.   bool operator==(const CheckedInt &O) const { return Value == O.Value; }
  148.   bool operator!=(const CheckedInt &O) const { return Value != O.Value; }
  149.  
  150.   CheckedInt operator+(intmax_t Offset) const {
  151.     CheckedInt Result;
  152.     if (AddOverflow(Value, Offset, Result.Value))
  153.       assertOutOfBounds();
  154.     return Result;
  155.   }
  156.  
  157.   intmax_t operator-(CheckedInt Other) const {
  158.     intmax_t Result;
  159.     if (SubOverflow(Value, Other.Value, Result))
  160.       assertOutOfBounds();
  161.     return Result;
  162.   }
  163.  
  164.   // Convert to integral, asserts if Value cannot be represented as Integral.
  165.   template <typename Integral,
  166.             std::enable_if_t<std::is_integral<Integral>::value, bool> = 0>
  167.   Integral to() const {
  168.     if (!canTypeFitValue<Integral>(Value))
  169.       assertOutOfBounds();
  170.     return static_cast<Integral>(Value);
  171.   }
  172.  
  173.   // Convert to enum, asserts if Value cannot be represented as Enum's
  174.   // underlying type.
  175.   template <typename Enum,
  176.             std::enable_if_t<std::is_enum<Enum>::value, bool> = 0>
  177.   Enum to() const {
  178.     using type = std::underlying_type_t<Enum>;
  179.     return Enum(to<type>());
  180.   }
  181.  
  182. private:
  183.   static void assertOutOfBounds() { assert(false && "Out of bounds"); }
  184.  
  185.   intmax_t Value;
  186. };
  187.  
  188. template <typename T, bool IsReverse> struct SafeIntIterator {
  189.   using iterator_category = std::random_access_iterator_tag;
  190.   using value_type = T;
  191.   using difference_type = intmax_t;
  192.   using pointer = T *;
  193.   using reference = T &;
  194.  
  195.   // Construct from T.
  196.   explicit SafeIntIterator(T Value) : SI(CheckedInt::from<T>(Value)) {}
  197.   // Construct from other direction.
  198.   SafeIntIterator(const SafeIntIterator<T, !IsReverse> &O) : SI(O.SI) {}
  199.  
  200.   // Dereference
  201.   value_type operator*() const { return SI.to<T>(); }
  202.   // Indexing
  203.   value_type operator[](intmax_t Offset) const { return *(*this + Offset); }
  204.  
  205.   // Can be compared for equivalence using the equality/inequality operators.
  206.   bool operator==(const SafeIntIterator &O) const { return SI == O.SI; }
  207.   bool operator!=(const SafeIntIterator &O) const { return SI != O.SI; }
  208.   // Comparison
  209.   bool operator<(const SafeIntIterator &O) const { return (*this - O) < 0; }
  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.  
  214.   // Pre Increment/Decrement
  215.   void operator++() { offset(1); }
  216.   void operator--() { offset(-1); }
  217.  
  218.   // Post Increment/Decrement
  219.   SafeIntIterator operator++(int) {
  220.     const auto Copy = *this;
  221.     ++*this;
  222.     return Copy;
  223.   }
  224.   SafeIntIterator operator--(int) {
  225.     const auto Copy = *this;
  226.     --*this;
  227.     return Copy;
  228.   }
  229.  
  230.   // Compound assignment operators
  231.   void operator+=(intmax_t Offset) { offset(Offset); }
  232.   void operator-=(intmax_t Offset) { offset(-Offset); }
  233.  
  234.   // Arithmetic
  235.   SafeIntIterator operator+(intmax_t Offset) const { return add(Offset); }
  236.   SafeIntIterator operator-(intmax_t Offset) const { return add(-Offset); }
  237.  
  238.   // Difference
  239.   intmax_t operator-(const SafeIntIterator &O) const {
  240.     return IsReverse ? O.SI - SI : SI - O.SI;
  241.   }
  242.  
  243. private:
  244.   SafeIntIterator(const CheckedInt &SI) : SI(SI) {}
  245.  
  246.   static intmax_t getOffset(intmax_t Offset) {
  247.     return IsReverse ? -Offset : Offset;
  248.   }
  249.  
  250.   CheckedInt add(intmax_t Offset) const { return SI + getOffset(Offset); }
  251.  
  252.   void offset(intmax_t Offset) { SI = SI + getOffset(Offset); }
  253.  
  254.   CheckedInt SI;
  255.  
  256.   // To allow construction from the other direction.
  257.   template <typename, bool> friend struct SafeIntIterator;
  258. };
  259.  
  260. } // namespace detail
  261.  
  262. template <typename T> struct iota_range {
  263.   using value_type = T;
  264.   using reference = T &;
  265.   using const_reference = const T &;
  266.   using iterator = detail::SafeIntIterator<value_type, false>;
  267.   using const_iterator = iterator;
  268.   using reverse_iterator = detail::SafeIntIterator<value_type, true>;
  269.   using const_reverse_iterator = reverse_iterator;
  270.   using difference_type = intmax_t;
  271.   using size_type = std::size_t;
  272.  
  273.   explicit iota_range(T Begin, T End, bool Inclusive)
  274.       : BeginValue(Begin), PastEndValue(End) {
  275.     assert(Begin <= End && "Begin must be less or equal to End.");
  276.     if (Inclusive)
  277.       ++PastEndValue;
  278.   }
  279.  
  280.   size_t size() const { return PastEndValue - BeginValue; }
  281.   bool empty() const { return BeginValue == PastEndValue; }
  282.  
  283.   auto begin() const { return const_iterator(BeginValue); }
  284.   auto end() const { return const_iterator(PastEndValue); }
  285.  
  286.   auto rbegin() const { return const_reverse_iterator(PastEndValue - 1); }
  287.   auto rend() const { return const_reverse_iterator(BeginValue - 1); }
  288.  
  289. private:
  290.   static_assert(std::is_integral<T>::value || std::is_enum<T>::value,
  291.                 "T must be an integral or enum type");
  292.   static_assert(std::is_same<T, std::remove_cv_t<T>>::value,
  293.                 "T must not be const nor volatile");
  294.  
  295.   iterator BeginValue;
  296.   iterator PastEndValue;
  297. };
  298.  
  299. /// Iterate over an integral type from Begin up to - but not including - End.
  300. /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
  301. /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
  302. /// iteration).
  303. template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
  304.                                                   !std::is_enum<T>::value>>
  305. auto seq(T Begin, T End) {
  306.   return iota_range<T>(Begin, End, false);
  307. }
  308.  
  309. /// Iterate over an integral type from Begin to End inclusive.
  310. /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
  311. /// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
  312. /// iteration).
  313. template <typename T, typename = std::enable_if_t<std::is_integral<T>::value &&
  314.                                                   !std::is_enum<T>::value>>
  315. auto seq_inclusive(T Begin, T End) {
  316.   return iota_range<T>(Begin, End, true);
  317. }
  318.  
  319. /// Iterate over an enum type from Begin up to - but not including - End.
  320. /// Note: `enum_seq` will generate each consecutive value, even if no
  321. /// enumerator with that value exists.
  322. /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
  323. /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
  324. /// iteration).
  325. template <typename EnumT,
  326.           typename = std::enable_if_t<std::is_enum<EnumT>::value>>
  327. auto enum_seq(EnumT Begin, EnumT End) {
  328.   static_assert(enum_iteration_traits<EnumT>::is_iterable,
  329.                 "Enum type is not marked as iterable.");
  330.   return iota_range<EnumT>(Begin, End, false);
  331. }
  332.  
  333. /// Iterate over an enum type from Begin up to - but not including - End, even
  334. /// when `EnumT` is not marked as safely iterable by `enum_iteration_traits`.
  335. /// Note: `enum_seq` will generate each consecutive value, even if no
  336. /// enumerator with that value exists.
  337. /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX] for
  338. /// forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX] for reverse
  339. /// iteration).
  340. template <typename EnumT,
  341.           typename = std::enable_if_t<std::is_enum<EnumT>::value>>
  342. auto enum_seq(EnumT Begin, EnumT End, force_iteration_on_noniterable_enum_t) {
  343.   return iota_range<EnumT>(Begin, End, false);
  344. }
  345.  
  346. /// Iterate over an enum type from Begin to End inclusive.
  347. /// Note: `enum_seq_inclusive` will generate each consecutive value, even if no
  348. /// enumerator with that value exists.
  349. /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
  350. /// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
  351. /// iteration).
  352. template <typename EnumT,
  353.           typename = std::enable_if_t<std::is_enum<EnumT>::value>>
  354. auto enum_seq_inclusive(EnumT Begin, EnumT End) {
  355.   static_assert(enum_iteration_traits<EnumT>::is_iterable,
  356.                 "Enum type is not marked as iterable.");
  357.   return iota_range<EnumT>(Begin, End, true);
  358. }
  359.  
  360. /// Iterate over an enum type from Begin to End inclusive, even when `EnumT`
  361. /// is not marked as safely iterable by `enum_iteration_traits`.
  362. /// Note: `enum_seq_inclusive` will generate each consecutive value, even if no
  363. /// enumerator with that value exists.
  364. /// Note: Begin and End values have to be within [INTMAX_MIN, INTMAX_MAX - 1]
  365. /// for forward iteration (resp. [INTMAX_MIN + 1, INTMAX_MAX - 1] for reverse
  366. /// iteration).
  367. template <typename EnumT,
  368.           typename = std::enable_if_t<std::is_enum<EnumT>::value>>
  369. auto enum_seq_inclusive(EnumT Begin, EnumT End,
  370.                         force_iteration_on_noniterable_enum_t) {
  371.   return iota_range<EnumT>(Begin, End, true);
  372. }
  373.  
  374. } // end namespace llvm
  375.  
  376. #endif // LLVM_ADT_SEQUENCE_H
  377.