//===- 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