1// This file is part of Eigen, a lightweight C++ template library
2// for linear algebra.
3//
4// Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr>
5// Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com>
6//
7// This Source Code Form is subject to the terms of the Mozilla
8// Public License v. 2.0. If a copy of the MPL was not distributed
9// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
10
11#ifndef EIGEN_COMMAINITIALIZER_H
12#define EIGEN_COMMAINITIALIZER_H
13
14namespace Eigen {
15
16/** \class CommaInitializer
17  * \ingroup Core_Module
18  *
19  * \brief Helper class used by the comma initializer operator
20  *
21  * This class is internally used to implement the comma initializer feature. It is
22  * the return type of MatrixBase::operator<<, and most of the time this is the only
23  * way it is used.
24  *
25  * \sa \ref MatrixBaseCommaInitRef "MatrixBase::operator<<", CommaInitializer::finished()
26  */
27template<typename XprType>
28struct CommaInitializer
29{
30  typedef typename XprType::Scalar Scalar;
31  typedef typename XprType::Index Index;
32
33  inline CommaInitializer(XprType& xpr, const Scalar& s)
34    : m_xpr(xpr), m_row(0), m_col(1), m_currentBlockRows(1)
35  {
36    m_xpr.coeffRef(0,0) = s;
37  }
38
39  template<typename OtherDerived>
40  inline CommaInitializer(XprType& xpr, const DenseBase<OtherDerived>& other)
41    : m_xpr(xpr), m_row(0), m_col(other.cols()), m_currentBlockRows(other.rows())
42  {
43    m_xpr.block(0, 0, other.rows(), other.cols()) = other;
44  }
45
46  /* inserts a scalar value in the target matrix */
47  CommaInitializer& operator,(const Scalar& s)
48  {
49    if (m_col==m_xpr.cols())
50    {
51      m_row+=m_currentBlockRows;
52      m_col = 0;
53      m_currentBlockRows = 1;
54      eigen_assert(m_row<m_xpr.rows()
55        && "Too many rows passed to comma initializer (operator<<)");
56    }
57    eigen_assert(m_col<m_xpr.cols()
58      && "Too many coefficients passed to comma initializer (operator<<)");
59    eigen_assert(m_currentBlockRows==1);
60    m_xpr.coeffRef(m_row, m_col++) = s;
61    return *this;
62  }
63
64  /* inserts a matrix expression in the target matrix */
65  template<typename OtherDerived>
66  CommaInitializer& operator,(const DenseBase<OtherDerived>& other)
67  {
68    if (m_col==m_xpr.cols())
69    {
70      m_row+=m_currentBlockRows;
71      m_col = 0;
72      m_currentBlockRows = other.rows();
73      eigen_assert(m_row+m_currentBlockRows<=m_xpr.rows()
74        && "Too many rows passed to comma initializer (operator<<)");
75    }
76    eigen_assert(m_col<m_xpr.cols()
77      && "Too many coefficients passed to comma initializer (operator<<)");
78    eigen_assert(m_currentBlockRows==other.rows());
79    if (OtherDerived::SizeAtCompileTime != Dynamic)
80      m_xpr.template block<OtherDerived::RowsAtCompileTime != Dynamic ? OtherDerived::RowsAtCompileTime : 1,
81                              OtherDerived::ColsAtCompileTime != Dynamic ? OtherDerived::ColsAtCompileTime : 1>
82                    (m_row, m_col) = other;
83    else
84      m_xpr.block(m_row, m_col, other.rows(), other.cols()) = other;
85    m_col += other.cols();
86    return *this;
87  }
88
89  inline ~CommaInitializer()
90  {
91    eigen_assert((m_row+m_currentBlockRows) == m_xpr.rows()
92         && m_col == m_xpr.cols()
93         && "Too few coefficients passed to comma initializer (operator<<)");
94  }
95
96  /** \returns the built matrix once all its coefficients have been set.
97    * Calling finished is 100% optional. Its purpose is to write expressions
98    * like this:
99    * \code
100    * quaternion.fromRotationMatrix((Matrix3f() << axis0, axis1, axis2).finished());
101    * \endcode
102    */
103  inline XprType& finished() { return m_xpr; }
104
105  XprType& m_xpr;   // target expression
106  Index m_row;              // current row id
107  Index m_col;              // current col id
108  Index m_currentBlockRows; // current block height
109};
110
111/** \anchor MatrixBaseCommaInitRef
112  * Convenient operator to set the coefficients of a matrix.
113  *
114  * The coefficients must be provided in a row major order and exactly match
115  * the size of the matrix. Otherwise an assertion is raised.
116  *
117  * Example: \include MatrixBase_set.cpp
118  * Output: \verbinclude MatrixBase_set.out
119  *
120  * \sa CommaInitializer::finished(), class CommaInitializer
121  */
122template<typename Derived>
123inline CommaInitializer<Derived> DenseBase<Derived>::operator<< (const Scalar& s)
124{
125  return CommaInitializer<Derived>(*static_cast<Derived*>(this), s);
126}
127
128/** \sa operator<<(const Scalar&) */
129template<typename Derived>
130template<typename OtherDerived>
131inline CommaInitializer<Derived>
132DenseBase<Derived>::operator<<(const DenseBase<OtherDerived>& other)
133{
134  return CommaInitializer<Derived>(*static_cast<Derived *>(this), other);
135}
136
137} // end namespace Eigen
138
139#endif // EIGEN_COMMAINITIALIZER_H
140