LLVM 22.0.0git
iterator.h
Go to the documentation of this file.
1//===- iterator.h - Utilities for using and defining iterators --*- C++ -*-===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#ifndef LLVM_ADT_ITERATOR_H
10#define LLVM_ADT_ITERATOR_H
11
13#include <cstddef>
14#include <iterator>
15#include <type_traits>
16#include <utility>
17
18namespace llvm {
19
20/// CRTP base class which implements the entire standard iterator facade
21/// in terms of a minimal subset of the interface.
22///
23/// Use this when it is reasonable to implement most of the iterator
24/// functionality in terms of a core subset. If you need special behavior or
25/// there are performance implications for this, you may want to override the
26/// relevant members instead.
27///
28/// Note, one abstraction that this does *not* provide is implementing
29/// subtraction in terms of addition by negating the difference. Negation isn't
30/// always information preserving, and I can see very reasonable iterator
31/// designs where this doesn't work well. It doesn't really force much added
32/// boilerplate anyways.
33///
34/// Another abstraction that this doesn't provide is implementing increment in
35/// terms of addition of one. These aren't equivalent for all iterator
36/// categories, and respecting that adds a lot of complexity for little gain.
37///
38/// Iterators are expected to have const rules analogous to pointers, with a
39/// single, const-qualified operator*() that returns ReferenceT. This matches
40/// the second and third pointers in the following example:
41/// \code
42/// int Value;
43/// { int *I = &Value; } // ReferenceT 'int&'
44/// { int *const I = &Value; } // ReferenceT 'int&'; const
45/// { const int *I = &Value; } // ReferenceT 'const int&'
46/// { const int *const I = &Value; } // ReferenceT 'const int&'; const
47/// \endcode
48/// If an iterator facade returns a handle to its own state, then T (and
49/// PointerT and ReferenceT) should usually be const-qualified. Otherwise, if
50/// clients are expected to modify the handle itself, the field can be declared
51/// mutable or use const_cast.
52///
53/// Classes wishing to use `iterator_facade_base` should implement the following
54/// methods:
55///
56/// Forward Iterators:
57/// (All of the following methods)
58/// - DerivedT &operator=(const DerivedT &R);
59/// - bool operator==(const DerivedT &R) const;
60/// - T &operator*() const;
61/// - DerivedT &operator++();
62///
63/// Bidirectional Iterators:
64/// (All methods of forward iterators, plus the following)
65/// - DerivedT &operator--();
66///
67/// Random-access Iterators:
68/// (All methods of bidirectional iterators excluding the following)
69/// - DerivedT &operator++();
70/// - DerivedT &operator--();
71/// (and plus the following)
72/// - bool operator<(const DerivedT &RHS) const;
73/// - DifferenceTypeT operator-(const DerivedT &R) const;
74/// - DerivedT &operator+=(DifferenceTypeT N);
75/// - DerivedT &operator-=(DifferenceTypeT N);
76///
77template <typename DerivedT, typename IteratorCategoryT, typename T,
78 typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *,
79 typename ReferenceT = T &>
81public:
82 using iterator_category = IteratorCategoryT;
83 using value_type = T;
84 using difference_type = DifferenceTypeT;
85 using pointer = PointerT;
86 using reference = ReferenceT;
87
88 // Note: These were previously protected, but MSVC has trouble with SFINAE
89 // accessing protected members in derived class templates (specifically in
90 // iterator_adaptor_base::operator-). Making them public fixes the build.
91 enum {
92 IsRandomAccess = std::is_base_of<std::random_access_iterator_tag,
93 IteratorCategoryT>::value,
94 IsBidirectional = std::is_base_of<std::bidirectional_iterator_tag,
95 IteratorCategoryT>::value,
96 };
97
98protected:
99 /// A proxy object for computing a reference via indirecting a copy of an
100 /// iterator. This is used in APIs which need to produce a reference via
101 /// indirection but for which the iterator object might be a temporary. The
102 /// proxy preserves the iterator internally and exposes the indirected
103 /// reference via a conversion operator.
104 class ReferenceProxy {
105 friend iterator_facade_base;
106
107 DerivedT I;
108
109 ReferenceProxy(DerivedT I) : I(std::move(I)) {}
110
111 public:
112 operator ReferenceT() const { return *I; }
113 };
114
115 /// A proxy object for computing a pointer via indirecting a copy of a
116 /// reference. This is used in APIs which need to produce a pointer but for
117 /// which the reference might be a temporary. The proxy preserves the
118 /// reference internally and exposes the pointer via a arrow operator.
119 class PointerProxy {
120 friend iterator_facade_base;
121
122 ReferenceT R;
123
124 template <typename RefT>
125 PointerProxy(RefT &&R) : R(std::forward<RefT>(R)) {}
126
127 public:
128 PointerT operator->() const { return &R; }
129 };
130
131public:
132 DerivedT operator+(DifferenceTypeT n) const {
133 static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
134 "Must pass the derived type to this template!");
135 static_assert(
137 "The '+' operator is only defined for random access iterators.");
138 DerivedT tmp = *static_cast<const DerivedT *>(this);
139 tmp += n;
140 return tmp;
141 }
142 friend DerivedT operator+(DifferenceTypeT n, const DerivedT &i) {
143 static_assert(
145 "The '+' operator is only defined for random access iterators.");
146 return i + n;
147 }
148 DerivedT operator-(DifferenceTypeT n) const {
149 static_assert(
151 "The '-' operator is only defined for random access iterators.");
152 DerivedT tmp = *static_cast<const DerivedT *>(this);
153 tmp -= n;
154 return tmp;
155 }
156
157 DerivedT &operator++() {
158 static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value,
159 "Must pass the derived type to this template!");
160 return static_cast<DerivedT *>(this)->operator+=(1);
161 }
162 DerivedT operator++(int) {
163 DerivedT tmp = *static_cast<DerivedT *>(this);
164 ++*static_cast<DerivedT *>(this);
165 return tmp;
166 }
167 DerivedT &operator--() {
168 static_assert(
170 "The decrement operator is only defined for bidirectional iterators.");
171 return static_cast<DerivedT *>(this)->operator-=(1);
172 }
173 DerivedT operator--(int) {
174 static_assert(
176 "The decrement operator is only defined for bidirectional iterators.");
177 DerivedT tmp = *static_cast<DerivedT *>(this);
178 --*static_cast<DerivedT *>(this);
179 return tmp;
180 }
181
182#ifndef __cpp_impl_three_way_comparison
183 bool operator!=(const DerivedT &RHS) const {
184 return !(static_cast<const DerivedT &>(*this) == RHS);
185 }
186#endif
187
188 bool operator>(const DerivedT &RHS) const {
189 static_assert(
191 "Relational operators are only defined for random access iterators.");
192 return !(static_cast<const DerivedT &>(*this) < RHS) &&
193 !(static_cast<const DerivedT &>(*this) == RHS);
194 }
195 bool operator<=(const DerivedT &RHS) const {
196 static_assert(
198 "Relational operators are only defined for random access iterators.");
199 return !(static_cast<const DerivedT &>(*this) > RHS);
200 }
201 bool operator>=(const DerivedT &RHS) const {
202 static_assert(
204 "Relational operators are only defined for random access iterators.");
205 return !(static_cast<const DerivedT &>(*this) < RHS);
206 }
207
208 PointerProxy operator->() const {
209 return static_cast<const DerivedT *>(this)->operator*();
210 }
211 ReferenceProxy operator[](DifferenceTypeT n) const {
212 static_assert(IsRandomAccess,
213 "Subscripting is only defined for random access iterators.");
214 return static_cast<const DerivedT *>(this)->operator+(n);
215 }
216};
217
218/// CRTP base class for adapting an iterator to a different type.
219///
220/// This class can be used through CRTP to adapt one iterator into another.
221/// Typically this is done through providing in the derived class a custom \c
222/// operator* implementation. Other methods can be overridden as well.
223template <
224 typename DerivedT, typename WrappedIteratorT,
225 typename IteratorCategoryT =
226 typename std::iterator_traits<WrappedIteratorT>::iterator_category,
227 typename T = typename std::iterator_traits<WrappedIteratorT>::value_type,
228 typename DifferenceTypeT =
229 typename std::iterator_traits<WrappedIteratorT>::difference_type,
230 typename PointerT = std::conditional_t<
231 std::is_same<T, typename std::iterator_traits<
232 WrappedIteratorT>::value_type>::value,
233 typename std::iterator_traits<WrappedIteratorT>::pointer, T *>,
234 typename ReferenceT = std::conditional_t<
235 std::is_same<T, typename std::iterator_traits<
236 WrappedIteratorT>::value_type>::value,
237 typename std::iterator_traits<WrappedIteratorT>::reference, T &>>
239 : public iterator_facade_base<DerivedT, IteratorCategoryT, T,
240 DifferenceTypeT, PointerT, ReferenceT> {
241 using BaseT = typename iterator_adaptor_base::iterator_facade_base;
242
243protected:
245
247
249 static_assert(std::is_base_of<iterator_adaptor_base, DerivedT>::value,
250 "Must pass the derived type to this template!");
251 }
252
253 const WrappedIteratorT &wrapped() const { return I; }
254
255public:
256 using difference_type = DifferenceTypeT;
257
259 static_assert(
260 BaseT::IsRandomAccess,
261 "The '+=' operator is only defined for random access iterators.");
262 I += n;
263 return *static_cast<DerivedT *>(this);
264 }
266 static_assert(
267 BaseT::IsRandomAccess,
268 "The '-=' operator is only defined for random access iterators.");
269 I -= n;
270 return *static_cast<DerivedT *>(this);
271 }
272 using BaseT::operator-;
273 template <bool Enabled = BaseT::IsRandomAccess,
274 typename = std::enable_if_t<Enabled>>
275 difference_type operator-(const DerivedT &RHS) const {
276 static_assert(
277 BaseT::IsRandomAccess,
278 "The '-' operator is only defined for random access iterators.");
279 return I - RHS.I;
280 }
281
282 // We have to explicitly provide ++ and -- rather than letting the facade
283 // forward to += because WrappedIteratorT might not support +=.
284 using BaseT::operator++;
285 DerivedT &operator++() {
286 ++I;
287 return *static_cast<DerivedT *>(this);
288 }
289 using BaseT::operator--;
290 DerivedT &operator--() {
291 static_assert(
292 BaseT::IsBidirectional,
293 "The decrement operator is only defined for bidirectional iterators.");
294 --I;
295 return *static_cast<DerivedT *>(this);
296 }
297
299 const iterator_adaptor_base &RHS) {
300 return LHS.I == RHS.I;
301 }
303 const iterator_adaptor_base &RHS) {
304 static_assert(
305 BaseT::IsRandomAccess,
306 "Relational operators are only defined for random access iterators.");
307 return LHS.I < RHS.I;
308 }
309
310 ReferenceT operator*() const { return *I; }
311};
312
313/// An iterator type that allows iterating over the pointees via some
314/// other iterator.
315///
316/// The typical usage of this is to expose a type that iterates over Ts, but
317/// which is implemented with some iterator over T*s:
318///
319/// \code
320/// using iterator = pointee_iterator<SmallVectorImpl<T *>::iterator>;
321/// \endcode
322template <typename WrappedIteratorT,
323 typename T = std::remove_reference_t<decltype(
324 **std::declval<WrappedIteratorT>())>>
328 typename std::iterator_traits<WrappedIteratorT>::iterator_category,
329 T> {
330 pointee_iterator() = default;
331 template <typename U>
333 : pointee_iterator::iterator_adaptor_base(std::forward<U &&>(u)) {}
334
335 T &operator*() const { return **this->I; }
336};
337
338template <typename RangeT, typename WrappedIteratorT =
339 decltype(std::begin(std::declval<RangeT>()))>
340iterator_range<pointee_iterator<WrappedIteratorT>>
342 using PointeeIteratorT = pointee_iterator<WrappedIteratorT>;
343 return make_range(PointeeIteratorT(std::begin(std::forward<RangeT>(Range))),
344 PointeeIteratorT(std::end(std::forward<RangeT>(Range))));
345}
346
347template <typename WrappedIteratorT,
348 typename T = decltype(&*std::declval<WrappedIteratorT>())>
350 : public iterator_adaptor_base<
352 typename std::iterator_traits<WrappedIteratorT>::iterator_category,
353 T> {
354 mutable T Ptr;
355
356public:
357 pointer_iterator() = default;
358
361
362 T &operator*() const { return Ptr = &*this->I; }
363};
364
365template <typename RangeT, typename WrappedIteratorT =
366 decltype(std::begin(std::declval<RangeT>()))>
367iterator_range<pointer_iterator<WrappedIteratorT>>
369 using PointerIteratorT = pointer_iterator<WrappedIteratorT>;
370 return make_range(PointerIteratorT(std::begin(std::forward<RangeT>(Range))),
371 PointerIteratorT(std::end(std::forward<RangeT>(Range))));
372}
373
374template <typename WrappedIteratorT,
375 typename T1 = std::remove_reference_t<decltype(
376 **std::declval<WrappedIteratorT>())>,
377 typename T2 = std::add_pointer_t<T1>>
380
381} // end namespace llvm
382
383#endif // LLVM_ADT_ITERATOR_H
#define I(x, y, z)
Definition MD5.cpp:57
#define T
#define T1
ConstantRange Range(APInt(BitWidth, Low), APInt(BitWidth, High))
Value * RHS
Value * LHS
iterator_adaptor_base(WrappedIteratorT u)
Definition iterator.h:248
const WrappedIteratorT & wrapped() const
Definition iterator.h:253
DerivedT & operator+=(difference_type n)
Definition iterator.h:258
difference_type operator-(const DerivedT &RHS) const
Definition iterator.h:275
friend bool operator<(const iterator_adaptor_base &LHS, const iterator_adaptor_base &RHS)
Definition iterator.h:302
DerivedT & operator-=(difference_type n)
Definition iterator.h:265
friend bool operator==(const iterator_adaptor_base &LHS, const iterator_adaptor_base &RHS)
Definition iterator.h:298
ReferenceT operator*() const
Definition iterator.h:310
CRTP base class which implements the entire standard iterator facade in terms of a minimal subset of ...
Definition iterator.h:80
PointerProxy operator->() const
Definition iterator.h:208
IteratorCategoryT iterator_category
Definition iterator.h:82
bool operator<=(const DerivedT &RHS) const
Definition iterator.h:195
bool operator>=(const DerivedT &RHS) const
Definition iterator.h:201
DerivedT operator--(int)
Definition iterator.h:173
DerivedT operator-(DifferenceTypeT n) const
Definition iterator.h:148
friend DerivedT operator+(DifferenceTypeT n, const DerivedT &i)
Definition iterator.h:142
DerivedT operator++(int)
Definition iterator.h:162
DifferenceTypeT difference_type
Definition iterator.h:84
bool operator!=(const DerivedT &RHS) const
Definition iterator.h:183
bool operator>(const DerivedT &RHS) const
Definition iterator.h:188
DerivedT operator+(DifferenceTypeT n) const
Definition iterator.h:132
ReferenceProxy operator[](DifferenceTypeT n) const
Definition iterator.h:211
T & operator*() const
Definition iterator.h:362
pointer_iterator(WrappedIteratorT u)
Definition iterator.h:359
This provides a very simple, boring adaptor for a begin and end iterator into a range type.
This is an optimization pass for GlobalISel generic memory operations.
pointer_iterator< pointee_iterator< WrappedIteratorT, T1 >, T2 > raw_pointer_iterator
Definition iterator.h:378
iterator_range< T > make_range(T x, T y)
Convenience function for iterating over sub-ranges.
iterator_range< pointee_iterator< WrappedIteratorT > > make_pointee_range(RangeT &&Range)
Definition iterator.h:341
iterator_range(Container &&) -> iterator_range< llvm::detail::IterOfRange< Container > >
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
Definition STLExtras.h:1915
iterator_range< pointer_iterator< WrappedIteratorT > > make_pointer_range(RangeT &&Range)
Definition iterator.h:368
@ Enabled
Convert any .debug_str_offsets tables to DWARF64 if needed.
Definition DWP.h:27
Implement std::hash so that hash_code can be used in STL containers.
Definition BitVector.h:870
An iterator type that allows iterating over the pointees via some other iterator.
Definition iterator.h:329
T & operator*() const
Definition iterator.h:335