@@ -147,24 +147,24 @@ using is_invocable = is_detected<detail::is_invocable, Callable, Args...>;
147
147
// Extra additions to <iterator>
148
148
// ===----------------------------------------------------------------------===//
149
149
150
- // / A utility class used to implement an iterator that contains some object and
151
- // / an index. The iterator moves the index but keeps the object constant.
152
- template <typename DerivedT, typename ObjectType , typename T,
150
+ // / A utility class used to implement an iterator that contains some base object
151
+ // / and an index. The iterator moves the index but keeps the base constant.
152
+ template <typename DerivedT, typename BaseT , typename T,
153
153
typename PointerT = T *, typename ReferenceT = T &>
154
154
class indexed_accessor_iterator
155
155
: public llvm::iterator_facade_base<DerivedT,
156
156
std::random_access_iterator_tag, T,
157
157
std::ptrdiff_t , PointerT, ReferenceT> {
158
158
public:
159
159
ptrdiff_t operator -(const indexed_accessor_iterator &rhs) const {
160
- assert (object == rhs.object && " incompatible iterators" );
160
+ assert (base == rhs.base && " incompatible iterators" );
161
161
return index - rhs.index ;
162
162
}
163
163
bool operator ==(const indexed_accessor_iterator &rhs) const {
164
- return object == rhs.object && index == rhs.index ;
164
+ return base == rhs.base && index == rhs.index ;
165
165
}
166
166
bool operator <(const indexed_accessor_iterator &rhs) const {
167
- assert (object == rhs.object && " incompatible iterators" );
167
+ assert (base == rhs.base && " incompatible iterators" );
168
168
return index < rhs.index ;
169
169
}
170
170
@@ -180,16 +180,134 @@ class indexed_accessor_iterator
180
180
// / Returns the current index of the iterator.
181
181
ptrdiff_t getIndex () const { return index; }
182
182
183
- // / Returns the current object of the iterator.
184
- const ObjectType & getObject () const { return object ; }
183
+ // / Returns the current base of the iterator.
184
+ const BaseT & getBase () const { return base ; }
185
185
186
186
protected:
187
- indexed_accessor_iterator (ObjectType object , ptrdiff_t index)
188
- : object(object ), index(index) {}
189
- ObjectType object ;
187
+ indexed_accessor_iterator (BaseT base , ptrdiff_t index)
188
+ : base(base ), index(index) {}
189
+ BaseT base ;
190
190
ptrdiff_t index;
191
191
};
192
192
193
+ namespace detail {
194
+ // / The class represents the base of a range of indexed_accessor_iterators. It
195
+ // / provides support for many different range functionalities, e.g.
196
+ // / drop_front/slice/etc.. Derived range classes must implement the following
197
+ // / static methods:
198
+ // / * ReferenceT dereference_iterator(const BaseT &base, ptrdiff_t index)
199
+ // / - Derefence an iterator pointing to the base object at the given index.
200
+ // / * BaseT offset_base(const BaseT &base, ptrdiff_t index)
201
+ // / - Return a new base that is offset from the provide base by 'index'
202
+ // / elements.
203
+ template <typename DerivedT, typename BaseT, typename T,
204
+ typename PointerT = T *, typename ReferenceT = T &>
205
+ class indexed_accessor_range_base {
206
+ public:
207
+ // / An iterator element of this range.
208
+ class iterator : public indexed_accessor_iterator <iterator, BaseT, T,
209
+ PointerT, ReferenceT> {
210
+ public:
211
+ // Index into this iterator, invoking a static method on the derived type.
212
+ ReferenceT operator *() const {
213
+ return DerivedT::dereference_iterator (this ->getBase (), this ->getIndex ());
214
+ }
215
+
216
+ private:
217
+ iterator (BaseT owner, ptrdiff_t curIndex)
218
+ : indexed_accessor_iterator<iterator, BaseT, T, PointerT, ReferenceT>(
219
+ owner, curIndex) {}
220
+
221
+ // / Allow access to the constructor.
222
+ friend indexed_accessor_range_base<DerivedT, BaseT, T, PointerT,
223
+ ReferenceT>;
224
+ };
225
+
226
+ iterator begin () const { return iterator (base, 0 ); }
227
+ iterator end () const { return iterator (base, count); }
228
+ ReferenceT operator [](unsigned index) const {
229
+ assert (index < size () && " invalid index for value range" );
230
+ return *std::next (begin (), index);
231
+ }
232
+
233
+ // / Return the size of this range.
234
+ size_t size () const { return count; }
235
+
236
+ // / Return if the range is empty.
237
+ bool empty () const { return size () == 0 ; }
238
+
239
+ // / Drop the first N elements, and keep M elements.
240
+ DerivedT slice (unsigned n, unsigned m) const {
241
+ assert (n + m <= size () && " invalid size specifiers" );
242
+ return DerivedT (DerivedT::offset_base (base, n), m);
243
+ }
244
+
245
+ // / Drop the first n elements.
246
+ DerivedT drop_front (unsigned n = 1 ) const {
247
+ assert (size () >= n && " Dropping more elements than exist" );
248
+ return slice (n, size () - n);
249
+ }
250
+ // / Drop the last n elements.
251
+ DerivedT drop_back (unsigned n = 1 ) const {
252
+ assert (size () >= n && " Dropping more elements than exist" );
253
+ return DerivedT (base, size () - n);
254
+ }
255
+
256
+ protected:
257
+ indexed_accessor_range_base (BaseT base, ptrdiff_t count)
258
+ : base(base), count(count) {}
259
+ indexed_accessor_range_base (const indexed_accessor_range_base &) = default ;
260
+ indexed_accessor_range_base (indexed_accessor_range_base &&) = default ;
261
+ indexed_accessor_range_base &
262
+ operator =(const indexed_accessor_range_base &) = default ;
263
+
264
+ // / The base that owns the provided range of values.
265
+ BaseT base;
266
+ // / The size from the owning range.
267
+ ptrdiff_t count;
268
+ };
269
+ } // end namespace detail
270
+
271
+ // / This class provides an implementation of a range of
272
+ // / indexed_accessor_iterators where the base is not indexable. Ranges with
273
+ // / bases that are offsetable should derive from indexed_accessor_range_base
274
+ // / instead. Derived range classes are expected to implement the following
275
+ // / static method:
276
+ // / * ReferenceT dereference_iterator(const BaseT &base, ptrdiff_t index)
277
+ // / - Derefence an iterator pointing to a parent base at the given index.
278
+ template <typename DerivedT, typename BaseT, typename T,
279
+ typename PointerT = T *, typename ReferenceT = T &>
280
+ class indexed_accessor_range
281
+ : public detail::indexed_accessor_range_base<
282
+ indexed_accessor_range<DerivedT, BaseT, T, PointerT, ReferenceT>,
283
+ std::pair<BaseT, ptrdiff_t >, T, PointerT, ReferenceT> {
284
+ protected:
285
+ indexed_accessor_range (BaseT base, ptrdiff_t startIndex, ptrdiff_t count)
286
+ : detail::indexed_accessor_range_base<
287
+ DerivedT, std::pair<BaseT, ptrdiff_t >, T, PointerT, ReferenceT>(
288
+ std::make_pair (base, startIndex), count) {}
289
+
290
+ private:
291
+ // / See `detail::indexed_accessor_range_base` for details.
292
+ static std::pair<BaseT, ptrdiff_t >
293
+ offset_base (const std::pair<BaseT, ptrdiff_t > &base, ptrdiff_t index) {
294
+ // We encode the internal base as a pair of the derived base and a start
295
+ // index into the derived base.
296
+ return std::make_pair (base.first , base.second + index);
297
+ }
298
+ // / See `detail::indexed_accessor_range_base` for details.
299
+ static ReferenceT
300
+ dereference_iterator (const std::pair<BaseT, ptrdiff_t > &base,
301
+ ptrdiff_t index) {
302
+ return DerivedT::dereference_iterator (base.first , base.second + index);
303
+ }
304
+
305
+ // / Allow access to `offset_base` and `dereference_iterator`.
306
+ friend detail::indexed_accessor_range_base<
307
+ indexed_accessor_range<DerivedT, BaseT, T, PointerT, ReferenceT>,
308
+ std::pair<BaseT, ptrdiff_t >, T, PointerT, ReferenceT>;
309
+ };
310
+
193
311
// / Given a container of pairs, return a range over the second elements.
194
312
template <typename ContainerTy> auto make_second_range (ContainerTy &&c) {
195
313
return llvm::map_range (
0 commit comments