@@ -63,11 +63,47 @@ namespace swift {
63
63
return result;
64
64
}
65
65
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 {
69
101
T Begin;
70
102
T End;
103
+
104
+ using int_type = typename Traits::int_type;
105
+ using difference_type = typename Traits::difference_type;
106
+
71
107
public:
72
108
IntRange () : Begin(0 ), End(0 ) {}
73
109
IntRange (T end) : Begin(0 ), End(end) {}
@@ -87,37 +123,48 @@ template <class T=unsigned> class IntRange {
87
123
typedef std::random_access_iterator_tag iterator_category;
88
124
89
125
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
+ }
92
134
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;
95
141
}
96
- iterator operator --(int ) { return iterator (Value--); }
97
142
bool operator ==(iterator rhs) { return Value == rhs.Value ; }
98
143
bool operator !=(iterator rhs) { return Value != rhs.Value ; }
99
144
100
145
iterator &operator +=(difference_type i) {
101
- Value += T ( i);
146
+ Value = Traits::addOffset (Value, i);
102
147
return *this ;
103
148
}
104
149
iterator operator +(difference_type i) const {
105
- return iterator (Value + T ( i));
150
+ return iterator (Traits::adddOfset ( Value, i));
106
151
}
107
152
friend iterator operator +(difference_type i, iterator base) {
108
- return iterator (base.Value + T ( i));
153
+ return iterator (Traits::addOffset ( base.Value , i));
109
154
}
110
155
iterator &operator -=(difference_type i) {
111
- Value -= T ( i);
156
+ Value = Traits::addOffset (Value, - i);
112
157
return *this ;
113
158
}
114
159
iterator operator -(difference_type i) const {
115
- return iterator (Value - T ( i));
160
+ return iterator (Traits::addOffset ( Value, - i));
116
161
}
117
162
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);
119
167
}
120
- T operator [](difference_type i) const { return Value + T (i); }
121
168
bool operator <(iterator rhs) const { return Value < rhs.Value ; }
122
169
bool operator <=(iterator rhs) const { return Value <= rhs.Value ; }
123
170
bool operator >(iterator rhs) const { return Value > rhs.Value ; }
@@ -134,26 +181,27 @@ template <class T=unsigned> class IntRange {
134
181
}
135
182
136
183
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)) ; }
138
185
T operator [](size_t i) const {
139
186
assert (i < size ());
140
- return Begin + i ;
187
+ return Traits::addOffset ( Begin, i) ;
141
188
}
142
189
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 ) ; }
144
191
IntRange drop_back (size_t length = 1 ) const {
145
192
assert (length <= size ());
146
- return IntRange (Begin, End - length);
193
+ return IntRange (Begin, Traits::addOffset ( End, - length) );
147
194
}
148
195
149
196
IntRange slice (size_t start) const {
150
197
assert (start <= size ());
151
- return IntRange (Begin + start, End);
198
+ return IntRange (Traits::addOffset ( Begin, start) , End);
152
199
}
153
200
IntRange slice (size_t start, size_t length) const {
154
201
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));
157
205
}
158
206
159
207
bool operator ==(IntRange other) const {
0 commit comments