Home | History | Annotate | Download | only in ADT
      1 //===- iterator.h - Utilities for using and defining iterators --*- C++ -*-===//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 
     10 #ifndef LLVM_ADT_ITERATOR_H
     11 #define LLVM_ADT_ITERATOR_H
     12 
     13 #include <cstddef>
     14 #include <iterator>
     15 #include <type_traits>
     16 
     17 namespace llvm {
     18 
     19 /// \brief CRTP base class which implements the entire standard iterator facade
     20 /// in terms of a minimal subset of the interface.
     21 ///
     22 /// Use this when it is reasonable to implement most of the iterator
     23 /// functionality in terms of a core subset. If you need special behavior or
     24 /// there are performance implications for this, you may want to override the
     25 /// relevant members instead.
     26 ///
     27 /// Note, one abstraction that this does *not* provide is implementing
     28 /// subtraction in terms of addition by negating the difference. Negation isn't
     29 /// always information preserving, and I can see very reasonable iterator
     30 /// designs where this doesn't work well. It doesn't really force much added
     31 /// boilerplate anyways.
     32 ///
     33 /// Another abstraction that this doesn't provide is implementing increment in
     34 /// terms of addition of one. These aren't equivalent for all iterator
     35 /// categories, and respecting that adds a lot of complexity for little gain.
     36 template <typename DerivedT, typename IteratorCategoryT, typename T,
     37           typename DifferenceTypeT = std::ptrdiff_t, typename PointerT = T *,
     38           typename ReferenceT = T &>
     39 class iterator_facade_base
     40     : public std::iterator<IteratorCategoryT, T, DifferenceTypeT, PointerT,
     41                            ReferenceT> {
     42 protected:
     43   enum {
     44     IsRandomAccess =
     45         std::is_base_of<std::random_access_iterator_tag, IteratorCategoryT>::value,
     46     IsBidirectional =
     47         std::is_base_of<std::bidirectional_iterator_tag, IteratorCategoryT>::value,
     48   };
     49 
     50   /// A proxy object for computing a reference via indirecting a copy of an
     51   /// iterator. This is used in APIs which need to produce a reference via
     52   /// indirection but for which the iterator object might be a temporary. The
     53   /// proxy preserves the iterator internally and exposes the indirected
     54   /// reference via a conversion operator.
     55   class ReferenceProxy {
     56     friend iterator_facade_base;
     57 
     58     DerivedT I;
     59 
     60     ReferenceProxy(DerivedT I) : I(std::move(I)) {}
     61 
     62   public:
     63     operator ReferenceT() const { return *I; }
     64   };
     65 
     66 public:
     67   DerivedT operator+(DifferenceTypeT n) const {
     68     static_assert(
     69         IsRandomAccess,
     70         "The '+' operator is only defined for random access iterators.");
     71     DerivedT tmp = *static_cast<const DerivedT *>(this);
     72     tmp += n;
     73     return tmp;
     74   }
     75   friend DerivedT operator+(DifferenceTypeT n, const DerivedT &i) {
     76     static_assert(
     77         IsRandomAccess,
     78         "The '+' operator is only defined for random access iterators.");
     79     return i + n;
     80   }
     81   DerivedT operator-(DifferenceTypeT n) const {
     82     static_assert(
     83         IsRandomAccess,
     84         "The '-' operator is only defined for random access iterators.");
     85     DerivedT tmp = *static_cast<const DerivedT *>(this);
     86     tmp -= n;
     87     return tmp;
     88   }
     89 
     90   DerivedT &operator++() {
     91     return static_cast<DerivedT *>(this)->operator+=(1);
     92   }
     93   DerivedT operator++(int) {
     94     DerivedT tmp = *static_cast<DerivedT *>(this);
     95     ++*static_cast<DerivedT *>(this);
     96     return tmp;
     97   }
     98   DerivedT &operator--() {
     99     static_assert(
    100         IsBidirectional,
    101         "The decrement operator is only defined for bidirectional iterators.");
    102     return static_cast<DerivedT *>(this)->operator-=(1);
    103   }
    104   DerivedT operator--(int) {
    105     static_assert(
    106         IsBidirectional,
    107         "The decrement operator is only defined for bidirectional iterators.");
    108     DerivedT tmp = *static_cast<DerivedT *>(this);
    109     --*static_cast<DerivedT *>(this);
    110     return tmp;
    111   }
    112 
    113   bool operator!=(const DerivedT &RHS) const {
    114     return !static_cast<const DerivedT *>(this)->operator==(RHS);
    115   }
    116 
    117   bool operator>(const DerivedT &RHS) const {
    118     static_assert(
    119         IsRandomAccess,
    120         "Relational operators are only defined for random access iterators.");
    121     return !static_cast<const DerivedT *>(this)->operator<(RHS) &&
    122            !static_cast<const DerivedT *>(this)->operator==(RHS);
    123   }
    124   bool operator<=(const DerivedT &RHS) const {
    125     static_assert(
    126         IsRandomAccess,
    127         "Relational operators are only defined for random access iterators.");
    128     return !static_cast<const DerivedT *>(this)->operator>(RHS);
    129   }
    130   bool operator>=(const DerivedT &RHS) const {
    131     static_assert(
    132         IsRandomAccess,
    133         "Relational operators are only defined for random access iterators.");
    134     return !static_cast<const DerivedT *>(this)->operator<(RHS);
    135   }
    136 
    137   PointerT operator->() const {
    138     return &static_cast<const DerivedT *>(this)->operator*();
    139   }
    140   ReferenceProxy operator[](DifferenceTypeT n) const {
    141     static_assert(IsRandomAccess,
    142                   "Subscripting is only defined for random access iterators.");
    143     return ReferenceProxy(static_cast<const DerivedT *>(this)->operator+(n));
    144   }
    145 };
    146 
    147 /// \brief CRTP base class for adapting an iterator to a different type.
    148 ///
    149 /// This class can be used through CRTP to adapt one iterator into another.
    150 /// Typically this is done through providing in the derived class a custom \c
    151 /// operator* implementation. Other methods can be overridden as well.
    152 template <
    153     typename DerivedT, typename WrappedIteratorT,
    154     typename IteratorCategoryT =
    155         typename std::iterator_traits<WrappedIteratorT>::iterator_category,
    156     typename T = typename std::iterator_traits<WrappedIteratorT>::value_type,
    157     typename DifferenceTypeT =
    158         typename std::iterator_traits<WrappedIteratorT>::difference_type,
    159     typename PointerT = typename std::conditional<
    160         std::is_same<T, typename std::iterator_traits<
    161                             WrappedIteratorT>::value_type>::value,
    162         typename std::iterator_traits<WrappedIteratorT>::pointer, T *>::type,
    163     typename ReferenceT = typename std::conditional<
    164         std::is_same<T, typename std::iterator_traits<
    165                             WrappedIteratorT>::value_type>::value,
    166         typename std::iterator_traits<WrappedIteratorT>::reference, T &>::type,
    167     // Don't provide these, they are mostly to act as aliases below.
    168     typename WrappedTraitsT = std::iterator_traits<WrappedIteratorT>>
    169 class iterator_adaptor_base
    170     : public iterator_facade_base<DerivedT, IteratorCategoryT, T,
    171                                   DifferenceTypeT, PointerT, ReferenceT> {
    172   typedef typename iterator_adaptor_base::iterator_facade_base BaseT;
    173 
    174 protected:
    175   WrappedIteratorT I;
    176 
    177   iterator_adaptor_base() = default;
    178 
    179   explicit iterator_adaptor_base(WrappedIteratorT u) : I(std::move(u)) {}
    180 
    181   const WrappedIteratorT &wrapped() const { return I; }
    182 
    183 public:
    184   typedef DifferenceTypeT difference_type;
    185 
    186   DerivedT &operator+=(difference_type n) {
    187     static_assert(
    188         BaseT::IsRandomAccess,
    189         "The '+=' operator is only defined for random access iterators.");
    190     I += n;
    191     return *static_cast<DerivedT *>(this);
    192   }
    193   DerivedT &operator-=(difference_type n) {
    194     static_assert(
    195         BaseT::IsRandomAccess,
    196         "The '-=' operator is only defined for random access iterators.");
    197     I -= n;
    198     return *static_cast<DerivedT *>(this);
    199   }
    200   using BaseT::operator-;
    201   difference_type operator-(const DerivedT &RHS) const {
    202     static_assert(
    203         BaseT::IsRandomAccess,
    204         "The '-' operator is only defined for random access iterators.");
    205     return I - RHS.I;
    206   }
    207 
    208   // We have to explicitly provide ++ and -- rather than letting the facade
    209   // forward to += because WrappedIteratorT might not support +=.
    210   using BaseT::operator++;
    211   DerivedT &operator++() {
    212     ++I;
    213     return *static_cast<DerivedT *>(this);
    214   }
    215   using BaseT::operator--;
    216   DerivedT &operator--() {
    217     static_assert(
    218         BaseT::IsBidirectional,
    219         "The decrement operator is only defined for bidirectional iterators.");
    220     --I;
    221     return *static_cast<DerivedT *>(this);
    222   }
    223 
    224   bool operator==(const DerivedT &RHS) const { return I == RHS.I; }
    225   bool operator<(const DerivedT &RHS) const {
    226     static_assert(
    227         BaseT::IsRandomAccess,
    228         "Relational operators are only defined for random access iterators.");
    229     return I < RHS.I;
    230   }
    231 
    232   ReferenceT operator*() const { return *I; }
    233 };
    234 
    235 /// \brief An iterator type that allows iterating over the pointees via some
    236 /// other iterator.
    237 ///
    238 /// The typical usage of this is to expose a type that iterates over Ts, but
    239 /// which is implemented with some iterator over T*s:
    240 ///
    241 /// \code
    242 ///   typedef pointee_iterator<SmallVectorImpl<T *>::iterator> iterator;
    243 /// \endcode
    244 template <typename WrappedIteratorT,
    245           typename T = typename std::remove_reference<
    246               decltype(**std::declval<WrappedIteratorT>())>::type>
    247 struct pointee_iterator
    248     : iterator_adaptor_base<
    249           pointee_iterator<WrappedIteratorT>, WrappedIteratorT,
    250           typename std::iterator_traits<WrappedIteratorT>::iterator_category,
    251           T> {
    252   pointee_iterator() = default;
    253   template <typename U>
    254   pointee_iterator(U &&u)
    255       : pointee_iterator::iterator_adaptor_base(std::forward<U &&>(u)) {}
    256 
    257   T &operator*() const { return **this->I; }
    258 };
    259 
    260 template <typename WrappedIteratorT,
    261           typename T = decltype(&*std::declval<WrappedIteratorT>())>
    262 class pointer_iterator
    263     : public iterator_adaptor_base<pointer_iterator<WrappedIteratorT>,
    264                                    WrappedIteratorT, T> {
    265   mutable T Ptr;
    266 
    267 public:
    268   pointer_iterator() = default;
    269 
    270   explicit pointer_iterator(WrappedIteratorT u)
    271       : pointer_iterator::iterator_adaptor_base(std::move(u)) {}
    272 
    273   T &operator*() { return Ptr = &*this->I; }
    274   const T &operator*() const { return Ptr = &*this->I; }
    275 };
    276 
    277 } // end namespace llvm
    278 
    279 #endif // LLVM_ADT_ITERATOR_H
    280