Skip to content

Commit 4fdccaf

Browse files
committed
Allow IntRange to range over enum values.
1 parent 8aab454 commit 4fdccaf

File tree

1 file changed

+70
-22
lines changed

1 file changed

+70
-22
lines changed

include/swift/Basic/Range.h

Lines changed: 70 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,47 @@ namespace swift {
6363
return result;
6464
}
6565

66-
/// A range of integers. This type behaves roughly like an ArrayRef.
67-
template <class T=unsigned> class IntRange {
68-
static_assert(std::is_integral<T>::value, "T must be an integer type");
66+
template <class T, bool IsEnum = std::is_enum<T>::value>
67+
struct IntRangeTraits;
68+
69+
template <class T>
70+
struct IntRangeTraits<T, /*is enum*/ false> {
71+
static_assert(std::is_integral<T>::value,
72+
"argument type of IntRange is either an integer nor an enum");
73+
using int_type = T;
74+
using difference_type = typename std::make_signed<int_type>::type;
75+
76+
static T addOffset(T value, difference_type quantity) {
77+
return T(difference_type(value) + quantity);
78+
}
79+
static difference_type distance(T begin, T end) {
80+
return difference_type(end) - difference_type(begin);
81+
}
82+
};
83+
84+
template <class T>
85+
struct IntRangeTraits<T, /*is enum*/ true> {
86+
using int_type = typename std::underlying_type<T>::type;
87+
using difference_type = typename std::make_signed<int_type>::type;
88+
89+
static T addOffset(T value, difference_type quantity) {
90+
return T(difference_type(value) + quantity);
91+
}
92+
static difference_type distance(T begin, T end) {
93+
return difference_type(end) - difference_type(begin);
94+
}
95+
};
96+
97+
/// A range of integers or enum values. This type behaves roughly
98+
/// like an ArrayRef.
99+
template <class T = unsigned, class Traits = IntRangeTraits<T>>
100+
class IntRange {
69101
T Begin;
70102
T End;
103+
104+
using int_type = typename Traits::int_type;
105+
using difference_type = typename Traits::difference_type;
106+
71107
public:
72108
IntRange() : Begin(0), End(0) {}
73109
IntRange(T end) : Begin(0), End(end) {}
@@ -87,37 +123,48 @@ template <class T=unsigned> class IntRange {
87123
typedef std::random_access_iterator_tag iterator_category;
88124

89125
T operator*() const { return Value; }
90-
iterator &operator++() { Value++; return *this; }
91-
iterator operator++(int) { return iterator(Value++); }
126+
iterator &operator++() {
127+
return *this += 1;
128+
}
129+
iterator operator++(int) {
130+
auto copy = *this;
131+
*this += 1;
132+
return copy;
133+
}
92134
iterator &operator--() {
93-
Value--;
94-
return *this;
135+
return *this -= 1;
136+
}
137+
iterator operator--(int) {
138+
auto copy = *this;
139+
*this -= 1;
140+
return copy;
95141
}
96-
iterator operator--(int) { return iterator(Value--); }
97142
bool operator==(iterator rhs) { return Value == rhs.Value; }
98143
bool operator!=(iterator rhs) { return Value != rhs.Value; }
99144

100145
iterator &operator+=(difference_type i) {
101-
Value += T(i);
146+
Value = Traits::addOffset(Value, i);
102147
return *this;
103148
}
104149
iterator operator+(difference_type i) const {
105-
return iterator(Value + T(i));
150+
return iterator(Traits::adddOfset(Value, i));
106151
}
107152
friend iterator operator+(difference_type i, iterator base) {
108-
return iterator(base.Value + T(i));
153+
return iterator(Traits::addOffset(base.Value, i));
109154
}
110155
iterator &operator-=(difference_type i) {
111-
Value -= T(i);
156+
Value = Traits::addOffset(Value, -i);
112157
return *this;
113158
}
114159
iterator operator-(difference_type i) const {
115-
return iterator(Value - T(i));
160+
return iterator(Traits::addOffset(Value, -i));
116161
}
117162
difference_type operator-(iterator rhs) const {
118-
return difference_type(Value - rhs.Value);
163+
return Traits::distance(rhs.Value, Value);
164+
}
165+
T operator[](difference_type i) const {
166+
return Traits::addOffset(Value, i);
119167
}
120-
T operator[](difference_type i) const { return Value + T(i); }
121168
bool operator<(iterator rhs) const { return Value < rhs.Value; }
122169
bool operator<=(iterator rhs) const { return Value <= rhs.Value; }
123170
bool operator>(iterator rhs) const { return Value > rhs.Value; }
@@ -134,26 +181,27 @@ template <class T=unsigned> class IntRange {
134181
}
135182

136183
bool empty() const { return Begin == End; }
137-
size_t size() const { return End - Begin; }
184+
size_t size() const { return size_t(Traits::distance(Begin, End)); }
138185
T operator[](size_t i) const {
139186
assert(i < size());
140-
return Begin + i;
187+
return Traits::addOffset(Begin, i);
141188
}
142189
T front() const { assert(!empty()); return Begin; }
143-
T back() const { assert(!empty()); return End - 1; }
190+
T back() const { assert(!empty()); return Traits::addOffset(End, -1); }
144191
IntRange drop_back(size_t length = 1) const {
145192
assert(length <= size());
146-
return IntRange(Begin, End - length);
193+
return IntRange(Begin, Traits::addOffset(End, -length));
147194
}
148195

149196
IntRange slice(size_t start) const {
150197
assert(start <= size());
151-
return IntRange(Begin + start, End);
198+
return IntRange(Traits::addOffset(Begin, start), End);
152199
}
153200
IntRange slice(size_t start, size_t length) const {
154201
assert(start <= size());
155-
return IntRange(Begin + start,
156-
Begin + start + std::min(length, End - (Begin + start)));
202+
auto newBegin = Traits::addOffset(Begin, start);
203+
auto newSize = std::min(length, size_t(Traits::distance(newBegin, End)));
204+
return IntRange(newBegin, Traits::addOffset(newBegin, newSize));
157205
}
158206

159207
bool operator==(IntRange other) const {

0 commit comments

Comments
 (0)