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  /* Copy/Move constructor which transfers ownership. This is crucial in
47   * absence of return value optimization to avoid assertions during destruction. */
48  // FIXME in C++11 mode this could be replaced by a proper RValue constructor
49  inline CommaInitializer(const CommaInitializer& o)
50  : m_xpr(o.m_xpr), m_row(o.m_row), m_col(o.m_col), m_currentBlockRows(o.m_currentBlockRows) {
51    // Mark original object as finished. In absence of R-value references we need to const_cast:
52    const_cast<CommaInitializer&>(o).m_row = m_xpr.rows();
53    const_cast<CommaInitializer&>(o).m_col = m_xpr.cols();
54    const_cast<CommaInitializer&>(o).m_currentBlockRows = 0;
55  }
56
57  /* inserts a scalar value in the target matrix */
58  CommaInitializer& operator,(const Scalar& s)
59  {
60    if (m_col==m_xpr.cols())
61    {
62      m_row+=m_currentBlockRows;
63      m_col = 0;
64      m_currentBlockRows = 1;
65      eigen_assert(m_row<m_xpr.rows()
66        && "Too many rows passed to comma initializer (operator<<)");
67    }
68    eigen_assert(m_col<m_xpr.cols()
69      && "Too many coefficients passed to comma initializer (operator<<)");
70    eigen_assert(m_currentBlockRows==1);
71    m_xpr.coeffRef(m_row, m_col++) = s;
72    return *this;
73  }
74
75  /* inserts a matrix expression in the target matrix */
76  template<typename OtherDerived>
77  CommaInitializer& operator,(const DenseBase<OtherDerived>& other)
78  {
79    if(other.cols()==0 || other.rows()==0)
80      return *this;
81    if (m_col==m_xpr.cols())
82    {
83      m_row+=m_currentBlockRows;
84      m_col = 0;
85      m_currentBlockRows = other.rows();
86      eigen_assert(m_row+m_currentBlockRows<=m_xpr.rows()
87        && "Too many rows passed to comma initializer (operator<<)");
88    }
89    eigen_assert(m_col<m_xpr.cols()
90      && "Too many coefficients passed to comma initializer (operator<<)");
91    eigen_assert(m_currentBlockRows==other.rows());
92    if (OtherDerived::SizeAtCompileTime != Dynamic)
93      m_xpr.template block<OtherDerived::RowsAtCompileTime != Dynamic ? OtherDerived::RowsAtCompileTime : 1,
94                              OtherDerived::ColsAtCompileTime != Dynamic ? OtherDerived::ColsAtCompileTime : 1>
95                    (m_row, m_col) = other;
96    else
97      m_xpr.block(m_row, m_col, other.rows(), other.cols()) = other;
98    m_col += other.cols();
99    return *this;
100  }
101
102  inline ~CommaInitializer()
103  {
104    eigen_assert((m_row+m_currentBlockRows) == m_xpr.rows()
105         && m_col == m_xpr.cols()
106         && "Too few coefficients passed to comma initializer (operator<<)");
107  }
108
109  /** \returns the built matrix once all its coefficients have been set.
110    * Calling finished is 100% optional. Its purpose is to write expressions
111    * like this:
112    * \code
113    * quaternion.fromRotationMatrix((Matrix3f() << axis0, axis1, axis2).finished());
114    * \endcode
115    */
116  inline XprType& finished() { return m_xpr; }
117
118  XprType& m_xpr;   // target expression
119  Index m_row;              // current row id
120  Index m_col;              // current col id
121  Index m_currentBlockRows; // current block height
122};
123
124/** \anchor MatrixBaseCommaInitRef
125  * Convenient operator to set the coefficients of a matrix.
126  *
127  * The coefficients must be provided in a row major order and exactly match
128  * the size of the matrix. Otherwise an assertion is raised.
129  *
130  * Example: \include MatrixBase_set.cpp
131  * Output: \verbinclude MatrixBase_set.out
132  *
133  * \note According the c++ standard, the argument expressions of this comma initializer are evaluated in arbitrary order.
134  *
135  * \sa CommaInitializer::finished(), class CommaInitializer
136  */
137template<typename Derived>
138inline CommaInitializer<Derived> DenseBase<Derived>::operator<< (const Scalar& s)
139{
140  return CommaInitializer<Derived>(*static_cast<Derived*>(this), s);
141}
142
143/** \sa operator<<(const Scalar&) */
144template<typename Derived>
145template<typename OtherDerived>
146inline CommaInitializer<Derived>
147DenseBase<Derived>::operator<<(const DenseBase<OtherDerived>& other)
148{
149  return CommaInitializer<Derived>(*static_cast<Derived *>(this), other);
150}
151
152} // end namespace Eigen
153
154#endif // EIGEN_COMMAINITIALIZER_H
155