EnumeratedRange.h (6296B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 /* Iterator over contiguous enum values */ 8 9 /* 10 * Implements generator functions that create a range to iterate over the values 11 * of a scoped or unscoped enum. Unlike IntegerRange, which can only function on 12 * the underlying integral type, the elements of the generated sequence will 13 * have the type of the enum in question. 14 * 15 * Note that the enum values should be contiguous in the iterated range; 16 * unfortunately there exists no way for EnumeratedRange to enforce this 17 * either dynamically or at compile time. 18 */ 19 20 #ifndef mozilla_EnumeratedRange_h 21 #define mozilla_EnumeratedRange_h 22 23 #include <limits> 24 #include <type_traits> 25 26 #include "mozilla/Assertions.h" 27 #include "mozilla/ReverseIterator.h" 28 29 namespace mozilla { 30 31 namespace detail { 32 33 template <typename EnumTypeT> 34 class EnumeratedIterator { 35 public: 36 typedef std::underlying_type_t<EnumTypeT> IntTypeT; 37 38 template <typename EnumType> 39 constexpr explicit EnumeratedIterator(EnumType aCurrent) 40 : mCurrent(aCurrent) {} 41 42 template <typename EnumType> 43 explicit EnumeratedIterator(const EnumeratedIterator<EnumType>& aOther) 44 : mCurrent(aOther.mCurrent) {} 45 46 EnumTypeT operator*() const { return mCurrent; } 47 48 /* Increment and decrement operators */ 49 50 EnumeratedIterator& operator++() { 51 mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1)); 52 return *this; 53 } 54 EnumeratedIterator& operator--() { 55 mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1)); 56 return *this; 57 } 58 EnumeratedIterator operator++(int) { 59 auto ret = *this; 60 mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1)); 61 return ret; 62 } 63 EnumeratedIterator operator--(int) { 64 auto ret = *this; 65 mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1)); 66 return ret; 67 } 68 69 /* Comparison operators */ 70 71 friend bool operator==(const EnumeratedIterator<EnumTypeT>& aIter1, 72 const EnumeratedIterator<EnumTypeT>& aIter2) { 73 return aIter1.mCurrent == aIter2.mCurrent; 74 } 75 76 friend bool operator!=(const EnumeratedIterator<EnumTypeT>& aIter1, 77 const EnumeratedIterator<EnumTypeT>& aIter2) { 78 return aIter1.mCurrent != aIter2.mCurrent; 79 } 80 81 friend bool operator<(const EnumeratedIterator<EnumTypeT>& aIter1, 82 const EnumeratedIterator<EnumTypeT>& aIter2) { 83 return aIter1.mCurrent < aIter2.mCurrent; 84 } 85 86 friend bool operator<=(const EnumeratedIterator<EnumTypeT>& aIter1, 87 const EnumeratedIterator<EnumTypeT>& aIter2) { 88 return aIter1.mCurrent <= aIter2.mCurrent; 89 } 90 friend bool operator>(const EnumeratedIterator<EnumTypeT>& aIter1, 91 const EnumeratedIterator<EnumTypeT>& aIter2) { 92 return aIter1.mCurrent > aIter2.mCurrent; 93 } 94 friend bool operator>=(const EnumeratedIterator<EnumTypeT>& aIter1, 95 const EnumeratedIterator<EnumTypeT>& aIter2) { 96 return aIter1.mCurrent >= aIter2.mCurrent; 97 } 98 99 private: 100 EnumTypeT mCurrent; 101 }; 102 103 template <typename EnumTypeT> 104 class EnumeratedRange { 105 public: 106 typedef EnumeratedIterator<EnumTypeT> iterator; 107 typedef EnumeratedIterator<EnumTypeT> const_iterator; 108 typedef ReverseIterator<iterator> reverse_iterator; 109 typedef ReverseIterator<const_iterator> const_reverse_iterator; 110 111 template <typename EnumType> 112 constexpr EnumeratedRange(EnumType aBegin, EnumType aEnd) 113 : mBegin(aBegin), mEnd(aEnd) {} 114 115 iterator begin() const { return iterator(mBegin); } 116 const_iterator cbegin() const { return begin(); } 117 iterator end() const { return iterator(mEnd); } 118 const_iterator cend() const { return end(); } 119 reverse_iterator rbegin() const { return reverse_iterator(mEnd); } 120 const_reverse_iterator crbegin() const { return rbegin(); } 121 reverse_iterator rend() const { return reverse_iterator(mBegin); } 122 const_reverse_iterator crend() const { return rend(); } 123 124 private: 125 EnumTypeT mBegin; 126 EnumTypeT mEnd; 127 }; 128 129 } // namespace detail 130 131 #ifdef __GNUC__ 132 // Enums can have an unsigned underlying type, which makes some of the 133 // comparisons below always true or always false. Temporarily disable 134 // -Wtype-limits to avoid breaking -Werror builds. 135 # pragma GCC diagnostic push 136 # pragma GCC diagnostic ignored "-Wtype-limits" 137 #endif 138 139 // Create a range to iterate from aBegin to aEnd, exclusive. 140 template <typename EnumType> 141 constexpr detail::EnumeratedRange<EnumType> MakeEnumeratedRange(EnumType aBegin, 142 EnumType aEnd) { 143 MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!"); 144 return detail::EnumeratedRange<EnumType>(aBegin, aEnd); 145 } 146 147 // Create a range to iterate from EnumType(0) to aEnd, exclusive. EnumType(0) 148 // should exist, but note that there is no way for us to ensure that it does! 149 template <typename EnumType> 150 constexpr detail::EnumeratedRange<EnumType> MakeEnumeratedRange(EnumType aEnd) { 151 return MakeEnumeratedRange(EnumType(0), aEnd); 152 } 153 154 // Create a range to iterate from aBegin to aEnd, inclusive. 155 // 156 // NOTE: This internally constructs a value that is one past `aEnd`, so the 157 // enumeration needs to either have a fixed underlying type, or `aEnd + 1` must 158 // be inside the range of the enumeration, in order to not be undefined 159 // behavior. 160 // 161 // See bug 1614512. 162 template <typename EnumType> 163 constexpr detail::EnumeratedRange<EnumType> MakeInclusiveEnumeratedRange( 164 EnumType aBegin, EnumType aEnd) { 165 using EnumUnderlyingType = std::underlying_type_t<EnumType>; 166 const auto end = static_cast<EnumUnderlyingType>(aEnd); 167 168 MOZ_ASSERT(end != std::numeric_limits<EnumUnderlyingType>::max(), 169 "aEnd shouldn't overflow!"); 170 return MakeEnumeratedRange(aBegin, static_cast<EnumType>(end + 1)); 171 } 172 173 template <typename EnumType> 174 constexpr auto MakeInclusiveEnumeratedRange(EnumType aEnd) { 175 return MakeInclusiveEnumeratedRange(EnumType{0}, aEnd); 176 } 177 178 #ifdef __GNUC__ 179 # pragma GCC diagnostic pop 180 #endif 181 182 } // namespace mozilla 183 184 #endif // mozilla_EnumeratedRange_h