Stratax 0.2.0
Loading...
Searching...
No Matches
Matrix.hpp
1#pragma once
2
3#include <stratax/core/containers/Buffer.hpp>
4#include <stratax/core/Concepts.hpp>
5#include <stratax/core/containers/Shape.hpp>
6#include <stratax/core/Exceptions.hpp>
7#include <stratax/core/containers/Strides.hpp>
9
10#include <initializer_list>
11#include <cstddef>
12#include <iterator>
13#include <utility>
14
15namespace stratax::container {
16
26template<typename T>
27requires Numeric<T>
28class Matrix
29{
30private:
31 core::Shape shape_;
32 core::Strides strides_;
33 core::Buffer<T> buffer_;
34
35public:
37 using value_type = T;
38
41
44
47
50
52 template<typename U>
54
60 Matrix(): Matrix(0, 0) {}
61
68 Matrix(std::size_t rows, std::size_t cols)
69 : shape_({rows, cols}, core::Shape::allow_zero),
70 strides_(shape_),
71 buffer_(core::validation::checked_multiply(rows, cols, "Matrix size overflow"))
72 {
73 }
74
82 explicit Matrix(const core::Shape& shape)
83 : shape_(core::validation::require_rank(shape, 2, "Shape must be rank 2")),
84 strides_(shape_),
85 buffer_(core::validation::checked_multiply(
86 shape_(0),
87 shape_(1),
88 "Matrix size overflow"))
89 {
90 }
91
99 Matrix(std::size_t rows, std::size_t cols, const T& value)
100 : shape_({rows, cols}, core::Shape::allow_zero),
101 strides_(shape_),
102 buffer_(core::validation::checked_multiply(rows, cols, "Matrix size overflow"), value)
103 {
104 }
105
115 Matrix(std::initializer_list<std::initializer_list<T>> list)
116 {
117 std::size_t rows = list.size();
118 std::size_t cols = (rows == 0) ? 0 : list.begin()->size();
119
120 // Ensure all rows have the same length
121 for (const auto& row : list)
122 {
123 if (row.size() != cols)
124 {
125 throw Exceptions::ShapeError("Matrix initializer rows must all have the same number of columns.");
126 }
127 }
128
130 strides_ = stratax::core::Strides(shape_);
131 buffer_ = stratax::core::Buffer<T>(
132 core::validation::checked_multiply(rows, cols, "Matrix size overflow"));
133
134 std::size_t index = 0;
135
136 for (const auto& row : list)
137 {
138 for (const auto& value : row)
139 {
140 buffer_[index++] = value;
141 }
142 }
143 }
144
148 Matrix(const Matrix&) = default;
149
153 Matrix(Matrix&&) noexcept = default;
154
158 Matrix& operator=(const Matrix&) = default;
159
163 Matrix& operator=(Matrix&&) noexcept = default;
164
168 ~Matrix() = default;
169
175 [[nodiscard]] std::size_t size() const noexcept
176 {
177 return shape_.elements();
178 }
179
185 [[nodiscard]] bool empty() const noexcept
186 {
187 return buffer_.empty();
188 }
189
195 [[nodiscard]] std::size_t rows() const noexcept
196 {
197 return shape_(0);
198 }
199
205 [[nodiscard]] std::size_t cols() const noexcept
206 {
207 return shape_(1);
208 }
209
215 const stratax::core::Shape& shape() const noexcept
216 {
217 return shape_;
218 }
219
225 const stratax::core::Strides& strides() const noexcept
226 {
227 return strides_;
228 }
229
235 [[nodiscard]] std::size_t rank() const noexcept
236 {
237 return shape_.rank();
238 }
239
249 T& operator()(std::size_t row, std::size_t col)
250 {
251 core::validation::require_index(row, rows(), "Row index out of bounds.");
252 core::validation::require_index(col, cols(), "Column index out of bounds.");
253 return buffer_[row * cols() + col];
254 }
255
265 const T& operator()(std::size_t row, std::size_t col) const
266 {
267 core::validation::require_index(row, rows(), "Row index out of bounds.");
268 core::validation::require_index(col, cols(), "Column index out of bounds.");
269 return buffer_[row * cols() + col];
270 }
271
280 T& operator[](std::size_t index) noexcept
281 {
282 return buffer_[index];
283 }
284
293 const T& operator[](std::size_t index) const noexcept
294 {
295 return buffer_[index];
296 }
297
307 T& at(std::ptrdiff_t row, std::ptrdiff_t col)
308 {
309 const std::size_t normalized_row =
310 core::validation::normalize_index(row, rows(), "Row index out of bounds.");
311 const std::size_t normalized_col =
312 core::validation::normalize_index(col, cols(), "Column index out of bounds.");
313 return (*this)(normalized_row, normalized_col);
314 }
315
325 const T& at(std::ptrdiff_t row, std::ptrdiff_t col) const
326 {
327 const std::size_t normalized_row =
328 core::validation::normalize_index(row, rows(), "Row index out of bounds.");
329 const std::size_t normalized_col =
330 core::validation::normalize_index(col, cols(), "Column index out of bounds.");
331 return (*this)(normalized_row, normalized_col);
332 }
333
340 T& front()
341 {
342 if (empty())
343 {
344 throw Exceptions::IndexError("Matrix front cannot be accessed when the matrix is empty.");
345 }
346
347 return buffer_.front();
348 }
349
356 const T& front() const
357 {
358 if (empty())
359 {
360 throw Exceptions::IndexError("Matrix front cannot be accessed when the matrix is empty.");
361 }
362
363 return buffer_.front();
364 }
365
372 T& back()
373 {
374 if (empty())
375 {
376 throw Exceptions::IndexError("Matrix back cannot be accessed when the matrix is empty.");
377 }
378
379 return buffer_.back();
380 }
381
388 const T& back() const
389 {
390 if (empty())
391 {
392 throw Exceptions::IndexError("Matrix back cannot be accessed when the matrix is empty.");
393 }
394
395 return buffer_.back();
396 }
397
403 [[nodiscard]] T* data() noexcept
404 {
405 return buffer_.data();
406 }
407
413 [[nodiscard]] const T* data() const noexcept
414 {
415 return buffer_.data();
416 }
417
423 [[nodiscard]] iterator begin() noexcept
424 {
425 return buffer_.begin();
426 }
427
433 [[nodiscard]] const_iterator begin() const noexcept
434 {
435 return buffer_.begin();
436 }
437
443 [[nodiscard]] const_iterator cbegin() const noexcept
444 {
445 return buffer_.cbegin();
446 }
447
453 [[nodiscard]] iterator end() noexcept
454 {
455 return buffer_.end();
456 }
457
463 [[nodiscard]] const_iterator end() const noexcept
464 {
465 return buffer_.end();
466 }
467
473 [[nodiscard]] const_iterator cend() const noexcept
474 {
475 return buffer_.cend();
476 }
477
483 [[nodiscard]] reverse_iterator rbegin() noexcept
484 {
485 return buffer_.rbegin();
486 }
487
493 [[nodiscard]] const_reverse_iterator rbegin() const noexcept
494 {
495 return buffer_.rbegin();
496 }
497
503 [[nodiscard]] const_reverse_iterator crbegin() const noexcept
504 {
505 return buffer_.crbegin();
506 }
507
513 [[nodiscard]] reverse_iterator rend() noexcept
514 {
515 return buffer_.rend();
516 }
517
523 [[nodiscard]] const_reverse_iterator rend() const noexcept
524 {
525 return buffer_.rend();
526 }
527
533 [[nodiscard]] const_reverse_iterator crend() const noexcept
534 {
535 return buffer_.crend();
536 }
537
543 void fill(const T& value)
544 {
545 buffer_.fill(value);
546 }
547
553 void swap(Matrix& other) noexcept
554 {
555 using std::swap;
556
557 swap(shape_, other.shape_);
558 swap(strides_, other.strides_);
559 swap(buffer_, other.buffer_);
560 }
561};
562
563}
564
Shared runtime validation helpers.
Signals an invalid index access.
Signals an invalid or incompatible shape.
const_iterator cend() const noexcept
Returns a const iterator one past the last element.
Definition Matrix.hpp:473
T * data() noexcept
Returns the raw data pointer.
Definition Matrix.hpp:403
const T & back() const
Returns the last element as a const reference.
Definition Matrix.hpp:388
void fill(const T &value)
Fills every element with the same value.
Definition Matrix.hpp:543
typename core::Buffer< T >::const_reverse_iterator const_reverse_iterator
Const reverse iterator over matrix elements.
Definition Matrix.hpp:49
const_reverse_iterator crbegin() const noexcept
Returns a const reverse iterator to the last element.
Definition Matrix.hpp:503
const_iterator cbegin() const noexcept
Returns a const iterator to the first element.
Definition Matrix.hpp:443
const T & front() const
Returns the first element as a const reference.
Definition Matrix.hpp:356
typename core::Buffer< T >::iterator iterator
Mutable iterator over matrix elements.
Definition Matrix.hpp:40
Matrix()
Creates a default rank-2 empty matrix.
Definition Matrix.hpp:60
Matrix(std::initializer_list< std::initializer_list< T > > list)
Creates a matrix from a nested initializer list.
Definition Matrix.hpp:115
T & front()
Returns the first element.
Definition Matrix.hpp:340
bool empty() const noexcept
Returns whether the matrix contains no elements.
Definition Matrix.hpp:185
const T & operator()(std::size_t row, std::size_t col) const
Returns an element by row and column with bounds checking.
Definition Matrix.hpp:265
const T * data() const noexcept
Returns the raw data pointer as a const pointer.
Definition Matrix.hpp:413
Matrix< U > rebind
Rebinds the matrix container to another element type.
Definition Matrix.hpp:53
typename core::Buffer< T >::const_iterator const_iterator
Const iterator over matrix elements.
Definition Matrix.hpp:43
reverse_iterator rbegin() noexcept
Returns a reverse iterator to the last element.
Definition Matrix.hpp:483
T & operator[](std::size_t index) noexcept
Returns a flat element without bounds checking.
Definition Matrix.hpp:280
const stratax::core::Strides & strides() const noexcept
Returns the matrix strides.
Definition Matrix.hpp:225
const_reverse_iterator rbegin() const noexcept
Returns a const reverse iterator to the last element.
Definition Matrix.hpp:493
T & operator()(std::size_t row, std::size_t col)
Returns an element by row and column with bounds checking.
Definition Matrix.hpp:249
T & back()
Returns the last element.
Definition Matrix.hpp:372
Matrix(std::size_t rows, std::size_t cols, const T &value)
Creates a matrix and fills it with a value.
Definition Matrix.hpp:99
T value_type
Element type stored by the matrix.
Definition Matrix.hpp:37
std::size_t rank() const noexcept
Returns the matrix rank.
Definition Matrix.hpp:235
Matrix(const core::Shape &shape)
Creates a matrix from a validated rank-2 shape.
Definition Matrix.hpp:82
const_reverse_iterator crend() const noexcept
Returns a const reverse iterator before the first element.
Definition Matrix.hpp:533
void swap(Matrix &other) noexcept
Swaps the contents of two matrices.
Definition Matrix.hpp:553
const T & operator[](std::size_t index) const noexcept
Returns a flat element without bounds checking.
Definition Matrix.hpp:293
Matrix(Matrix &&) noexcept=default
Transfers ownership from another matrix.
Matrix(const Matrix &)=default
Creates a copy of another matrix.
const stratax::core::Shape & shape() const noexcept
Definition Matrix.hpp:215
iterator begin() noexcept
Returns an iterator to the first element.
Definition Matrix.hpp:423
const_iterator begin() const noexcept
Returns a const iterator to the first element.
Definition Matrix.hpp:433
std::size_t size() const noexcept
Definition Matrix.hpp:175
Matrix(std::size_t rows, std::size_t cols)
Creates a rank-2 matrix with the given number of rows and columns.
Definition Matrix.hpp:68
reverse_iterator rend() noexcept
Returns a reverse iterator before the first element.
Definition Matrix.hpp:513
const_reverse_iterator rend() const noexcept
Returns a const reverse iterator before the first element.
Definition Matrix.hpp:523
typename core::Buffer< T >::reverse_iterator reverse_iterator
Mutable reverse iterator over matrix elements.
Definition Matrix.hpp:46
iterator end() noexcept
Returns an iterator one past the last element.
Definition Matrix.hpp:453
const T & at(std::ptrdiff_t row, std::ptrdiff_t col) const
Returns an element by row and column.
Definition Matrix.hpp:325
const_iterator end() const noexcept
Returns a const iterator one past the last element.
Definition Matrix.hpp:463
T & at(std::ptrdiff_t row, std::ptrdiff_t col)
Returns an element by row and column.
Definition Matrix.hpp:307
std::size_t rows() const noexcept
Definition Matrix.hpp:195
std::size_t cols() const noexcept
Definition Matrix.hpp:205
Owns contiguous dynamically allocated storage.
Definition Buffer.hpp:38
std::reverse_iterator< iterator > reverse_iterator
Mutable reverse iterator over contiguous buffer elements.
Definition Buffer.hpp:53
const T * const_iterator
Const iterator over contiguous buffer elements.
Definition Buffer.hpp:50
T * iterator
Mutable iterator over contiguous buffer elements.
Definition Buffer.hpp:47
std::reverse_iterator< const_iterator > const_reverse_iterator
Const reverse iterator over contiguous buffer elements.
Definition Buffer.hpp:56
Stores a list of dimension lengths for an array shape.
Definition Shape.hpp:22
static constexpr allow_zero_t allow_zero
Tag value documenting that zero-valued dimensions are intentional.
Definition Shape.hpp:41
Stores strides for a shape in contiguous memory.
Definition Strides.hpp:23