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