Mathter
A configurable 3D math library for game developers.
MatrixImpl.hpp
Go to the documentation of this file.
1 //==============================================================================
2 // This software is distributed under The Unlicense.
3 // For more information, please refer to <http://unlicense.org/>
4 //==============================================================================
5 
6 #pragma once
7 
8 
9 #include "../Common/Definitions.hpp"
10 #include "../Common/Traits.hpp"
11 #include "../Vector.hpp"
12 
13 #include <array>
14 
15 
16 namespace mathter {
17 
18 
19 //------------------------------------------------------------------------------
20 // Matrix base class only allocating the memory
21 //------------------------------------------------------------------------------
22 
23 template <class T, int Rows, int Columns, eMatrixOrder Order = eMatrixOrder::FOLLOW_VECTOR, eMatrixLayout Layout = eMatrixLayout::ROW_MAJOR, bool Packed = false>
24 class MatrixData {
25 public:
27  constexpr int ColumnCount() const {
28  return Columns;
29  }
31  constexpr int RowCount() const {
32  return Rows;
33  }
35  constexpr int Width() const {
36  return Columns;
37  }
39  constexpr int Height() const {
40  return Rows;
41  }
42  // Rows equal height, Columns equal width, row-major has column-sized stripes
43  static constexpr int StripeDim = Layout == eMatrixLayout::ROW_MAJOR ? Columns : Rows;
44  static constexpr int StripeCount = Layout == eMatrixLayout::ROW_MAJOR ? Rows : Columns;
45 
46  std::array<Vector<T, StripeDim, Packed>, StripeCount> stripes;
47 
48 protected:
49  // Get element
50  inline T& GetElement(int row, int col) {
51  assert(row < RowCount());
52  assert(col < ColumnCount());
53  return GetElementImpl(col, row, std::integral_constant<bool, Layout == eMatrixLayout::ROW_MAJOR>());
54  }
55  inline T GetElement(int row, int col) const {
56  assert(row < RowCount());
57  assert(col < ColumnCount());
58  return GetElementImpl(col, row, std::integral_constant<bool, Layout == eMatrixLayout::ROW_MAJOR>());
59  }
60 
61 private:
62  inline T& GetElementImpl(int col, int row, std::true_type) {
63  return stripes[row][col];
64  }
65  inline T GetElementImpl(int col, int row, std::true_type) const {
66  return stripes[row][col];
67  }
68  inline T& GetElementImpl(int col, int row, std::false_type) {
69  return stripes[col][row];
70  }
71  inline T GetElementImpl(int col, int row, std::false_type) const {
72  return stripes[col][row];
73  }
74 };
75 
76 
77 //------------------------------------------------------------------------------
78 // Submatrix helper
79 //------------------------------------------------------------------------------
80 
81 template <class MatrixT, int SRows, int SColumns>
82 class SubmatrixHelper {
83  friend MatrixT;
84  using Props = traits::MatrixTraits<MatrixT>;
85  template <class, int, int>
86  friend class SubmatrixHelper;
87  static constexpr int VecDim = std::max(SRows, SColumns);
88  static constexpr bool VectorAssignable = std::min(SRows, SColumns) == 1;
89 
90 protected:
91  SubmatrixHelper(MatrixT& mat, int row, int col) : mat(mat), row(row), col(col) {}
92 
93 public:
94  SubmatrixHelper(const SubmatrixHelper& rhs) = delete;
95  SubmatrixHelper(SubmatrixHelper&& rhs) : mat(rhs.mat), row(rhs.row), col(rhs.col) {}
96 
97 
98  template <class U, eMatrixOrder UOrder, eMatrixLayout ULayout, bool UPacked>
101  for (int i = 0; i < SRows; ++i) {
102  for (int j = 0; j < SColumns; ++j) {
103  ret(i, j) = (*this)(i, j);
104  }
105  }
106  return ret;
107  }
108 
109  template <class U, bool Packed2, class = typename std::enable_if<VectorAssignable, U>::type>
110  operator Vector<U, VecDim, Packed2>() const {
112  int k = 0;
113  for (int i = 0; i < SRows; ++i) {
114  for (int j = 0; j < SColumns; ++j) {
115  v(k) = (*this)(i, j);
116  ++k;
117  }
118  }
119  return v;
120  }
121 
122 
123  template <class U, eMatrixOrder UOrder, eMatrixLayout ULayout, bool UPacked>
125  static_assert(!std::is_const<MatrixT>::value, "Cannot assign to submatrix of const matrix.");
126 
127  // If aliasing happens, the same matrix is copied to itself with no side-effects.
128  for (int i = 0; i < SRows; ++i) {
129  for (int j = 0; j < SColumns; ++j) {
130  mat(row + i, col + j) = rhs(i, j);
131  }
132  }
133  return *this;
134  }
135 
136 
137  // From vector if applicable (for 1*N and N*1 submatrices)
138  template <class U, bool Packed, class = typename std::enable_if<VectorAssignable, U>::type>
140  static_assert(!std::is_const<MatrixT>::value, "Cannot assign to submatrix of const matrix.");
141 
142  int k = 0;
143  for (int i = 0; i < SRows; ++i) {
144  for (int j = 0; j < SColumns; ++j) {
145  mat(row + i, col + j) = v(k);
146  ++k;
147  }
148  }
149  return *this;
150  }
151 
152 
153  template <class MatrixU>
155  static_assert(!std::is_const<MatrixT>::value, "Cannot assign to submatrix of const matrix.");
156 
157  // If *this and rhs reference the same matrix, aliasing must be resolved.
158  if ((void*)&mat == (void*)&rhs.mat) {
160  SRows,
161  SColumns,
165  tmpmat;
166  tmpmat = rhs;
167  operator=(tmpmat);
168  }
169  else {
170  for (int i = 0; i < SRows; ++i) {
171  for (int j = 0; j < SColumns; ++j) {
172  mat(row + i, col + j) = rhs(i, j);
173  }
174  }
175  }
176  return *this;
177  }
179  static_assert(!std::is_const<MatrixT>::value, "Cannot assign to submatrix of const matrix.");
180  return operator=<MatrixT>(rhs);
181  }
182 
183  typename Props::Type& operator()(int row, int col) {
184  return mat(this->row + row, this->col + col);
185  }
186 
187  typename Props::Type operator()(int row, int col) const {
188  return mat(this->row + row, this->col + col);
189  }
190 
191 private:
192  MatrixT& mat;
193  int row = -1, col = -1;
194 };
195 
196 
197 //------------------------------------------------------------------------------
198 // Matrix class providing the common interface for all matrices
199 //------------------------------------------------------------------------------
200 
201 template <class T, int Rows, int Columns, eMatrixOrder Order = eMatrixOrder::FOLLOW_VECTOR, eMatrixLayout Layout = eMatrixLayout::ROW_MAJOR, bool Packed = false>
202 class MATHTER_EBCO Matrix : public MatrixData<T, Rows, Columns, Order, Layout, Packed> {
203  static_assert(Columns >= 1 && Rows >= 1, "Dimensions must be positive integers.");
204 
205  static constexpr int VecDim = std::max(Rows, Columns);
206  static constexpr bool VectorAssignable = std::min(Rows, Columns) == 1;
207 
208 protected:
210 
211  template <class T2, int Rows2, int Columns2, eMatrixOrder Order2, eMatrixLayout Layout2, bool Packed2>
212  friend class Matrix;
213 
214 public:
219 
220  //--------------------------------------------
221  // Constructors
222  //--------------------------------------------
223 
224  Matrix() = default;
225 
226  // From same multiplication order
227  template <class T2, eMatrixLayout Layout2, bool Packed2>
229  for (int i = 0; i < RowCount(); ++i) {
230  for (int j = 0; j < ColumnCount(); ++j) {
231  (*this)(i, j) = rhs(i, j);
232  }
233  }
234  }
235 
236  // From opposite multiplication order
237  template <class T2, eMatrixLayout Layout2, bool Packed2>
239  for (int i = 0; i < RowCount(); ++i) {
240  for (int j = 0; j < ColumnCount(); ++j) {
241  (*this)(i, j) = rhs(j, i); // Transpose argument
242  }
243  }
244  }
245 
246  template <class H, class... Args,
247  typename std::enable_if<traits::All<traits::IsScalar, H, Args...>::value, int>::type = 0,
248  typename std::enable_if<1 + sizeof...(Args) == Rows * Columns, int>::type = 0>
249  Matrix(H h, Args... args) {
250  Assign<0, 0>(h, args...);
251  }
252 
253  // From vector if applicable (for 1*N and N*1 matrices)
254  template <class T2, bool Packed2, class = typename std::enable_if<VectorAssignable, T2>::type>
256  for (int i = 0; i < v.Dimension(); ++i) {
257  (*this)(i) = v(i);
258  }
259  }
260 
261 
262  //--------------------------------------------
263  // Accessors
264  //--------------------------------------------
265 
266  // General matrix indexing
267  inline T& operator()(int row, int col) {
268  return GetElement(row, col);
269  }
270  inline T operator()(int row, int col) const {
271  return GetElement(row, col);
272  }
273 
274  // Column and row vector simple indexing
275  template <class Q = T>
276  inline typename std::enable_if<(Columns == 1 && Rows > 1) || (Columns > 1 && Rows == 1), Q>::type& operator()(int idx) {
277  return GetElement(Rows == 1 ? 0 : idx, Columns == 1 ? 0 : idx);
278  }
279  template <class Q = T>
280  inline typename std::enable_if<(Columns == 1 && Rows > 1) || (Columns > 1 && Rows == 1), Q>::type operator()(int idx) const {
281  return GetElement(Rows == 1 ? 0 : idx, Columns == 1 ? 0 : idx);
282  }
283 
284  // Submatrices
285  template <int Subrows, int Subcolumns>
287  assert(Subrows + rowIdx <= Rows);
288  assert(Subcolumns + colIdx <= Columns);
289 
290  return SubmatrixHelper<Matrix, Subrows, Subcolumns>(*this, rowIdx, colIdx);
291  }
292 
293  template <int Subrows, int Subcolumns>
295  assert(Subrows + rowIdx <= Rows);
296  assert(Subcolumns + colIdx <= Columns);
297 
298  return SubmatrixHelper<const Matrix, Subrows, Subcolumns>(*this, rowIdx, colIdx);
299  }
300 
302  auto Column(int colIdx) {
303  return Submatrix<Rows, 1>(0, colIdx);
304  }
306  auto Row(int rowIdx) {
307  return Submatrix<1, Columns>(rowIdx, 0);
308  }
310  auto Column(int colIdx) const {
311  return Submatrix<Rows, 1>(0, colIdx);
312  }
314  auto Row(int rowIdx) const {
315  return Submatrix<1, Columns>(rowIdx, 0);
316  }
317 
318  // Conversion to vector if applicable
319  template <class T2, bool Packed2, class = typename std::enable_if<VectorAssignable, T2>::type>
320  operator Vector<T2, VecDim, Packed2>() const {
322  int k = 0;
323  for (int i = 0; i < Rows; ++i) {
324  for (int j = 0; j < Columns; ++j) {
325  v(k) = (*this)(i, j);
326  ++k;
327  }
328  }
329  return v;
330  }
331 
332 protected:
333  template <int i, int j, class Head, class... Args>
334  void Assign(Head head, Args... args) {
335  (*this)(i, j) = (T)head;
336  Assign<((j != Columns - 1) ? i : (i + 1)), ((j + 1) % Columns)>(args...);
337  }
338 
339  template <int, int>
340  void Assign() {}
341 };
342 
343 
344 } // namespace mathter
T operator()(int row, int col) const
Definition: MatrixImpl.hpp:270
Props::Type operator()(int row, int col) const
Definition: MatrixImpl.hpp:187
#define MATHTER_EBCO
Definition: Definitions.hpp:82
auto Column(int colIdx)
Return the submatrix corresponding to the specified column.
Definition: MatrixImpl.hpp:302
SubmatrixHelper & operator=(const Vector< U, VecDim, Packed > &v)
Definition: MatrixImpl.hpp:139
SubmatrixHelper & operator=(const Matrix< U, SRows, SColumns, UOrder, ULayout, UPacked > &rhs)
Definition: MatrixImpl.hpp:124
std::enable_if<(Columns==1 &&Rows > 1)||(Columns > 1 &&Rows==1), Q >::type operator()(int idx) const
Definition: MatrixImpl.hpp:280
T & operator()(int row, int col)
Definition: MatrixImpl.hpp:267
auto Row(int rowIdx) const
Return the submatrix corresponding to the specified row.
Definition: MatrixImpl.hpp:314
mathter::SubmatrixHelper< Matrix, Subrows, Subcolumns > Submatrix(int rowIdx, int colIdx)
Definition: MatrixImpl.hpp:286
Represents a vector in N-dimensional space.
Definition: Definitions.hpp:57
Definition: Traits.hpp:48
Definition: MatrixImpl.hpp:24
static constexpr int StripeCount
Definition: MatrixImpl.hpp:44
auto Row(int rowIdx)
Return the submatrix corresponding to the specified row.
Definition: MatrixImpl.hpp:306
Definition: Traits.hpp:66
std::array< Vector< T, StripeDim, Packed >, StripeCount > stripes
Definition: MatrixImpl.hpp:46
Definition: Approx.hpp:11
Matrix(H h, Args... args)
Definition: MatrixImpl.hpp:249
Props::Type & operator()(int row, int col)
Definition: MatrixImpl.hpp:183
SubmatrixHelper & operator=(const SubmatrixHelper &rhs)
Definition: MatrixImpl.hpp:178
auto Column(int colIdx) const
Return the submatrix corresponding to the specified column.
Definition: MatrixImpl.hpp:310
Matrix(const Vector< T2, VecDim, Packed2 > &v)
Definition: MatrixImpl.hpp:255
Matrix(const Matrix< T2, Columns, Rows, Order==eMatrixOrder::FOLLOW_VECTOR ? eMatrixOrder::PRECEDE_VECTOR :eMatrixOrder::FOLLOW_VECTOR, Layout2, Packed2 > &rhs)
Definition: MatrixImpl.hpp:238
constexpr int Height() const
Returns the number of rows of the matrix.
Definition: MatrixImpl.hpp:39
static constexpr int StripeDim
Definition: MatrixImpl.hpp:43
Definition: Definitions.hpp:66
constexpr int ColumnCount() const
Returns the number of columns of the matrix.
Definition: MatrixImpl.hpp:27
mathter::SubmatrixHelper< const Matrix, Subrows, Subcolumns > Submatrix(int rowIdx, int colIdx) const
Definition: MatrixImpl.hpp:294
Definition: Traits.hpp:184
Definition: Definitions.hpp:63
constexpr int Width() const
Returns the number of columns of the matrix.
Definition: MatrixImpl.hpp:35
constexpr int Dimension() const
Returns the number of dimensions of the vector.
Definition: VectorImpl.hpp:402
SubmatrixHelper & operator=(const SubmatrixHelper< MatrixU, SRows, SColumns > &rhs)
Definition: MatrixImpl.hpp:154
std::enable_if<(Columns==1 &&Rows > 1)||(Columns > 1 &&Rows==1), Q >::type & operator()(int idx)
Definition: MatrixImpl.hpp:276
Matrix(const Matrix< T2, Rows, Columns, Order, Layout2, Packed2 > &rhs)
Definition: MatrixImpl.hpp:228
SubmatrixHelper(SubmatrixHelper &&rhs)
Definition: MatrixImpl.hpp:95
constexpr int RowCount() const
Returns the number of rows of the matrix.
Definition: MatrixImpl.hpp:31