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 12 #include "llvm/ADT/iterator_range.h" 13 #include <cstddef> 14 #include <iterator> 15 #include <type_traits> 16 #include <utility> 17 18 namespace 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 /// 77 template <typename DerivedT, typename IteratorCategoryT, typename T, 78 typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *, 79 typename ReferenceT = T &> 80 class iterator_facade_base { 81 public: 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 protected: 89 enum { 90 IsRandomAccess = std::is_base_of<std::random_access_iterator_tag, 91 IteratorCategoryT>::value, 92 IsBidirectional = std::is_base_of<std::bidirectional_iterator_tag, 93 IteratorCategoryT>::value, 94 }; 95 96 /// A proxy object for computing a reference via indirecting a copy of an 97 /// iterator. This is used in APIs which need to produce a reference via 98 /// indirection but for which the iterator object might be a temporary. The 99 /// proxy preserves the iterator internally and exposes the indirected 100 /// reference via a conversion operator. 101 class ReferenceProxy { 102 friend iterator_facade_base; 103 104 DerivedT I; 105 106 ReferenceProxy(DerivedT I) : I(std::move(I)) {} 107 108 public: 109 operator ReferenceT() const { return *I; } 110 }; 111 112 /// A proxy object for computing a pointer via indirecting a copy of a 113 /// reference. This is used in APIs which need to produce a pointer but for 114 /// which the reference might be a temporary. The proxy preserves the 115 /// reference internally and exposes the pointer via a arrow operator. 116 class PointerProxy { 117 friend iterator_facade_base; 118 119 ReferenceT R; 120 121 template <typename RefT> 122 PointerProxy(RefT &&R) : R(std::forward<RefT>(R)) {} 123 124 public: 125 PointerT operator->() const { return &R; } 126 }; 127 128 public: 129 DerivedT operator+(DifferenceTypeT n) const { 130 static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value, 131 "Must pass the derived type to this template!"); 132 static_assert( 133 IsRandomAccess, 134 "The '+' operator is only defined for random access iterators."); 135 DerivedT tmp = *static_cast<const DerivedT *>(this); 136 tmp += n; 137 return tmp; 138 } 139 friend DerivedT operator+(DifferenceTypeT n, const DerivedT &i) { 140 static_assert( 141 IsRandomAccess, 142 "The '+' operator is only defined for random access iterators."); 143 return i + n; 144 } 145 DerivedT operator-(DifferenceTypeT n) const { 146 static_assert( 147 IsRandomAccess, 148 "The '-' operator is only defined for random access iterators."); 149 DerivedT tmp = *static_cast<const DerivedT *>(this); 150 tmp -= n; 151 return tmp; 152 } 153 154 DerivedT &operator++() { 155 static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value, 156 "Must pass the derived type to this template!"); 157 return static_cast<DerivedT *>(this)->operator+=(1); 158 } 159 DerivedT operator++(int) { 160 DerivedT tmp = *static_cast<DerivedT *>(this); 161 ++*static_cast<DerivedT *>(this); 162 return tmp; 163 } 164 DerivedT &operator--() { 165 static_assert( 166 IsBidirectional, 167 "The decrement operator is only defined for bidirectional iterators."); 168 return static_cast<DerivedT *>(this)->operator-=(1); 169 } 170 DerivedT operator--(int) { 171 static_assert( 172 IsBidirectional, 173 "The decrement operator is only defined for bidirectional iterators."); 174 DerivedT tmp = *static_cast<DerivedT *>(this); 175 --*static_cast<DerivedT *>(this); 176 return tmp; 177 } 178 179 #ifndef __cpp_impl_three_way_comparison 180 bool operator!=(const DerivedT &RHS) const { 181 return !(static_cast<const DerivedT &>(*this) == RHS); 182 } 183 #endif 184 185 bool operator>(const DerivedT &RHS) const { 186 static_assert( 187 IsRandomAccess, 188 "Relational operators are only defined for random access iterators."); 189 return !(static_cast<const DerivedT &>(*this) < RHS) && 190 !(static_cast<const DerivedT &>(*this) == RHS); 191 } 192 bool operator<=(const DerivedT &RHS) const { 193 static_assert( 194 IsRandomAccess, 195 "Relational operators are only defined for random access iterators."); 196 return !(static_cast<const DerivedT &>(*this) > RHS); 197 } 198 bool operator>=(const DerivedT &RHS) const { 199 static_assert( 200 IsRandomAccess, 201 "Relational operators are only defined for random access iterators."); 202 return !(static_cast<const DerivedT &>(*this) < RHS); 203 } 204 205 PointerProxy operator->() const { 206 return static_cast<const DerivedT *>(this)->operator*(); 207 } 208 ReferenceProxy operator[](DifferenceTypeT n) const { 209 static_assert(IsRandomAccess, 210 "Subscripting is only defined for random access iterators."); 211 return static_cast<const DerivedT *>(this)->operator+(n); 212 } 213 }; 214 215 /// CRTP base class for adapting an iterator to a different type. 216 /// 217 /// This class can be used through CRTP to adapt one iterator into another. 218 /// Typically this is done through providing in the derived class a custom \c 219 /// operator* implementation. Other methods can be overridden as well. 220 template < 221 typename DerivedT, typename WrappedIteratorT, 222 typename IteratorCategoryT = 223 typename std::iterator_traits<WrappedIteratorT>::iterator_category, 224 typename T = typename std::iterator_traits<WrappedIteratorT>::value_type, 225 typename DifferenceTypeT = 226 typename std::iterator_traits<WrappedIteratorT>::difference_type, 227 typename PointerT = std::conditional_t< 228 std::is_same<T, typename std::iterator_traits< 229 WrappedIteratorT>::value_type>::value, 230 typename std::iterator_traits<WrappedIteratorT>::pointer, T *>, 231 typename ReferenceT = std::conditional_t< 232 std::is_same<T, typename std::iterator_traits< 233 WrappedIteratorT>::value_type>::value, 234 typename std::iterator_traits<WrappedIteratorT>::reference, T &>> 235 class iterator_adaptor_base 236 : public iterator_facade_base<DerivedT, IteratorCategoryT, T, 237 DifferenceTypeT, PointerT, ReferenceT> { 238 using BaseT = typename iterator_adaptor_base::iterator_facade_base; 239 240 protected: 241 WrappedIteratorT I; 242 243 iterator_adaptor_base() = default; 244 245 explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) { 246 static_assert(std::is_base_of<iterator_adaptor_base, DerivedT>::value, 247 "Must pass the derived type to this template!"); 248 } 249 250 const WrappedIteratorT &wrapped() const { return I; } 251 252 public: 253 using difference_type = DifferenceTypeT; 254 255 DerivedT &operator+=(difference_type n) { 256 static_assert( 257 BaseT::IsRandomAccess, 258 "The '+=' operator is only defined for random access iterators."); 259 I += n; 260 return *static_cast<DerivedT *>(this); 261 } 262 DerivedT &operator-=(difference_type n) { 263 static_assert( 264 BaseT::IsRandomAccess, 265 "The '-=' operator is only defined for random access iterators."); 266 I -= n; 267 return *static_cast<DerivedT *>(this); 268 } 269 using BaseT::operator-; 270 difference_type operator-(const DerivedT &RHS) const { 271 static_assert( 272 BaseT::IsRandomAccess, 273 "The '-' operator is only defined for random access iterators."); 274 return I - RHS.I; 275 } 276 277 // We have to explicitly provide ++ and -- rather than letting the facade 278 // forward to += because WrappedIteratorT might not support +=. 279 using BaseT::operator++; 280 DerivedT &operator++() { 281 ++I; 282 return *static_cast<DerivedT *>(this); 283 } 284 using BaseT::operator--; 285 DerivedT &operator--() { 286 static_assert( 287 BaseT::IsBidirectional, 288 "The decrement operator is only defined for bidirectional iterators."); 289 --I; 290 return *static_cast<DerivedT *>(this); 291 } 292 293 friend bool operator==(const iterator_adaptor_base &LHS, 294 const iterator_adaptor_base &RHS) { 295 return LHS.I == RHS.I; 296 } 297 friend bool operator<(const iterator_adaptor_base &LHS, 298 const iterator_adaptor_base &RHS) { 299 static_assert( 300 BaseT::IsRandomAccess, 301 "Relational operators are only defined for random access iterators."); 302 return LHS.I < RHS.I; 303 } 304 305 ReferenceT operator*() const { return *I; } 306 }; 307 308 /// An iterator type that allows iterating over the pointees via some 309 /// other iterator. 310 /// 311 /// The typical usage of this is to expose a type that iterates over Ts, but 312 /// which is implemented with some iterator over T*s: 313 /// 314 /// \code 315 /// using iterator = pointee_iterator<SmallVectorImpl<T *>::iterator>; 316 /// \endcode 317 template <typename WrappedIteratorT, 318 typename T = std::remove_reference_t<decltype( 319 **std::declval<WrappedIteratorT>())>> 320 struct pointee_iterator 321 : iterator_adaptor_base< 322 pointee_iterator<WrappedIteratorT, T>, WrappedIteratorT, 323 typename std::iterator_traits<WrappedIteratorT>::iterator_category, 324 T> { 325 pointee_iterator() = default; 326 template <typename U> 327 pointee_iterator(U &&u) 328 : pointee_iterator::iterator_adaptor_base(std::forward<U &&>(u)) {} 329 330 T &operator*() const { return **this->I; } 331 }; 332 333 template <typename RangeT, typename WrappedIteratorT = 334 decltype(std::begin(std::declval<RangeT>()))> 335 iterator_range<pointee_iterator<WrappedIteratorT>> 336 make_pointee_range(RangeT &&Range) { 337 using PointeeIteratorT = pointee_iterator<WrappedIteratorT>; 338 return make_range(PointeeIteratorT(std::begin(std::forward<RangeT>(Range))), 339 PointeeIteratorT(std::end(std::forward<RangeT>(Range)))); 340 } 341 342 template <typename WrappedIteratorT, 343 typename T = decltype(&*std::declval<WrappedIteratorT>())> 344 class pointer_iterator 345 : public iterator_adaptor_base< 346 pointer_iterator<WrappedIteratorT, T>, WrappedIteratorT, 347 typename std::iterator_traits<WrappedIteratorT>::iterator_category, 348 T> { 349 mutable T Ptr; 350 351 public: 352 pointer_iterator() = default; 353 354 explicit pointer_iterator(WrappedIteratorT u) 355 : pointer_iterator::iterator_adaptor_base(std::move(u)) {} 356 357 T &operator*() const { return Ptr = &*this->I; } 358 }; 359 360 template <typename RangeT, typename WrappedIteratorT = 361 decltype(std::begin(std::declval<RangeT>()))> 362 iterator_range<pointer_iterator<WrappedIteratorT>> 363 make_pointer_range(RangeT &&Range) { 364 using PointerIteratorT = pointer_iterator<WrappedIteratorT>; 365 return make_range(PointerIteratorT(std::begin(std::forward<RangeT>(Range))), 366 PointerIteratorT(std::end(std::forward<RangeT>(Range)))); 367 } 368 369 template <typename WrappedIteratorT, 370 typename T1 = std::remove_reference_t<decltype( 371 **std::declval<WrappedIteratorT>())>, 372 typename T2 = std::add_pointer_t<T1>> 373 using raw_pointer_iterator = 374 pointer_iterator<pointee_iterator<WrappedIteratorT, T1>, T2>; 375 376 } // end namespace llvm 377 378 #endif // LLVM_ADT_ITERATOR_H 379