| //===- iterator.h - Utilities for using and defining iterators --*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_ADT_ITERATOR_H |
| #define LLVM_ADT_ITERATOR_H |
| |
| #include "llvm/ADT/iterator_range.h" |
| #include <cstddef> |
| #include <iterator> |
| #include <type_traits> |
| #include <utility> |
| |
| namespace llvm { |
| |
| /// CRTP base class which implements the entire standard iterator facade |
| /// in terms of a minimal subset of the interface. |
| /// |
| /// Use this when it is reasonable to implement most of the iterator |
| /// functionality in terms of a core subset. If you need special behavior or |
| /// there are performance implications for this, you may want to override the |
| /// relevant members instead. |
| /// |
| /// Note, one abstraction that this does *not* provide is implementing |
| /// subtraction in terms of addition by negating the difference. Negation isn't |
| /// always information preserving, and I can see very reasonable iterator |
| /// designs where this doesn't work well. It doesn't really force much added |
| /// boilerplate anyways. |
| /// |
| /// Another abstraction that this doesn't provide is implementing increment in |
| /// terms of addition of one. These aren't equivalent for all iterator |
| /// categories, and respecting that adds a lot of complexity for little gain. |
| /// |
| /// Iterators are expected to have const rules analogous to pointers, with a |
| /// single, const-qualified operator*() that returns ReferenceT. This matches |
| /// the second and third pointers in the following example: |
| /// \code |
| /// int Value; |
| /// { int *I = &Value; } // ReferenceT 'int&' |
| /// { int *const I = &Value; } // ReferenceT 'int&'; const |
| /// { const int *I = &Value; } // ReferenceT 'const int&' |
| /// { const int *const I = &Value; } // ReferenceT 'const int&'; const |
| /// \endcode |
| /// If an iterator facade returns a handle to its own state, then T (and |
| /// PointerT and ReferenceT) should usually be const-qualified. Otherwise, if |
| /// clients are expected to modify the handle itself, the field can be declared |
| /// mutable or use const_cast. |
| /// |
| /// Classes wishing to use `iterator_facade_base` should implement the following |
| /// methods: |
| /// |
| /// Forward Iterators: |
| /// (All of the following methods) |
| /// - DerivedT &operator=(const DerivedT &R); |
| /// - bool operator==(const DerivedT &R) const; |
| /// - T &operator*() const; |
| /// - DerivedT &operator++(); |
| /// |
| /// Bidirectional Iterators: |
| /// (All methods of forward iterators, plus the following) |
| /// - DerivedT &operator--(); |
| /// |
| /// Random-access Iterators: |
| /// (All methods of bidirectional iterators excluding the following) |
| /// - DerivedT &operator++(); |
| /// - DerivedT &operator--(); |
| /// (and plus the following) |
| /// - bool operator<(const DerivedT &RHS) const; |
| /// - DifferenceTypeT operator-(const DerivedT &R) const; |
| /// - DerivedT &operator+=(DifferenceTypeT N); |
| /// - DerivedT &operator-=(DifferenceTypeT N); |
| /// |
| template <typename DerivedT, typename IteratorCategoryT, typename T, |
| typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *, |
| typename ReferenceT = T &> |
| class iterator_facade_base { |
| public: |
| using iterator_category = IteratorCategoryT; |
| using value_type = T; |
| using difference_type = DifferenceTypeT; |
| using pointer = PointerT; |
| using reference = ReferenceT; |
| |
| protected: |
| enum { |
| IsRandomAccess = std::is_base_of<std::random_access_iterator_tag, |
| IteratorCategoryT>::value, |
| IsBidirectional = std::is_base_of<std::bidirectional_iterator_tag, |
| IteratorCategoryT>::value, |
| }; |
| |
| /// A proxy object for computing a reference via indirecting a copy of an |
| /// iterator. This is used in APIs which need to produce a reference via |
| /// indirection but for which the iterator object might be a temporary. The |
| /// proxy preserves the iterator internally and exposes the indirected |
| /// reference via a conversion operator. |
| class ReferenceProxy { |
| friend iterator_facade_base; |
| |
| DerivedT I; |
| |
| ReferenceProxy(DerivedT I) : I(std::move(I)) {} |
| |
| public: |
| operator ReferenceT() const { return *I; } |
| }; |
| |
| /// A proxy object for computing a pointer via indirecting a copy of a |
| /// reference. This is used in APIs which need to produce a pointer but for |
| /// which the reference might be a temporary. The proxy preserves the |
| /// reference internally and exposes the pointer via a arrow operator. |
| class PointerProxy { |
| friend iterator_facade_base; |
| |
| ReferenceT R; |
| |
| template <typename RefT> |
| PointerProxy(RefT &&R) : R(std::forward<RefT>(R)) {} |
| |
| public: |
| PointerT operator->() const { return &R; } |
| }; |
| |
| public: |
| DerivedT operator+(DifferenceTypeT n) const { |
| static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value, |
| "Must pass the derived type to this template!"); |
| static_assert( |
| IsRandomAccess, |
| "The '+' operator is only defined for random access iterators."); |
| DerivedT tmp = *static_cast<const DerivedT *>(this); |
| tmp += n; |
| return tmp; |
| } |
| friend DerivedT operator+(DifferenceTypeT n, const DerivedT &i) { |
| static_assert( |
| IsRandomAccess, |
| "The '+' operator is only defined for random access iterators."); |
| return i + n; |
| } |
| DerivedT operator-(DifferenceTypeT n) const { |
| static_assert( |
| IsRandomAccess, |
| "The '-' operator is only defined for random access iterators."); |
| DerivedT tmp = *static_cast<const DerivedT *>(this); |
| tmp -= n; |
| return tmp; |
| } |
| |
| DerivedT &operator++() { |
| static_assert(std::is_base_of<iterator_facade_base, DerivedT>::value, |
| "Must pass the derived type to this template!"); |
| return static_cast<DerivedT *>(this)->operator+=(1); |
| } |
| DerivedT operator++(int) { |
| DerivedT tmp = *static_cast<DerivedT *>(this); |
| ++*static_cast<DerivedT *>(this); |
| return tmp; |
| } |
| DerivedT &operator--() { |
| static_assert( |
| IsBidirectional, |
| "The decrement operator is only defined for bidirectional iterators."); |
| return static_cast<DerivedT *>(this)->operator-=(1); |
| } |
| DerivedT operator--(int) { |
| static_assert( |
| IsBidirectional, |
| "The decrement operator is only defined for bidirectional iterators."); |
| DerivedT tmp = *static_cast<DerivedT *>(this); |
| --*static_cast<DerivedT *>(this); |
| return tmp; |
| } |
| |
| #ifndef __cpp_impl_three_way_comparison |
| bool operator!=(const DerivedT &RHS) const { |
| return !(static_cast<const DerivedT &>(*this) == RHS); |
| } |
| #endif |
| |
| bool operator>(const DerivedT &RHS) const { |
| static_assert( |
| IsRandomAccess, |
| "Relational operators are only defined for random access iterators."); |
| return !(static_cast<const DerivedT &>(*this) < RHS) && |
| !(static_cast<const DerivedT &>(*this) == RHS); |
| } |
| bool operator<=(const DerivedT &RHS) const { |
| static_assert( |
| IsRandomAccess, |
| "Relational operators are only defined for random access iterators."); |
| return !(static_cast<const DerivedT &>(*this) > RHS); |
| } |
| bool operator>=(const DerivedT &RHS) const { |
| static_assert( |
| IsRandomAccess, |
| "Relational operators are only defined for random access iterators."); |
| return !(static_cast<const DerivedT &>(*this) < RHS); |
| } |
| |
| PointerProxy operator->() const { |
| return static_cast<const DerivedT *>(this)->operator*(); |
| } |
| ReferenceProxy operator[](DifferenceTypeT n) const { |
| static_assert(IsRandomAccess, |
| "Subscripting is only defined for random access iterators."); |
| return static_cast<const DerivedT *>(this)->operator+(n); |
| } |
| }; |
| |
| /// CRTP base class for adapting an iterator to a different type. |
| /// |
| /// This class can be used through CRTP to adapt one iterator into another. |
| /// Typically this is done through providing in the derived class a custom \c |
| /// operator* implementation. Other methods can be overridden as well. |
| template < |
| typename DerivedT, typename WrappedIteratorT, |
| typename IteratorCategoryT = |
| typename std::iterator_traits<WrappedIteratorT>::iterator_category, |
| typename T = typename std::iterator_traits<WrappedIteratorT>::value_type, |
| typename DifferenceTypeT = |
| typename std::iterator_traits<WrappedIteratorT>::difference_type, |
| typename PointerT = std::conditional_t< |
| std::is_same<T, typename std::iterator_traits< |
| WrappedIteratorT>::value_type>::value, |
| typename std::iterator_traits<WrappedIteratorT>::pointer, T *>, |
| typename ReferenceT = std::conditional_t< |
| std::is_same<T, typename std::iterator_traits< |
| WrappedIteratorT>::value_type>::value, |
| typename std::iterator_traits<WrappedIteratorT>::reference, T &>> |
| class iterator_adaptor_base |
| : public iterator_facade_base<DerivedT, IteratorCategoryT, T, |
| DifferenceTypeT, PointerT, ReferenceT> { |
| using BaseT = typename iterator_adaptor_base::iterator_facade_base; |
| |
| protected: |
| WrappedIteratorT I; |
| |
| iterator_adaptor_base() = default; |
| |
| explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) { |
| static_assert(std::is_base_of<iterator_adaptor_base, DerivedT>::value, |
| "Must pass the derived type to this template!"); |
| } |
| |
| const WrappedIteratorT &wrapped() const { return I; } |
| |
| public: |
| using difference_type = DifferenceTypeT; |
| |
| DerivedT &operator+=(difference_type n) { |
| static_assert( |
| BaseT::IsRandomAccess, |
| "The '+=' operator is only defined for random access iterators."); |
| I += n; |
| return *static_cast<DerivedT *>(this); |
| } |
| DerivedT &operator-=(difference_type n) { |
| static_assert( |
| BaseT::IsRandomAccess, |
| "The '-=' operator is only defined for random access iterators."); |
| I -= n; |
| return *static_cast<DerivedT *>(this); |
| } |
| using BaseT::operator-; |
| difference_type operator-(const DerivedT &RHS) const { |
| static_assert( |
| BaseT::IsRandomAccess, |
| "The '-' operator is only defined for random access iterators."); |
| return I - RHS.I; |
| } |
| |
| // We have to explicitly provide ++ and -- rather than letting the facade |
| // forward to += because WrappedIteratorT might not support +=. |
| using BaseT::operator++; |
| DerivedT &operator++() { |
| ++I; |
| return *static_cast<DerivedT *>(this); |
| } |
| using BaseT::operator--; |
| DerivedT &operator--() { |
| static_assert( |
| BaseT::IsBidirectional, |
| "The decrement operator is only defined for bidirectional iterators."); |
| --I; |
| return *static_cast<DerivedT *>(this); |
| } |
| |
| friend bool operator==(const iterator_adaptor_base &LHS, |
| const iterator_adaptor_base &RHS) { |
| return LHS.I == RHS.I; |
| } |
| friend bool operator<(const iterator_adaptor_base &LHS, |
| const iterator_adaptor_base &RHS) { |
| static_assert( |
| BaseT::IsRandomAccess, |
| "Relational operators are only defined for random access iterators."); |
| return LHS.I < RHS.I; |
| } |
| |
| ReferenceT operator*() const { return *I; } |
| }; |
| |
| /// An iterator type that allows iterating over the pointees via some |
| /// other iterator. |
| /// |
| /// The typical usage of this is to expose a type that iterates over Ts, but |
| /// which is implemented with some iterator over T*s: |
| /// |
| /// \code |
| /// using iterator = pointee_iterator<SmallVectorImpl<T *>::iterator>; |
| /// \endcode |
| template <typename WrappedIteratorT, |
| typename T = std::remove_reference_t<decltype( |
| **std::declval<WrappedIteratorT>())>> |
| struct pointee_iterator |
| : iterator_adaptor_base< |
| pointee_iterator<WrappedIteratorT, T>, WrappedIteratorT, |
| typename std::iterator_traits<WrappedIteratorT>::iterator_category, |
| T> { |
| pointee_iterator() = default; |
| template <typename U> |
| pointee_iterator(U &&u) |
| : pointee_iterator::iterator_adaptor_base(std::forward<U &&>(u)) {} |
| |
| T &operator*() const { return **this->I; } |
| }; |
| |
| template <typename RangeT, typename WrappedIteratorT = |
| decltype(std::begin(std::declval<RangeT>()))> |
| iterator_range<pointee_iterator<WrappedIteratorT>> |
| make_pointee_range(RangeT &&Range) { |
| using PointeeIteratorT = pointee_iterator<WrappedIteratorT>; |
| return make_range(PointeeIteratorT(std::begin(std::forward<RangeT>(Range))), |
| PointeeIteratorT(std::end(std::forward<RangeT>(Range)))); |
| } |
| |
| template <typename WrappedIteratorT, |
| typename T = decltype(&*std::declval<WrappedIteratorT>())> |
| class pointer_iterator |
| : public iterator_adaptor_base< |
| pointer_iterator<WrappedIteratorT, T>, WrappedIteratorT, |
| typename std::iterator_traits<WrappedIteratorT>::iterator_category, |
| T> { |
| mutable T Ptr; |
| |
| public: |
| pointer_iterator() = default; |
| |
| explicit pointer_iterator(WrappedIteratorT u) |
| : pointer_iterator::iterator_adaptor_base(std::move(u)) {} |
| |
| T &operator*() const { return Ptr = &*this->I; } |
| }; |
| |
| template <typename RangeT, typename WrappedIteratorT = |
| decltype(std::begin(std::declval<RangeT>()))> |
| iterator_range<pointer_iterator<WrappedIteratorT>> |
| make_pointer_range(RangeT &&Range) { |
| using PointerIteratorT = pointer_iterator<WrappedIteratorT>; |
| return make_range(PointerIteratorT(std::begin(std::forward<RangeT>(Range))), |
| PointerIteratorT(std::end(std::forward<RangeT>(Range)))); |
| } |
| |
| template <typename WrappedIteratorT, |
| typename T1 = std::remove_reference_t<decltype( |
| **std::declval<WrappedIteratorT>())>, |
| typename T2 = std::add_pointer_t<T1>> |
| using raw_pointer_iterator = |
| pointer_iterator<pointee_iterator<WrappedIteratorT, T1>, T2>; |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_ADT_ITERATOR_H |