1 /*
2 Scan Tailor - Interactive post-processing tool for scanned pages.
3 Copyright (C) Joseph Artsimovich <joseph.artsimovich@gmail.com>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #ifndef MAT_T_H_
20 #define MAT_T_H_
21
22 #include <boost/scoped_array.hpp>
23 #include <cassert>
24 #include <cstddef>
25
26 /**
27 * \brief A matrix of elements of type T.
28 *
29 * \note The memory layout is always column-major, as that's what MatrixCalc uses.
30 */
31 template <typename T>
32 class MatT {
33 public:
34 typedef T type;
35
36 /**
37 * \brief Constructs an empty 0x0 matrix.
38 */
39 MatT();
40
41 /**
42 * \brief Constructs a (rows)x(cols) matrix, initializing all elements to T().
43 */
44 MatT(size_t rows, size_t cols);
45
46 /**
47 * \brief Constructs a (rows)x(cols) matrix, initializing all elements to the provided value.
48 */
49 MatT(size_t rows, size_t cols, T initial_value);
50
51 /**
52 * \brief Construction from an array of elements of possibly different type.
53 *
54 * Conversion is done by static casts. Data elements must be in column-major order.
55 */
56 template <typename OT>
57 explicit MatT(size_t rows, size_t cols, const OT* data);
58
59 /**
60 * Ordinary copy-construction.
61 */
62 MatT(const MatT& other);
63
64 /**
65 * \brief Construction from a matrix of a different type.
66 *
67 * Conversion is done by static casts.
68 */
69 template <typename OT>
70 explicit MatT(const MatT<OT>& other);
71
72 /**
73 * \brief Ordinary assignment.
74 */
75 MatT& operator=(const MatT& other);
76
77 /**
78 * \brief Assignment from a matrix of a different type.
79 *
80 * Conversion is done by static casts.
81 */
82 template <typename OT>
83 MatT& operator=(const MatT<OT>& other);
84
85 MatT& operator+=(const MatT& rhs);
86
87 MatT& operator-=(const MatT& rhs);
88
89 MatT& operator*=(T scalar);
90
rows()91 size_t rows() const { return m_rows; }
92
cols()93 size_t cols() const { return m_cols; }
94
data()95 const T* data() const { return m_data.get(); }
96
data()97 T* data() { return m_data.get(); }
98
operator()99 const T& operator()(size_t row, size_t col) const {
100 assert(row < m_rows && col < m_cols);
101
102 return m_data[row + col * m_rows];
103 }
104
operator()105 T& operator()(size_t row, size_t col) {
106 assert(row < m_rows && col < m_cols);
107
108 return m_data[row + col * m_rows];
109 }
110
111 void fill(const T& value);
112
113 void swap(MatT& other);
114
115 private:
116 size_t m_rows;
117 size_t m_cols;
118 boost::scoped_array<T> m_data;
119 };
120
121
122 template <typename T>
MatT()123 MatT<T>::MatT() : m_rows(0), m_cols(0) {}
124
125 template <typename T>
MatT(size_t rows,size_t cols)126 MatT<T>::MatT(size_t rows, size_t cols)
127 : m_rows(rows),
128 m_cols(cols),
129 m_data(new T[rows * cols]()) { // The "()" will cause elements to be initialized to T().
130 }
131
132 template <typename T>
MatT(size_t rows,size_t cols,T initial_value)133 MatT<T>::MatT(size_t rows, size_t cols, T initial_value) : m_rows(rows), m_cols(cols), m_data(new T[rows * cols]) {
134 const size_t len = rows * cols;
135 for (size_t i = 0; i < len; ++i) {
136 m_data[i] = initial_value;
137 }
138 }
139
140 template <typename T>
141 template <typename OT>
MatT(size_t rows,size_t cols,const OT * data)142 MatT<T>::MatT(size_t rows, size_t cols, const OT* data) : m_rows(rows), m_cols(cols), m_data(new T[rows * cols]) {
143 const size_t len = rows * cols;
144 for (size_t i = 0; i < len; ++i) {
145 m_data[i] = static_cast<T>(data[i]);
146 }
147 }
148
149 template <typename T>
MatT(const MatT & other)150 MatT<T>::MatT(const MatT& other) : m_rows(other.rows()), m_cols(other.cols()), m_data(new T[m_rows * m_cols]) {
151 const size_t len = m_rows * m_cols;
152 const T* other_data = other.data();
153 for (size_t i = 0; i < len; ++i) {
154 m_data[i] = other_data[i];
155 }
156 }
157
158 template <typename T>
159 template <typename OT>
MatT(const MatT<OT> & other)160 MatT<T>::MatT(const MatT<OT>& other) : m_rows(other.rows()), m_cols(other.cols()), m_data(new T[m_rows * m_cols]) {
161 const size_t len = m_rows * m_cols;
162 const T* other_data = other.data();
163 for (size_t i = 0; i < len; ++i) {
164 m_data[i] = other_data[i];
165 }
166 }
167
168 template <typename T>
169 MatT<T>& MatT<T>::operator=(const MatT& other) {
170 MatT(other).swap(*this);
171
172 return *this;
173 }
174
175 template <typename T>
176 template <typename OT>
177 MatT<T>& MatT<T>::operator=(const MatT<OT>& other) {
178 MatT(other).swap(*this);
179
180 return *this;
181 }
182
183 template <typename T>
184 MatT<T>& MatT<T>::operator+=(const MatT& rhs) {
185 assert(m_rows == rhs.m_rows && m_cols == rhs.m_cols);
186
187 const size_t len = m_rows * m_cols;
188 for (size_t i = 0; i < len; ++i) {
189 m_data[i] += rhs.m_data[i];
190 }
191
192 return *this;
193 }
194
195 template <typename T>
196 MatT<T>& MatT<T>::operator-=(const MatT& rhs) {
197 assert(m_rows == rhs.m_rows && m_cols == rhs.m_cols);
198
199 const size_t len = m_rows * m_cols;
200 for (size_t i = 0; i < len; ++i) {
201 m_data[i] -= rhs.m_data[i];
202 }
203
204 return *this;
205 }
206
207 template <typename T>
208 MatT<T>& MatT<T>::operator*=(const T scalar) {
209 const size_t len = m_rows * m_cols;
210 for (size_t i = 0; i < len; ++i) {
211 m_data[i] *= scalar;
212 }
213
214 return *this;
215 }
216
217 template <typename T>
fill(const T & value)218 void MatT<T>::fill(const T& value) {
219 const size_t len = m_rows * m_cols;
220 for (size_t i = 0; i < len; ++i) {
221 m_data[i] = value;
222 }
223 }
224
225 template <typename T>
swap(MatT & other)226 void MatT<T>::swap(MatT& other) {
227 size_t tmp = m_rows;
228 m_rows = other.m_rows;
229 other.m_rows = tmp;
230
231 tmp = m_cols;
232 m_cols = other.m_cols;
233 other.m_cols = tmp;
234
235 m_data.swap(other.m_data);
236 }
237
238 template <typename T>
swap(const MatT<T> & o1,const MatT<T> & o2)239 void swap(const MatT<T>& o1, const MatT<T>& o2) {
240 o1.swap(o2);
241 }
242
243 template <typename T>
244 MatT<T> operator*(const MatT<T>& mat, double scalar) {
245 MatT<T> res(mat);
246 res *= scalar;
247
248 return res;
249 }
250
251 template <typename T>
252 MatT<T> operator*(double scalar, const MatT<T>& mat) {
253 MatT<T> res(mat);
254 res *= scalar;
255
256 return res;
257 }
258
259 #endif // ifndef MAT_T_H_
260