17 # define CORTEX_MATRIX
24 #include <initializer_list>
41 template <
typename T,
typename Alloc = std::allocator<T>>
54 using pointer =
typename alloc_traits::pointer;
94 , m_allocator{ alloc }
118 , m_allocator{ alloc }
120 , m_finish{ m_start +
size() }
122 if constexpr (std::is_default_constructible_v<value_type>)
123 std::ranges::uninitialized_default_construct(*
this);
125 std::ranges::uninitialized_fill(*
this,
value_type{});
142 , m_allocator{ alloc }
144 , m_finish{ m_start +
size() }
145 { std::ranges::uninitialized_fill(*
this, fill_value); }
155 : m_num_rows{ other.m_num_rows }
156 , m_num_columns{ other.m_num_columns}
157 , m_allocator{ other.m_allocator }
158 , m_start{ _M_allocate(_M_size_check(m_num_rows, m_num_columns)) }
159 , m_finish{ m_start +
size() }
160 { std::ranges::uninitialized_copy(other, *
this); }
171 : m_num_rows{ other.m_num_rows }
172 , m_num_columns{ other.m_num_columns }
173 , m_allocator{ alloc }
174 , m_start{ _M_allocate(_M_size_check(other.m_num_rows, other.m_num_columns)) }
175 , m_finish{ m_start +
size() }
176 { std::ranges::uninitialized_copy(other, *
this); }
187 : m_num_rows{ other.m_num_rows }
188 , m_num_columns{ other.m_num_columns }
189 , m_allocator{ std::move(other.m_allocator) }
190 , m_start{ other.m_start }
191 , m_finish{ other.m_finish }
211 : m_num_rows{ other.m_num_rows }
212 , m_num_columns{ other.m_num_columns }
213 , m_allocator{ alloc }
214 , m_start{ other.m_start }
215 , m_finish{ other.m_finish }
237 : m_num_rows{ list.size() }
238 , m_num_columns{ list.begin()->size() }
239 , m_allocator{ alloc }
240 , m_start{ _M_allocate(_M_size_check(m_num_rows, m_num_columns)) }
241 , m_finish{ m_start +
size() }
244 for (
auto row{ list.begin() }; row != list.end(); ++row)
246 if (row->size() != this->m_num_columns)
247 throw std::invalid_argument(
"The size of the inner std::initializer_list must be same size as the number of columns in the matrix");
249 std::uninitialized_move_n(row->begin(), this->m_num_columns, m_start + offset);
250 offset += this->m_num_columns;
264 : m_num_rows{ std::get<0>(dimensions) }
265 , m_num_columns{ std::get<1>(dimensions) }
266 , m_allocator{ alloc }
267 , m_start{ _M_allocate(_M_size_check(m_num_rows, m_num_columns)) }
268 , m_finish{ m_start +
size() }
270 if constexpr (std::is_default_constructible_v<value_type>)
271 std::ranges::uninitialized_default_construct(*
this);
273 std::ranges::uninitialized_fill(*
this,
value_type{});
290 std::ranges::destroy(*
this);
291 _M_deallocate(m_start,
size());
293 m_num_rows = other.m_num_rows;
294 m_num_columns = other.m_num_columns;
295 m_allocator = other.m_allocator;
296 m_start = _M_allocate(_M_size_check(m_num_rows, m_num_columns));
297 m_finish = m_start +
size();
298 std::ranges::uninitialized_copy(other, *
this);
318 std::ranges::destroy(*
this);
319 _M_deallocate(m_start,
size());
321 m_num_rows = other.m_num_rows;
322 m_num_columns = other.m_num_columns;
323 m_allocator = std::move(other.m_allocator);
324 m_start = other.m_start;
325 m_finish = other.m_finish;
347 operator= (std::initializer_list<std::initializer_list<value_type>> list)
350 std::ranges::destroy(*
this);
351 _M_deallocate(m_start,
size());
354 m_num_rows = list.size();
355 m_num_columns = list.begin()->size();
356 m_start = _M_allocate(_M_size_check(m_num_rows, m_num_columns));
357 m_finish = m_start +
size();
360 for (
auto row{ list.begin() }; row != list.end(); ++row)
362 if (row->size() != this->m_num_columns)
363 throw std::invalid_argument(
"The size of the inner std::initializer_list must be same size as the number of columns in the matrix");
365 std::uninitialized_move_n(row->begin(), this->m_num_columns, m_start + offset);
366 offset += this->m_num_columns;
376 #if __cplusplus >= 202202L
384 std::ranges::destroy(*
this);
385 _M_deallocate(m_start,
size());
406 assign(std::initializer_list<std::initializer_list<value_type>> list)
409 auto new_rows { list.size() };
410 auto new_columns { list.begin()->size() };
412 std::ranges::destroy(*
this);
414 if (new_rows != m_num_rows || new_columns != m_num_columns)
417 _M_deallocate(m_start,
size());
419 m_start = _M_allocate(_M_size_check(new_rows, new_columns));
420 m_finish = m_start + _M_size_check(new_rows, new_columns);
423 m_num_rows = new_rows;
424 m_num_columns = new_columns;
427 for (
auto row{ list.begin() }; row != list.end(); ++row)
429 if (row->size() != this->m_num_columns)
430 throw std::invalid_argument(
"The size of the inner std::initializer_list must be same size as the number of columns in the matrix");
432 std::uninitialized_move_n(row->begin(), this->m_num_columns, m_start + offset);
433 offset += this->m_num_columns;
468 auto old_size{
size() };
469 auto new_size{ _M_size_check(new_rows, new_columns) };
471 auto new_start{ _M_allocate(new_size) };
472 auto new_finish{ new_start + new_size };
475 if (new_size > alloc_traits::max_size(m_allocator))
476 throw std::length_error(
"matrix resize too large");
478 if (old_size < new_size)
480 if (
auto old_finish_pos_in_new{ new_start + old_size }; m_start)
482 std::ranges::uninitialized_copy(m_start, m_finish, new_start, old_finish_pos_in_new);
483 std::ranges::uninitialized_fill(old_finish_pos_in_new, new_finish, fill_value);
486 std::ranges::uninitialized_fill(new_start, new_finish, fill_value);
488 else if (old_size > new_size)
490 if (
auto size_diff { old_size - new_size }; m_start)
491 std::ranges::uninitialized_copy(m_start, m_finish - size_diff, new_start, new_finish);
493 std::ranges::uninitialized_fill(new_start, new_finish, fill_value);
496 std::ranges::destroy(*
this);
497 _M_deallocate(m_start, old_size);
500 m_finish = new_finish;
502 m_num_rows = new_rows;
503 m_num_columns = new_columns;
513 [[maybe_unused]] constexpr
auto
517 auto pos { this->
begin() + (position - this->
cbegin()) };
518 std::ranges::destroy_at(std::addressof(*pos));
519 std::ranges::uninitialized_fill(pos, pos + 1,
value_type{});
532 [[maybe_unused]] constexpr
auto
536 const auto bgn { this->
begin() };
537 const auto cbgn { this->
cbegin() };
539 auto fst { bgn + (first - cbgn) };
540 auto lst { bgn + (last - cbgn) };
542 std::ranges::destroy(fst, lst);
543 return std::ranges::uninitialized_fill(fst, lst,
value_type{});
560 _M_deallocate(m_start,
size());
582 auto new_size{ _M_size_check(new_rows, new_columns) };
584 if (new_size !=
size())
585 throw std::length_error(
"Cannot reshape matrix that has different total size");
587 resize(new_rows, new_columns);
600 matrix tmp = std::move(other);
601 other = std::move(*
this);
602 *
this = std::move(tmp);
613 {
return m_allocator; }
625 : m_num_rows * m_num_columns != 0uL
626 ? m_num_rows * m_num_columns
627 : std::max(m_num_rows, m_num_columns);
638 {
return m_num_rows; }
648 {
return m_num_columns; }
659 {
return alloc_traits::max_size(m_allocator); }
669 {
return std::make_tuple(m_num_rows, m_num_columns); }
680 {
return m_num_rows == m_num_columns; }
690 {
return m_start == m_finish; }
700 {
return _M_data_ptr(m_start); }
710 {
return _M_data_ptr(m_start); }
725 _M_range_check(row, column);
726 return *(m_start + _M_index(row, column));
742 _M_range_check(row, column);
743 return *(m_start + _M_index(row, column));
757 {
return at(row, column); }
770 {
return at(row, column); }
803 {
return *(
end() - 1); }
814 {
return *(
end() - 1); }
977 template<std::copy_constructible F>
987 std::ranges::transform(*
this, result.
begin(), func);
1003 template<std::ranges::input_range Rng, std::copy_constructible F>
1006 ->
matrix<std::invoke_result_t<F,
value_type,
typename std::remove_cvref_t<decltype(*std::ranges::begin(rng))>>>
1008 using range_elem_t =
typename std::remove_cvref_t<decltype(*std::ranges::begin(rng))>;
1015 std::ranges::transform(*
this, rng, result.
begin(), func);
1033 template<std::input_iterator It, std::sentinel_for<It> Sn, std::copy_constructible Fn>
1035 map(It first, Sn last, Fn func)
const
1038 using iterator_elem_t =
typename std::remove_cvref_t<typename std::iterator_traits<It>::value_type>;
1045 std::ranges::transform(this->
begin(), this->
end(), first, last, result.
begin(), func);
1152 {
return n != 0 ? alloc_traits::allocate(m_allocator, n) :
pointer{}; }
1168 alloc_traits::deallocate(m_allocator, ptr, n);
1184 if (row >= m_num_rows || column >= m_num_columns)
1185 throw std::out_of_range(
"matrix::_M_range_check - index out of range.");
1193 throw std::invalid_argument{
"BoxView::_M_size_check - row size cannot be zero" };
1194 else if (column == 0uL)
1195 throw std::invalid_argument{
"BoxView::_M_size_check - column size cannot be zero" };
1197 return row * column;
1203 {
return row * m_num_columns + column; }
1210 template <
typename U>
1212 _M_data_ptr(U* ptr)
const noexcept
1216 #if __cplusplus >= 201103L
1226 template <
typename Ptr>
1228 _M_data_ptr(Ptr ptr)
const
1229 ->
typename std::pointer_traits<Ptr>::element_type*
1230 {
return empty() ? nullptr : std::to_address(*ptr); }
1241 template <
typename U>
1243 _M_data_ptr(U* ptr) noexcept
1261 template <
typename ElemL,
typename ElemR>
1263 { lhsE == rhsE } -> std::convertible_to<bool>;
1265 constexpr
inline auto
1267 noexcept(std::declval<ElemL>() == std::declval<ElemR>())
1268 && noexcept(std::ranges::equal(lhs, rhs))) ->
bool
1270 if (lhs.shape() != rhs.shape())
1272 return std::ranges::equal(lhs, rhs);
1286 template <
typename ElemL,
typename ElemR>
1287 constexpr
inline auto
1289 {
return std::lexicographical_compare_three_way(lhs.
begin(), lhs.
end(), rhs.
begin(), rhs.
end(), std::compare_three_way{}); }
1301 template<
typename E, std::copy_constructible F>
1305 {
return bx.
map(f); }
1321 template <
typename T>
1322 constexpr
inline auto
1324 noexcept( noexcept(x.swap(y)) ) ->
void
matrix - Two Dimensional Array
Definition: matrix.hxx:43
constexpr auto front() noexcept -> reference
Front.
Definition: matrix.hxx:779
T & reference
Definition: matrix.hxx:52
constexpr auto operator()(size_type row, size_type column) -> reference
Point based element access operator.
Definition: matrix.hxx:755
constexpr auto rbegin() const noexcept -> const_reverse_iterator
Reverse Begin Iterator (const)
Definition: matrix.hxx:867
constexpr auto is_square() const noexcept -> bool
Is Square Predicate.
Definition: matrix.hxx:678
constexpr auto data() const noexcept -> const_pointer
Data.
Definition: matrix.hxx:708
constexpr matrix(size_type num_rows, size_type num_columns, const_reference fill_value, const allocator_type &alloc=allocator_type())
Explicit Value and Size Constructor.
Definition: matrix.hxx:139
~matrix()
Destructor.
Definition: matrix.hxx:379
constexpr auto back() const noexcept -> const_reference
Back.
Definition: matrix.hxx:812
constexpr auto reshape(size_type new_rows, size_type new_columns) -> void
Reshape current matrix elements to new dimensions.
Definition: matrix.hxx:579
cxl::normal_iterator< pointer, matrix > iterator
Definition: matrix.hxx:57
std::size_t size_type
Definition: matrix.hxx:46
constexpr auto shape() const noexcept -> std::tuple< size_type, size_type >
Dimensions.
Definition: matrix.hxx:667
constexpr matrix(const matrix &other)
Copy Constructor.
Definition: matrix.hxx:154
constexpr matrix(const allocator_type &alloc) noexcept
Allocator Constructor.
Definition: matrix.hxx:91
constexpr auto crbegin() const noexcept -> const_reverse_iterator
Constant Reverse Begin Iterator.
Definition: matrix.hxx:878
constexpr matrix(std::initializer_list< std::initializer_list< value_type >> list, [[maybe_unused]] const allocator_type &alloc=allocator_type{})
Initialiser List Constructor.
Definition: matrix.hxx:236
constexpr auto erase(const_iterator position) -> iterator
Erases element indicated by position.
Definition: matrix.hxx:514
constexpr auto cbegin() const noexcept -> const_iterator
Constant Begin Iterator.
Definition: matrix.hxx:845
Alloc allocator_type
Definition: matrix.hxx:49
constexpr matrix(matrix &&other, const allocator_type &alloc) noexcept
Move Constructor with Alternative Allocator.
Definition: matrix.hxx:210
constexpr auto empty() const noexcept -> bool
Empty.
Definition: matrix.hxx:688
void swap(matrix &other) noexcept
Swaps two Matrices of the same type.
Definition: matrix.hxx:598
constexpr auto begin() noexcept -> iterator
Begin Iterator.
Definition: matrix.hxx:823
constexpr auto cend() const noexcept -> const_iterator
Constant End Iterator.
Definition: matrix.hxx:911
std::reverse_iterator< iterator > reverse_iterator
Definition: matrix.hxx:59
cxl::normal_iterator< const_pointer, matrix > const_iterator
Definition: matrix.hxx:58
T value_type
Definition: matrix.hxx:45
constexpr auto crend() const noexcept -> const_reverse_iterator
Constant Reverse End Iterator.
Definition: matrix.hxx:944
constexpr matrix() noexcept
Default Constructor.
Definition: matrix.hxx:76
constexpr auto operator=(const matrix &other) -> matrix &
Copy Assignment.
Definition: matrix.hxx:285
constexpr auto back() noexcept -> reference
Back.
Definition: matrix.hxx:801
constexpr auto num_rows() const noexcept -> size_type
Number of rows.
Definition: matrix.hxx:636
constexpr matrix(const matrix &other, const allocator_type &alloc)
Copy Constructor with Alternative Allocator.
Definition: matrix.hxx:170
constexpr auto max_size() const noexcept -> size_type
Max matrix Size.
Definition: matrix.hxx:657
constexpr matrix(size_type num_rows, size_type num_columns, const allocator_type &alloc=allocator_type{})
Default Size Constructor.
Definition: matrix.hxx:115
const T & const_reference
Definition: matrix.hxx:53
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition: matrix.hxx:60
constexpr auto resize(size_type new_rows, size_type new_columns, const_reference fill_value) -> void
Resizes Matrices memory.
Definition: matrix.hxx:465
std::ptrdiff_t difference_type
Definition: matrix.hxx:47
constexpr auto map(F func) const -> matrix< std::invoke_result_t< F, value_type >>
matrix Transpose
Definition: matrix.hxx:979
constexpr auto get_allocator() const noexcept -> allocator_type
Get Allocator.
Definition: matrix.hxx:611
constexpr auto rend() noexcept -> reverse_iterator
Reverse End Iterator.
Definition: matrix.hxx:922
typename std::allocator_traits< Alloc > alloc_traits
Definition: matrix.hxx:50
typename alloc_traits::pointer pointer
Definition: matrix.hxx:54
constexpr auto begin() const noexcept -> const_iterator
Begin Iterator (const)
Definition: matrix.hxx:834
constexpr auto at(size_type row, size_type column) const -> const_reference
Point based element access.
Definition: matrix.hxx:739
constexpr auto map(Rng &&rng, F func) const -> matrix< std::invoke_result_t< F, value_type, typename std::remove_cvref_t< decltype(*std::ranges::begin(rng))>>>
matrix map with range
Definition: matrix.hxx:1005
constexpr auto num_columns() const noexcept -> size_type
Number of Columns.
Definition: matrix.hxx:646
constexpr auto resize(size_type new_rows, size_type new_columns) -> void
Resizes the matrix memory.
Definition: matrix.hxx:444
constexpr auto clear() -> void
Clears the matrix elements.
Definition: matrix.hxx:553
constexpr auto rend() const noexcept -> const_reverse_iterator
Reverse End Iterator (const)
Definition: matrix.hxx:933
typename alloc_traits::const_pointer const_pointer
Definition: matrix.hxx:55
constexpr auto end() noexcept -> iterator
End Iterator.
Definition: matrix.hxx:889
constexpr auto data() noexcept -> pointer
Data.
Definition: matrix.hxx:698
constexpr matrix(const std::tuple< size_type, size_type > &dimensions, [[maybe_unused]] const allocator_type &alloc=allocator_type{})
Dimension Constructor.
Definition: matrix.hxx:263
constexpr auto assign(std::initializer_list< std::initializer_list< value_type >> list) -> void
Initialiser List Assign.
Definition: matrix.hxx:406
constexpr auto rbegin() noexcept -> reverse_iterator
Reverse Begin Iterator.
Definition: matrix.hxx:856
constexpr matrix(matrix &&other) noexcept
Move Constructor.
Definition: matrix.hxx:186
constexpr auto front() const noexcept -> const_reference
Front.
Definition: matrix.hxx:790
constexpr auto end() const noexcept -> const_iterator
End Iterator (const)
Definition: matrix.hxx:900
constexpr auto at(size_type row, size_type column) -> reference
Point based element access.
Definition: matrix.hxx:722
constexpr auto map(It first, Sn last, Fn func) const -> matrix< std::invoke_result_t< Fn, value_type, typename std::remove_cvref_t< typename std::iterator_traits< It >::value_type >>>
Map - Iterator Pair.
Definition: matrix.hxx:1035
constexpr auto size() const noexcept -> size_type
matrix Size
Definition: matrix.hxx:621
constexpr auto erase(const_iterator first, const_iterator last) -> iterator
Erases elements between first and last.
Definition: matrix.hxx:533
Normal Iterator.
Definition: normal.hxx:48
Definition: matrix.hxx:30
constexpr auto operator||(const matrix< E > &bx, F f) noexcept -> matrix< std::invoke_result_t< F, E >>
Map Operator.
Definition: matrix.hxx:1303
requires requires(ElemL lhsE, ElemR rhsE)
Compares two Matrices for equality.
Definition: matrix.hxx:1262
constexpr auto operator<=>(const matrix< ElemL > &lhs, const matrix< ElemR > &rhs)
Spaceship Operator for matrix.
Definition: matrix.hxx:1288
constexpr auto operator==(const matrix< ElemL > &lhs, const matrix< ElemR > &rhs) noexcept(noexcept(std::declval< ElemL >()==std::declval< ElemR >()) &&noexcept(std::ranges::equal(lhs, rhs))) -> bool
Definition: matrix.hxx:1266
Definition: matrix.hxx:1310
constexpr auto swap(cxl::matrix< T > &x, cxl::matrix< T > &y) noexcept(noexcept(x.swap(y))) -> void
Uses std::swap to swap the contents of two matrices.
Definition: matrix.hxx:1323
Adapts a non-object iterator to an object iterator without changing its semantics.