Bug 1687263: part 2) Add `NodeOffsetRange::operator==(const nsRange& aRange)`. r...
[gecko.git] / mfbt / EnumeratedRange.h
blobc3b8c8960b9a24e3c0ead8ea67d48434de9803c2
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/ReverseIterator.h"
28 namespace mozilla {
30 namespace detail {
32 template <typename EnumTypeT>
33 class EnumeratedIterator {
34 public:
35 typedef typename std::underlying_type<EnumTypeT>::type IntTypeT;
37 template <typename EnumType>
38 constexpr explicit EnumeratedIterator(EnumType aCurrent)
39 : mCurrent(aCurrent) {}
41 template <typename EnumType>
42 explicit EnumeratedIterator(const EnumeratedIterator<EnumType>& aOther)
43 : mCurrent(aOther.mCurrent) {}
45 EnumTypeT operator*() const { return mCurrent; }
47 /* Increment and decrement operators */
49 EnumeratedIterator& operator++() {
50 mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1));
51 return *this;
53 EnumeratedIterator& operator--() {
54 mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1));
55 return *this;
57 EnumeratedIterator operator++(int) {
58 auto ret = *this;
59 mCurrent = EnumTypeT(IntTypeT(mCurrent) + IntTypeT(1));
60 return ret;
62 EnumeratedIterator operator--(int) {
63 auto ret = *this;
64 mCurrent = EnumTypeT(IntTypeT(mCurrent) - IntTypeT(1));
65 return ret;
68 /* Comparison operators */
70 template <typename EnumType>
71 friend bool operator==(const EnumeratedIterator<EnumType>& aIter1,
72 const EnumeratedIterator<EnumType>& aIter2);
73 template <typename EnumType>
74 friend bool operator!=(const EnumeratedIterator<EnumType>& aIter1,
75 const EnumeratedIterator<EnumType>& aIter2);
76 template <typename EnumType>
77 friend bool operator<(const EnumeratedIterator<EnumType>& aIter1,
78 const EnumeratedIterator<EnumType>& aIter2);
79 template <typename EnumType>
80 friend bool operator<=(const EnumeratedIterator<EnumType>& aIter1,
81 const EnumeratedIterator<EnumType>& aIter2);
82 template <typename EnumType>
83 friend bool operator>(const EnumeratedIterator<EnumType>& aIter1,
84 const EnumeratedIterator<EnumType>& aIter2);
85 template <typename EnumType>
86 friend bool operator>=(const EnumeratedIterator<EnumType>& aIter1,
87 const EnumeratedIterator<EnumType>& aIter2);
89 private:
90 EnumTypeT mCurrent;
93 template <typename EnumType>
94 bool operator==(const EnumeratedIterator<EnumType>& aIter1,
95 const EnumeratedIterator<EnumType>& aIter2) {
96 return aIter1.mCurrent == aIter2.mCurrent;
99 template <typename EnumType>
100 bool operator!=(const EnumeratedIterator<EnumType>& aIter1,
101 const EnumeratedIterator<EnumType>& aIter2) {
102 return aIter1.mCurrent != aIter2.mCurrent;
105 template <typename EnumType>
106 bool operator<(const EnumeratedIterator<EnumType>& aIter1,
107 const EnumeratedIterator<EnumType>& aIter2) {
108 return aIter1.mCurrent < aIter2.mCurrent;
111 template <typename EnumType>
112 bool operator<=(const EnumeratedIterator<EnumType>& aIter1,
113 const EnumeratedIterator<EnumType>& aIter2) {
114 return aIter1.mCurrent <= aIter2.mCurrent;
117 template <typename EnumType>
118 bool operator>(const EnumeratedIterator<EnumType>& aIter1,
119 const EnumeratedIterator<EnumType>& aIter2) {
120 return aIter1.mCurrent > aIter2.mCurrent;
123 template <typename EnumType>
124 bool operator>=(const EnumeratedIterator<EnumType>& aIter1,
125 const EnumeratedIterator<EnumType>& aIter2) {
126 return aIter1.mCurrent >= aIter2.mCurrent;
129 template <typename EnumTypeT>
130 class EnumeratedRange {
131 public:
132 typedef EnumeratedIterator<EnumTypeT> iterator;
133 typedef EnumeratedIterator<EnumTypeT> const_iterator;
134 typedef ReverseIterator<iterator> reverse_iterator;
135 typedef ReverseIterator<const_iterator> const_reverse_iterator;
137 template <typename EnumType>
138 constexpr EnumeratedRange(EnumType aBegin, EnumType aEnd)
139 : mBegin(aBegin), mEnd(aEnd) {}
141 iterator begin() const { return iterator(mBegin); }
142 const_iterator cbegin() const { return begin(); }
143 iterator end() const { return iterator(mEnd); }
144 const_iterator cend() const { return end(); }
145 reverse_iterator rbegin() const { return reverse_iterator(mEnd); }
146 const_reverse_iterator crbegin() const { return rbegin(); }
147 reverse_iterator rend() const { return reverse_iterator(mBegin); }
148 const_reverse_iterator crend() const { return rend(); }
150 private:
151 EnumTypeT mBegin;
152 EnumTypeT mEnd;
155 } // namespace detail
157 #ifdef __GNUC__
158 // Enums can have an unsigned underlying type, which makes some of the
159 // comparisons below always true or always false. Temporarily disable
160 // -Wtype-limits to avoid breaking -Werror builds.
161 # pragma GCC diagnostic push
162 # pragma GCC diagnostic ignored "-Wtype-limits"
163 #endif
165 // Create a range to iterate from aBegin to aEnd, exclusive.
166 template <typename EnumType>
167 constexpr detail::EnumeratedRange<EnumType> MakeEnumeratedRange(EnumType aBegin,
168 EnumType aEnd) {
169 MOZ_ASSERT(aBegin <= aEnd, "Cannot generate invalid, unbounded range!");
170 return detail::EnumeratedRange<EnumType>(aBegin, aEnd);
173 // Create a range to iterate from EnumType(0) to aEnd, exclusive. EnumType(0)
174 // should exist, but note that there is no way for us to ensure that it does!
175 template <typename EnumType>
176 constexpr detail::EnumeratedRange<EnumType> MakeEnumeratedRange(EnumType aEnd) {
177 return MakeEnumeratedRange(EnumType(0), aEnd);
180 // Create a range to iterate from aBegin to aEnd, inclusive.
182 // NOTE: This internally constructs a value that is one past `aEnd`, so the
183 // enumeration needs to either have a fixed underlying type, or `aEnd + 1` must
184 // be inside the range of the enumeration, in order to not be undefined
185 // behavior.
187 // See bug 1614512.
188 template <typename EnumType>
189 constexpr detail::EnumeratedRange<EnumType> MakeInclusiveEnumeratedRange(
190 EnumType aBegin, EnumType aEnd) {
191 using EnumUnderlyingType = typename std::underlying_type_t<EnumType>;
192 const auto end = static_cast<EnumUnderlyingType>(aEnd);
194 MOZ_ASSERT(end != std::numeric_limits<EnumUnderlyingType>::max(),
195 "aEnd shouldn't overflow!");
196 return MakeEnumeratedRange(aBegin, static_cast<EnumType>(end + 1));
199 #ifdef __GNUC__
200 # pragma GCC diagnostic pop
201 #endif
203 } // namespace mozilla
205 #endif // mozilla_EnumeratedRange_h