Stratax
Scientific computing containers and operations
Loading...
Searching...
No Matches
Matrix.hpp
Go to the documentation of this file.
1#pragma once
2
9
10#include <initializer_list>
11#include <cstddef>
12#include <iterator>
13#include <utility>
14
16
17template<typename T>
18requires Numeric<T>
28class Matrix
29{
30private:
31 core::Shape shape_;
32 core::Strides strides_;
33 core::Buffer<T> buffer_;
34
35public:
36 using value_type = T;
37
38 template<typename U>
40
46 Matrix(): Matrix(0, 0) {}
47
54 Matrix(std::size_t rows, std::size_t cols)
55 : shape_({rows, cols}, core::Shape::allow_zero),
56 strides_(shape_),
57 buffer_(core::validation::checked_multiply(rows, cols, "Matrix size overflow"))
58 {
59 }
60
68 explicit Matrix(const core::Shape& shape)
69 : shape_(core::validation::require_rank(shape, 2, "Shape must be rank 2")),
70 strides_(shape_),
71 buffer_(core::validation::checked_multiply(
72 shape_(0),
73 shape_(1),
74 "Matrix size overflow"))
75 {
76 }
77
85 Matrix(std::size_t rows, std::size_t cols, const T& value)
86 : shape_({rows, cols}, core::Shape::allow_zero),
87 strides_(shape_),
88 buffer_(core::validation::checked_multiply(rows, cols, "Matrix size overflow"), value)
89 {
90 }
91
101 Matrix(std::initializer_list<std::initializer_list<T>> list)
102 {
103 std::size_t rows = list.size();
104 std::size_t cols = (rows == 0) ? 0 : list.begin()->size();
105
106 // Ensure all rows have the same length
107 for (const auto& row : list)
108 {
109 if (row.size() != cols)
110 {
111 throw Exceptions::StrataxError("All rows must have the same number of columns.");
112 }
113 }
114
116 strides_ = stratax::core::Strides(shape_);
117 buffer_ = stratax::core::Buffer<T>(
118 core::validation::checked_multiply(rows, cols, "Matrix size overflow"));
119
120 std::size_t index = 0;
121
122 for (const auto& row : list)
123 {
124 for (const auto& value : row)
125 {
126 buffer_[index++] = value;
127 }
128 }
129 }
130
134 Matrix(const Matrix&) = default;
135
139 Matrix(Matrix&&) noexcept = default;
140
144 Matrix& operator=(const Matrix&) = default;
145
149 Matrix& operator=(Matrix&&) noexcept = default;
150
154 ~Matrix() = default;
155
161 [[nodiscard]] std::size_t size() const noexcept
162 {
163 return shape_.elements();
164 }
165
171 [[nodiscard]] bool empty() const noexcept
172 {
173 return buffer_.empty();
174 }
175
181 [[nodiscard]] std::size_t rows() const noexcept
182 {
183 return shape_(0);
184 }
185
191 [[nodiscard]] std::size_t cols() const noexcept
192 {
193 return shape_(1);
194 }
195
201 const stratax::core::Shape& shape() const noexcept
202 {
203 return shape_;
204 }
205
211 const stratax::core::Strides& strides() const noexcept
212 {
213 return strides_;
214 }
215
221 [[nodiscard]] std::size_t rank() const noexcept
222 {
223 return shape_.rank();
224 }
225
235 T& operator()(std::size_t row, std::size_t col)
236 {
237 core::validation::require_index(row, rows(), "Row index out of bounds.");
238 core::validation::require_index(col, cols(), "Column index out of bounds.");
239 return buffer_[row * cols() + col];
240 }
241
251 const T& operator()(std::size_t row, std::size_t col) const
252 {
253 core::validation::require_index(row, rows(), "Row index out of bounds.");
254 core::validation::require_index(col, cols(), "Column index out of bounds.");
255 return buffer_[row * cols() + col];
256 }
257
266 T& operator[](std::size_t index) noexcept
267 {
268 return buffer_[index];
269 }
270
279 const T& operator[](std::size_t index) const noexcept
280 {
281 return buffer_[index];
282 }
283
293 T& at(std::size_t row, std::size_t col)
294 {
295 return (*this)(row, col);
296 }
297
307 const T& at(std::size_t row, std::size_t col) const
308 {
309 return (*this)(row, col);
310 }
311
318 T& front()
319 {
320 if (empty())
321 {
322 throw Exceptions::IndexError("Cannot access front of an empty matrix.");
323 }
324
325 return buffer_.front();
326 }
327
334 const T& front() const
335 {
336 if (empty())
337 {
338 throw Exceptions::IndexError("Cannot access front of an empty matrix.");
339 }
340
341 return buffer_.front();
342 }
343
350 T& back()
351 {
352 if (empty())
353 {
354 throw Exceptions::IndexError("Cannot access back of an empty matrix.");
355 }
356
357 return buffer_.back();
358 }
359
366 const T& back() const
367 {
368 if (empty())
369 {
370 throw Exceptions::IndexError("Cannot access back of an empty matrix.");
371 }
372
373 return buffer_.back();
374 }
375
381 [[nodiscard]] T* data() noexcept
382 {
383 return buffer_.data();
384 }
385
391 [[nodiscard]] const T* data() const noexcept
392 {
393 return buffer_.data();
394 }
395
401 [[nodiscard]] T* begin() noexcept
402 {
403 return buffer_.begin();
404 }
405
411 [[nodiscard]] const T* begin() const noexcept
412 {
413 return buffer_.begin();
414 }
415
421 [[nodiscard]] const T* cbegin() const noexcept
422 {
423 return buffer_.cbegin();
424 }
425
431 [[nodiscard]] T* end() noexcept
432 {
433 return buffer_.end();
434 }
435
441 [[nodiscard]] const T* end() const noexcept
442 {
443 return buffer_.end();
444 }
445
451 [[nodiscard]] const T* cend() const noexcept
452 {
453 return buffer_.cend();
454 }
455
461 [[nodiscard]] std::reverse_iterator<T*> rbegin() noexcept
462 {
463 return buffer_.rbegin();
464 }
465
471 [[nodiscard]] std::reverse_iterator<const T*> rbegin() const noexcept
472 {
473 return buffer_.rbegin();
474 }
475
481 [[nodiscard]] std::reverse_iterator<const T*> crbegin() const noexcept
482 {
483 return buffer_.crbegin();
484 }
485
491 [[nodiscard]] std::reverse_iterator<T*> rend() noexcept
492 {
493 return buffer_.rend();
494 }
495
501 [[nodiscard]] std::reverse_iterator<const T*> rend() const noexcept
502 {
503 return buffer_.rend();
504 }
505
511 [[nodiscard]] std::reverse_iterator<const T*> crend() const noexcept
512 {
513 return buffer_.crend();
514 }
515
521 void fill(const T& value)
522 {
523 buffer_.fill(value);
524 }
525
531 void swap(Matrix& other) noexcept
532 {
533 using std::swap;
534
535 swap(shape_, other.shape_);
536 swap(strides_, other.strides_);
537 swap(buffer_, other.buffer_);
538 }
539};
540
541}
Shared runtime validation helpers.
Signals an invalid index access.
Base class for Stratax-specific runtime errors.
Definition Exceptions.hpp:9
std::reverse_iterator< const T * > crend() const noexcept
Returns a const reverse iterator before the first element.
Definition Matrix.hpp:511
const T * begin() const noexcept
Returns a const iterator to the first element.
Definition Matrix.hpp:411
std::reverse_iterator< T * > rend() noexcept
Returns a reverse iterator before the first element.
Definition Matrix.hpp:491
T * data() noexcept
Returns the raw data pointer.
Definition Matrix.hpp:381
const T & back() const
Returns the last element as a const reference.
Definition Matrix.hpp:366
void fill(const T &value)
Fills every element with the same value.
Definition Matrix.hpp:521
const T & front() const
Returns the first element as a const reference.
Definition Matrix.hpp:334
Matrix()
Creates a default rank-2 empty matrix.
Definition Matrix.hpp:46
Matrix(std::initializer_list< std::initializer_list< T > > list)
Creates a matrix from a nested initializer list.
Definition Matrix.hpp:101
std::reverse_iterator< const T * > crbegin() const noexcept
Returns a const reverse iterator to the last element.
Definition Matrix.hpp:481
T & front()
Returns the first element.
Definition Matrix.hpp:318
const T & at(std::size_t row, std::size_t col) const
Returns an element by row and column.
Definition Matrix.hpp:307
bool empty() const noexcept
Returns whether the matrix contains no elements.
Definition Matrix.hpp:171
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:251
const T * data() const noexcept
Returns the raw data pointer as a const pointer.
Definition Matrix.hpp:391
std::reverse_iterator< const T * > rbegin() const noexcept
Returns a const reverse iterator to the last element.
Definition Matrix.hpp:471
const T * cend() const noexcept
Returns a const iterator one past the last element.
Definition Matrix.hpp:451
T & operator[](std::size_t index) noexcept
Returns a flat element without bounds checking.
Definition Matrix.hpp:266
const stratax::core::Strides & strides() const noexcept
Returns the matrix strides.
Definition Matrix.hpp:211
T & operator()(std::size_t row, std::size_t col)
Returns an element by row and column with bounds checking.
Definition Matrix.hpp:235
T & back()
Returns the last element.
Definition Matrix.hpp:350
T * end() noexcept
Returns an iterator one past the last element.
Definition Matrix.hpp:431
Matrix(std::size_t rows, std::size_t cols, const T &value)
Creates a matrix and fills it with a value.
Definition Matrix.hpp:85
std::size_t rank() const noexcept
Returns the matrix rank.
Definition Matrix.hpp:221
const T * cbegin() const noexcept
Returns a const iterator to the first element.
Definition Matrix.hpp:421
Matrix(const core::Shape &shape)
Creates a matrix from a validated rank-2 shape.
Definition Matrix.hpp:68
void swap(Matrix &other) noexcept
Swaps the contents of two matrices.
Definition Matrix.hpp:531
const T & operator[](std::size_t index) const noexcept
Returns a flat element without bounds checking.
Definition Matrix.hpp:279
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:201
std::size_t size() const noexcept
Definition Matrix.hpp:161
std::reverse_iterator< T * > rbegin() noexcept
Returns a reverse iterator to the last element.
Definition Matrix.hpp:461
const T * end() const noexcept
Returns a const iterator one past the last element.
Definition Matrix.hpp:441
T * begin() noexcept
Returns an iterator to the first element.
Definition Matrix.hpp:401
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:54
std::reverse_iterator< const T * > rend() const noexcept
Returns a const reverse iterator before the first element.
Definition Matrix.hpp:501
T & at(std::size_t row, std::size_t col)
Returns an element by row and column.
Definition Matrix.hpp:293
std::size_t rows() const noexcept
Definition Matrix.hpp:181
std::size_t cols() const noexcept
Definition Matrix.hpp:191
Owns contiguous dynamically allocated storage.
Definition Buffer.hpp:38
Stores a list of dimension lengths for an array shape.
Definition Shape.hpp:20
static constexpr allow_zero_t allow_zero
Definition Shape.hpp:36
Stores strides for a shape in contiguous memory.
Definition Strides.hpp:23
Matches all scalar types supported by Stratax numeric containers.
Definition Concepts.hpp:152
std::size_t checked_multiply(std::size_t lhs, std::size_t rhs, const char *message)
Multiplies two sizes while checking for overflow.
void require_index(std::size_t index, std::size_t size, const char *message)
Requires an index to be less than a size.