// This file is part of Eigen, a lightweight C++ template library
// for linear algebra.
//
// Copyright (C) 2008-2014 Gael Guennebaud <gael.guennebaud@inria.fr>
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#ifndef EIGEN_COREITERATORS_H
#define EIGEN_COREITERATORS_H

// IWYU pragma: private
#include "./InternalHeaderCheck.h"

namespace Eigen {

/* This file contains the respective InnerIterator definition of the expressions defined in Eigen/Core
 */

namespace internal {

template <typename XprType, typename EvaluatorKind>
class inner_iterator_selector;

}

/** \class InnerIterator
 * \brief An InnerIterator allows to loop over the element of any matrix expression.
 *
 * \warning To be used with care because an evaluator is constructed every time an InnerIterator iterator is
 * constructed.
 *
 * TODO: add a usage example
 */
template <typename XprType>
class InnerIterator {
 protected:
  typedef internal::inner_iterator_selector<XprType, typename internal::evaluator_traits<XprType>::Kind> IteratorType;
  typedef internal::evaluator<XprType> EvaluatorType;
  typedef typename internal::traits<XprType>::Scalar Scalar;

 public:
  /** Construct an iterator over the \a outerId -th row or column of \a xpr */
  InnerIterator(const XprType &xpr, const Index &outerId) : m_eval(xpr), m_iter(m_eval, outerId, xpr.innerSize()) {}

  /// \returns the value of the current coefficient.
  EIGEN_STRONG_INLINE Scalar value() const { return m_iter.value(); }
  /** Increment the iterator \c *this to the next non-zero coefficient.
   * Explicit zeros are not skipped over. To skip explicit zeros, see class SparseView
   */
  EIGEN_STRONG_INLINE InnerIterator &operator++() {
    m_iter.operator++();
    return *this;
  }
  EIGEN_STRONG_INLINE InnerIterator &operator+=(Index i) {
    m_iter.operator+=(i);
    return *this;
  }
  EIGEN_STRONG_INLINE InnerIterator operator+(Index i) {
    InnerIterator result(*this);
    result += i;
    return result;
  }

  /// \returns the column or row index of the current coefficient.
  EIGEN_STRONG_INLINE Index index() const { return m_iter.index(); }
  /// \returns the row index of the current coefficient.
  EIGEN_STRONG_INLINE Index row() const { return m_iter.row(); }
  /// \returns the column index of the current coefficient.
  EIGEN_STRONG_INLINE Index col() const { return m_iter.col(); }
  /// \returns \c true if the iterator \c *this still references a valid coefficient.
  EIGEN_STRONG_INLINE operator bool() const { return m_iter; }

 protected:
  EvaluatorType m_eval;
  IteratorType m_iter;

 private:
  // If you get here, then you're not using the right InnerIterator type, e.g.:
  //   SparseMatrix<double,RowMajor> A;
  //   SparseMatrix<double>::InnerIterator it(A,0);
  template <typename T>
  InnerIterator(const EigenBase<T> &, Index outer);
};

namespace internal {

// Generic inner iterator implementation for dense objects
template <typename XprType>
class inner_iterator_selector<XprType, IndexBased> {
 protected:
  typedef evaluator<XprType> EvaluatorType;
  typedef typename traits<XprType>::Scalar Scalar;
  enum { IsRowMajor = (XprType::Flags & RowMajorBit) == RowMajorBit };

 public:
  EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId, const Index &innerSize)
      : m_eval(eval), m_inner(0), m_outer(outerId), m_end(innerSize) {}

  EIGEN_STRONG_INLINE Scalar value() const {
    return (IsRowMajor) ? m_eval.coeff(m_outer, m_inner) : m_eval.coeff(m_inner, m_outer);
  }

  EIGEN_STRONG_INLINE inner_iterator_selector &operator++() {
    m_inner++;
    return *this;
  }

  EIGEN_STRONG_INLINE Index index() const { return m_inner; }
  inline Index row() const { return IsRowMajor ? m_outer : index(); }
  inline Index col() const { return IsRowMajor ? index() : m_outer; }

  EIGEN_STRONG_INLINE operator bool() const { return m_inner < m_end && m_inner >= 0; }

 protected:
  const EvaluatorType &m_eval;
  Index m_inner;
  const Index m_outer;
  const Index m_end;
};

// For iterator-based evaluator, inner-iterator is already implemented as
// evaluator<>::InnerIterator
template <typename XprType>
class inner_iterator_selector<XprType, IteratorBased> : public evaluator<XprType>::InnerIterator {
 protected:
  typedef typename evaluator<XprType>::InnerIterator Base;
  typedef evaluator<XprType> EvaluatorType;

 public:
  EIGEN_STRONG_INLINE inner_iterator_selector(const EvaluatorType &eval, const Index &outerId,
                                              const Index & /*innerSize*/)
      : Base(eval, outerId) {}
};

}  // end namespace internal

}  // end namespace Eigen

#endif  // EIGEN_COREITERATORS_H
