Backed out changeset b09d48d2b473 (bug 1655101) for causing mochitest webgl failures...
[gecko.git] / mfbt / EnumeratedRange.h
blobef0e6910ab5cd891b39173e5227385ffc606ffdf
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/. */
7 /* Iterator over contiguous enum values */
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.
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.
20 #ifndef mozilla_EnumeratedRange_h
21 #define mozilla_EnumeratedRange_h
23 #include <limits>
24 #include <type_traits>
26 #include "mozilla/Assertions.h"
27 #include "mozilla/ReverseIterator.h"
29 namespace mozilla {
31 namespace detail {
33 template <typename EnumTypeT>
34 class EnumeratedIterator {
35 public:
36 typedef typename std::underlying_type<EnumTypeT>::type IntTypeT;
38 template <typename EnumType>
39 constexpr explicit EnumeratedIterator(EnumType aCurrent)
40 : mCurrent(aCurrent) {}
42 template <typename EnumType>
43 explicit EnumeratedIterator(const EnumeratedIterator<EnumType>& aOther)
44 : mCurrent(aOther.mCurrent) {}
46 EnumTypeT operator*() const { return mCurrent; }
48 /* Increment and decrement operators */
50 EnumeratedIterator& operator++() {
51 mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1));
52 return *this;
54 EnumeratedIterator& operator--() {
55 mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1));
56 return *this;
58 EnumeratedIterator operator++(int) {
59 auto ret = *this;
60 mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1));
61 return ret;
63 EnumeratedIterator operator--(int) {
64 auto ret = *this;
65 mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1));
66 return ret;
69 /* Comparison operators */
71 template <typename EnumType>
72 friend bool operator==(const EnumeratedIterator<EnumType>& aIter1,
73 const EnumeratedIterator<EnumType>& aIter2);
74 template <typename EnumType>
75 friend bool operator!=(const EnumeratedIterator<EnumType>& aIter1,
76 const EnumeratedIterator<EnumType>& aIter2);
77 template <typename EnumType>
78 friend bool operator<(const EnumeratedIterator<EnumType>& aIter1,
79 const EnumeratedIterator<EnumType>& aIter2);
80 template <typename EnumType>
81 friend bool operator<=(const EnumeratedIterator<EnumType>& aIter1,
82 const EnumeratedIterator<EnumType>& aIter2);
83 template <typename EnumType>
84 friend bool operator>(const EnumeratedIterator<EnumType>& aIter1,
85 const EnumeratedIterator<EnumType>& aIter2);
86 template <typename EnumType>
87 friend bool operator>=(const EnumeratedIterator<EnumType>& aIter1,
88 const EnumeratedIterator<EnumType>& aIter2);
90 private:
91 EnumTypeT mCurrent;
94 template <typename EnumType>
95 bool operator==(const EnumeratedIterator<EnumType>& aIter1,
96 const EnumeratedIterator<EnumType>& aIter2) {
97 return aIter1.mCurrent == aIter2.mCurrent;
100 template <typename EnumType>
101 bool operator!=(const EnumeratedIterator<EnumType>& aIter1,
102 const EnumeratedIterator<EnumType>& aIter2) {
103 return aIter1.mCurrent != aIter2.mCurrent;
106 template <typename EnumType>
107 bool operator<(const EnumeratedIterator<EnumType>& aIter1,
108 const EnumeratedIterator<EnumType>& aIter2) {
109 return aIter1.mCurrent < aIter2.mCurrent;
112 template <typename EnumType>
113 bool operator<=(const EnumeratedIterator<EnumType>& aIter1,
114 const EnumeratedIterator<EnumType>& aIter2) {
115 return aIter1.mCurrent <= aIter2.mCurrent;
118 template <typename EnumType>
119 bool operator>(const EnumeratedIterator<EnumType>& aIter1,
120 const EnumeratedIterator<EnumType>& aIter2) {
121 return aIter1.mCurrent > aIter2.mCurrent;
124 template <typename EnumType>
125 bool operator>=(const EnumeratedIterator<EnumType>& aIter1,
126 const EnumeratedIterator<EnumType>& aIter2) {
127 return aIter1.mCurrent >= aIter2.mCurrent;
130 template <typename EnumTypeT>
131 class EnumeratedRange {
132 public:
133 typedef EnumeratedIterator<EnumTypeT> iterator;
134 typedef EnumeratedIterator<EnumTypeT> const_iterator;
135 typedef ReverseIterator<iterator> reverse_iterator;
136 typedef ReverseIterator<const_iterator> const_reverse_iterator;
138 template <typename EnumType>
139 constexpr EnumeratedRange(EnumType aBegin, EnumType aEnd)
140 : mBegin(aBegin), mEnd(aEnd) {}
142 iterator begin() const { return iterator(mBegin); }
143 const_iterator cbegin() const { return begin(); }
144 iterator end() const { return iterator(mEnd); }
145 const_iterator cend() const { return end(); }
146 reverse_iterator rbegin() const { return reverse_iterator(mEnd); }
147 const_reverse_iterator crbegin() const { return rbegin(); }
148 reverse_iterator rend() const { return reverse_iterator(mBegin); }
149 const_reverse_iterator crend() const { return rend(); }
151 private:
152 EnumTypeT mBegin;
153 EnumTypeT mEnd;
156 } // namespace detail
158 #ifdef __GNUC__
159 // Enums can have an unsigned underlying type, which makes some of the
160 // comparisons below always true or always false. Temporarily disable
161 // -Wtype-limits to avoid breaking -Werror builds.
162 # pragma GCC diagnostic push
163 # pragma GCC diagnostic ignored "-Wtype-limits"
164 #endif
166 // Create a range to iterate from aBegin to aEnd, exclusive.
167 template <typename EnumType>
168 constexpr detail::EnumeratedRange<EnumType> MakeEnumeratedRange(EnumType aBegin,
169 EnumType aEnd) {
170 MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!");
171 return detail::EnumeratedRange<EnumType>(aBegin, aEnd);
174 // Create a range to iterate from EnumType(0) to aEnd, exclusive. EnumType(0)
175 // should exist, but note that there is no way for us to ensure that it does!
176 template <typename EnumType>
177 constexpr detail::EnumeratedRange<EnumType> MakeEnumeratedRange(EnumType aEnd) {
178 return MakeEnumeratedRange(EnumType(0), aEnd);
181 // Create a range to iterate from aBegin to aEnd, inclusive.
183 // NOTE: This internally constructs a value that is one past `aEnd`, so the
184 // enumeration needs to either have a fixed underlying type, or `aEnd + 1` must
185 // be inside the range of the enumeration, in order to not be undefined
186 // behavior.
188 // See bug 1614512.
189 template <typename EnumType>
190 constexpr detail::EnumeratedRange<EnumType> MakeInclusiveEnumeratedRange(
191 EnumType aBegin, EnumType aEnd) {
192 using EnumUnderlyingType = typename std::underlying_type_t<EnumType>;
193 const auto end = static_cast<EnumUnderlyingType>(aEnd);
195 MOZ_ASSERT(end != std::numeric_limits<EnumUnderlyingType>::max(),
196 "aEnd shouldn't overflow!");
197 return MakeEnumeratedRange(aBegin, static_cast<EnumType>(end + 1));
200 template <typename EnumType>
201 constexpr auto MakeInclusiveEnumeratedRange(EnumType aEnd) {
202 return MakeInclusiveEnumeratedRange(EnumType{0}, aEnd);
205 #ifdef __GNUC__
206 # pragma GCC diagnostic pop
207 #endif
209 } // namespace mozilla
211 #endif // mozilla_EnumeratedRange_h