1 | // This file is part of Eigen, a lightweight C++ template library |
2 | // for linear algebra. |
3 | // |
4 | // Copyright (C) 2006-2008 Benoit Jacob <jacob.benoit.1@gmail.com> |
5 | // Copyright (C) 2008 Gael Guennebaud <gael.guennebaud@inria.fr> |
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_IO_H |
12 | #define EIGEN_IO_H |
13 | |
14 | namespace Eigen { |
15 | |
16 | enum { DontAlignCols = 1 }; |
17 | enum { StreamPrecision = -1, |
18 | FullPrecision = -2 }; |
19 | |
20 | namespace internal { |
21 | template<typename Derived> |
22 | std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt); |
23 | } |
24 | |
25 | /** \class IOFormat |
26 | * \ingroup Core_Module |
27 | * |
28 | * \brief Stores a set of parameters controlling the way matrices are printed |
29 | * |
30 | * List of available parameters: |
31 | * - \b precision number of digits for floating point values, or one of the special constants \c StreamPrecision and \c FullPrecision. |
32 | * The default is the special value \c StreamPrecision which means to use the |
33 | * stream's own precision setting, as set for instance using \c cout.precision(3). The other special value |
34 | * \c FullPrecision means that the number of digits will be computed to match the full precision of each floating-point |
35 | * type. |
36 | * - \b flags an OR-ed combination of flags, the default value is 0, the only currently available flag is \c DontAlignCols which |
37 | * allows to disable the alignment of columns, resulting in faster code. |
38 | * - \b coeffSeparator string printed between two coefficients of the same row |
39 | * - \b rowSeparator string printed between two rows |
40 | * - \b rowPrefix string printed at the beginning of each row |
41 | * - \b rowSuffix string printed at the end of each row |
42 | * - \b matPrefix string printed at the beginning of the matrix |
43 | * - \b matSuffix string printed at the end of the matrix |
44 | * |
45 | * Example: \include IOFormat.cpp |
46 | * Output: \verbinclude IOFormat.out |
47 | * |
48 | * \sa DenseBase::format(), class WithFormat |
49 | */ |
50 | struct IOFormat |
51 | { |
52 | /** Default constructor, see class IOFormat for the meaning of the parameters */ |
53 | IOFormat(int _precision = StreamPrecision, int _flags = 0, |
54 | const std::string& _coeffSeparator = " " , |
55 | const std::string& _rowSeparator = "\n" , const std::string& _rowPrefix="" , const std::string& _rowSuffix="" , |
56 | const std::string& _matPrefix="" , const std::string& _matSuffix="" ) |
57 | : matPrefix(_matPrefix), matSuffix(_matSuffix), rowPrefix(_rowPrefix), rowSuffix(_rowSuffix), rowSeparator(_rowSeparator), |
58 | rowSpacer("" ), coeffSeparator(_coeffSeparator), precision(_precision), flags(_flags) |
59 | { |
60 | // TODO check if rowPrefix, rowSuffix or rowSeparator contains a newline |
61 | // don't add rowSpacer if columns are not to be aligned |
62 | if((flags & DontAlignCols)) |
63 | return; |
64 | int i = int(matSuffix.length())-1; |
65 | while (i>=0 && matSuffix[i]!='\n') |
66 | { |
67 | rowSpacer += ' '; |
68 | i--; |
69 | } |
70 | } |
71 | std::string matPrefix, matSuffix; |
72 | std::string rowPrefix, rowSuffix, rowSeparator, rowSpacer; |
73 | std::string coeffSeparator; |
74 | int precision; |
75 | int flags; |
76 | }; |
77 | |
78 | /** \class WithFormat |
79 | * \ingroup Core_Module |
80 | * |
81 | * \brief Pseudo expression providing matrix output with given format |
82 | * |
83 | * \tparam ExpressionType the type of the object on which IO stream operations are performed |
84 | * |
85 | * This class represents an expression with stream operators controlled by a given IOFormat. |
86 | * It is the return type of DenseBase::format() |
87 | * and most of the time this is the only way it is used. |
88 | * |
89 | * See class IOFormat for some examples. |
90 | * |
91 | * \sa DenseBase::format(), class IOFormat |
92 | */ |
93 | template<typename ExpressionType> |
94 | class WithFormat |
95 | { |
96 | public: |
97 | |
98 | WithFormat(const ExpressionType& matrix, const IOFormat& format) |
99 | : m_matrix(matrix), m_format(format) |
100 | {} |
101 | |
102 | friend std::ostream & operator << (std::ostream & s, const WithFormat& wf) |
103 | { |
104 | return internal::print_matrix(s, wf.m_matrix.eval(), wf.m_format); |
105 | } |
106 | |
107 | protected: |
108 | typename ExpressionType::Nested m_matrix; |
109 | IOFormat m_format; |
110 | }; |
111 | |
112 | namespace internal { |
113 | |
114 | // NOTE: This helper is kept for backward compatibility with previous code specializing |
115 | // this internal::significant_decimals_impl structure. In the future we should directly |
116 | // call digits10() which has been introduced in July 2016 in 3.3. |
117 | template<typename Scalar> |
118 | struct significant_decimals_impl |
119 | { |
120 | static inline int run() |
121 | { |
122 | return NumTraits<Scalar>::digits10(); |
123 | } |
124 | }; |
125 | |
126 | /** \internal |
127 | * print the matrix \a _m to the output stream \a s using the output format \a fmt */ |
128 | template<typename Derived> |
129 | std::ostream & print_matrix(std::ostream & s, const Derived& _m, const IOFormat& fmt) |
130 | { |
131 | if(_m.size() == 0) |
132 | { |
133 | s << fmt.matPrefix << fmt.matSuffix; |
134 | return s; |
135 | } |
136 | |
137 | typename Derived::Nested m = _m; |
138 | typedef typename Derived::Scalar Scalar; |
139 | |
140 | Index width = 0; |
141 | |
142 | std::streamsize explicit_precision; |
143 | if(fmt.precision == StreamPrecision) |
144 | { |
145 | explicit_precision = 0; |
146 | } |
147 | else if(fmt.precision == FullPrecision) |
148 | { |
149 | if (NumTraits<Scalar>::IsInteger) |
150 | { |
151 | explicit_precision = 0; |
152 | } |
153 | else |
154 | { |
155 | explicit_precision = significant_decimals_impl<Scalar>::run(); |
156 | } |
157 | } |
158 | else |
159 | { |
160 | explicit_precision = fmt.precision; |
161 | } |
162 | |
163 | std::streamsize old_precision = 0; |
164 | if(explicit_precision) old_precision = s.precision(explicit_precision); |
165 | |
166 | bool align_cols = !(fmt.flags & DontAlignCols); |
167 | if(align_cols) |
168 | { |
169 | // compute the largest width |
170 | for(Index j = 0; j < m.cols(); ++j) |
171 | for(Index i = 0; i < m.rows(); ++i) |
172 | { |
173 | std::stringstream sstr; |
174 | sstr.copyfmt(s); |
175 | sstr << m.coeff(i,j); |
176 | width = std::max<Index>(width, Index(sstr.str().length())); |
177 | } |
178 | } |
179 | s << fmt.matPrefix; |
180 | for(Index i = 0; i < m.rows(); ++i) |
181 | { |
182 | if (i) |
183 | s << fmt.rowSpacer; |
184 | s << fmt.rowPrefix; |
185 | if(width) s.width(width); |
186 | s << m.coeff(i, 0); |
187 | for(Index j = 1; j < m.cols(); ++j) |
188 | { |
189 | s << fmt.coeffSeparator; |
190 | if (width) s.width(width); |
191 | s << m.coeff(i, j); |
192 | } |
193 | s << fmt.rowSuffix; |
194 | if( i < m.rows() - 1) |
195 | s << fmt.rowSeparator; |
196 | } |
197 | s << fmt.matSuffix; |
198 | if(explicit_precision) s.precision(old_precision); |
199 | return s; |
200 | } |
201 | |
202 | } // end namespace internal |
203 | |
204 | /** \relates DenseBase |
205 | * |
206 | * Outputs the matrix, to the given stream. |
207 | * |
208 | * If you wish to print the matrix with a format different than the default, use DenseBase::format(). |
209 | * |
210 | * It is also possible to change the default format by defining EIGEN_DEFAULT_IO_FORMAT before including Eigen headers. |
211 | * If not defined, this will automatically be defined to Eigen::IOFormat(), that is the Eigen::IOFormat with default parameters. |
212 | * |
213 | * \sa DenseBase::format() |
214 | */ |
215 | template<typename Derived> |
216 | std::ostream & operator << |
217 | (std::ostream & s, |
218 | const DenseBase<Derived> & m) |
219 | { |
220 | return internal::print_matrix(s, m.eval(), EIGEN_DEFAULT_IO_FORMAT); |
221 | } |
222 | |
223 | } // end namespace Eigen |
224 | |
225 | #endif // EIGEN_IO_H |
226 | |