25 namespace seqan3::detail
30 struct number_cols : strong_type<size_t, number_cols>
33 using strong_type<size_t, number_cols>::strong_type;
38 struct number_rows : strong_type<size_t, number_rows>
41 using strong_type<size_t, number_rows>::strong_type;
60 template <
typename value_t,
62 matrix_major_order order = matrix_major_order::row>
63 class two_dimensional_matrix
74 template <
typename matrix_t>
82 using value_type =
typename storage_type::value_type;
83 using reference =
typename storage_type::reference;
84 using const_reference =
typename storage_type::const_reference;
85 using pointer =
typename storage_type::pointer;
86 using const_pointer =
typename storage_type::const_pointer;
87 using difference_type =
typename storage_type::difference_type;
88 using size_type =
typename storage_type::size_type;
89 using iterator = iterator_type<two_dimensional_matrix>;
90 using const_iterator = iterator_type<two_dimensional_matrix const>;
96 two_dimensional_matrix() =
default;
97 two_dimensional_matrix(two_dimensional_matrix
const &) =
default;
98 two_dimensional_matrix(two_dimensional_matrix &&) =
default;
99 two_dimensional_matrix & operator=(two_dimensional_matrix
const &) =
default;
100 two_dimensional_matrix & operator=(two_dimensional_matrix &&) =
default;
101 ~two_dimensional_matrix() =
default;
107 two_dimensional_matrix(number_rows
const row_dim, number_cols
const col_dim) :
108 row_dim{row_dim.get()}, col_dim{col_dim.get()}
110 storage.resize(row_dim.get() * col_dim.get());
119 template <std::ranges::forward_range entries_t>
121 requires (std::convertible_to<std::ranges::range_value_t<entries_t>, value_type>)
123 two_dimensional_matrix(number_rows const row_dim, number_cols const col_dim, entries_t entries) :
124 row_dim{row_dim.get()},
125 col_dim{col_dim.get()}
127 static_assert(std::move_constructible<std::ranges::range_value_t<entries_t>>,
"The value type must be moveable.");
129 assert(
static_cast<size_t>(std::ranges::distance(entries)) == (row_dim.get() * col_dim.get()));
130 storage.resize(row_dim.get() * col_dim.get());
135 two_dimensional_matrix(number_rows
const row_dim, number_cols
const col_dim, storage_type entries) :
136 row_dim{row_dim.get()},
137 col_dim{col_dim.get()}
139 assert(
static_cast<size_t>(std::ranges::distance(entries)) == (row_dim.get() * col_dim.get()));
168 template <
typename other_value_t,
typename other_allocator_t, matrix_major_order other_order>
170 requires std::assignable_from<other_value_t &, value_t &>
172 explicit constexpr two_dimensional_matrix(two_dimensional_matrix<other_value_t,
174 other_order>
const & matrix) :
175 two_dimensional_matrix{number_rows{matrix.rows()}, number_cols{matrix.cols()}}
177 for (
size_t i = 0; i < cols(); ++i)
179 for (
size_t j = 0; j < rows(); ++j)
181 matrix_coordinate coord{row_index_type{j}, column_index_type{i}};
182 (*this)[coord] = matrix[coord];
191 constexpr reference operator[](matrix_coordinate
const & coordinate) noexcept
193 assert(coordinate.col < cols());
194 assert(coordinate.row < rows());
196 return *(
begin() + matrix_offset{row_index_type{
static_cast<std::ptrdiff_t>(coordinate.row)},
201 constexpr const_reference operator[](matrix_coordinate
const & coordinate)
const noexcept
203 assert(coordinate.col < cols());
204 assert(coordinate.row < rows());
206 return *(
begin() + matrix_offset{row_index_type{
static_cast<std::ptrdiff_t>(coordinate.row)},
211 constexpr reference
at(matrix_coordinate
const & coordinate)
213 if (coordinate.col >= cols())
214 throw std::invalid_argument{
"Column index is out of range. Please check the dimensions of the matrix."};
215 if (coordinate.row >= rows())
216 throw std::invalid_argument{
"Row index is out of range. Please check the dimensions of the matrix."};
218 return (*
this)[coordinate];
222 constexpr const_reference
at(matrix_coordinate
const & coordinate)
const
224 if (coordinate.col >= cols())
225 throw std::invalid_argument{
"Column index is out of range. Please check the dimensions of the matrix."};
226 if (coordinate.row >= rows())
227 throw std::invalid_argument{
"Row index is out of range. Please check the dimensions of the matrix."};
229 return (*
this)[coordinate];
237 void resize(number_rows
const row_dim, number_cols
const col_dim)
239 this->row_dim = row_dim.get();
240 this->col_dim = col_dim.get();
241 storage.resize(this->row_dim * this->col_dim);
245 size_t rows() const noexcept
251 size_t cols() const noexcept
257 constexpr pointer
data() noexcept
259 return storage.data();
263 constexpr const_pointer
data() const noexcept
265 return storage.data();
272 constexpr iterator
begin() noexcept
275 return {*
this, storage.begin()};
278 constexpr const_iterator
begin() const noexcept
280 return {*
this, storage.begin()};
284 constexpr const_iterator
cbegin() const noexcept
290 constexpr iterator
end() noexcept
292 return {*
this, storage.end()};
296 constexpr const_iterator
end() const noexcept
298 return {*
this, storage.end()};
302 constexpr const_iterator
cend() const noexcept
310 storage_type storage;
323 template <
typename value_t,
typename allocator_t, matrix_major_order order>
324 template <
typename matrix_t>
325 class two_dimensional_matrix<value_t, allocator_t, order>::iterator_type :
326 public two_dimensional_matrix_iterator_base<iterator_type<matrix_t>, order>
330 using base_t = two_dimensional_matrix_iterator_base<iterator_type<matrix_t>, order>;
333 template <
typename derived_t, matrix_major_order other_order>
335 requires is_type_specialisation_of_v<derived_t, iterator_type> && (other_order == order)
337 friend class two_dimensional_matrix_iterator_base;
340 template <
typename other_matrix_t>
341 requires std::same_as<other_matrix_t, std::remove_const_t<matrix_t>> &&
342 std::is_const_v<matrix_t>
343 friend class iterator_type;
346 using storage_iterator = std::ranges::iterator_t<
348 std::is_const_v<matrix_t>, storage_type
const, storage_type
362 using pointer =
typename storage_iterator::pointer;
372 constexpr iterator_type() =
default;
373 constexpr iterator_type(iterator_type
const &) =
default;
374 constexpr iterator_type(iterator_type &&) =
default;
375 constexpr iterator_type & operator=(iterator_type
const &) =
default;
376 constexpr iterator_type & operator=(iterator_type &&) =
default;
377 ~iterator_type() =
default;
383 constexpr iterator_type(matrix_t & matrix, storage_iterator iter) :
389 template <
typename other_matrix_t>
391 requires std::same_as<other_matrix_t, std::remove_const_t<matrix_t>> && std::is_const_v<matrix_t>
393 constexpr iterator_type(
394 iterator_type<other_matrix_t> other) noexcept :
395 matrix_ptr{other.matrix_ptr},
396 host_iter{other.host_iter}
401 using base_t::operator+=;
404 constexpr iterator_type & operator+=(matrix_offset
const & offset) noexcept
406 assert(matrix_ptr !=
nullptr);
408 if constexpr (order == matrix_major_order::column)
410 host_iter += (offset.col * matrix_ptr->rows());
411 host_iter += offset.row;
415 host_iter += offset.col;
416 host_iter += (offset.row * matrix_ptr->cols());
422 matrix_coordinate coordinate() const noexcept
424 assert(matrix_ptr !=
nullptr);
426 auto diff = *
this - matrix_ptr->begin();
427 if constexpr (order == matrix_major_order::column)
428 return {row_index_type{diff % matrix_ptr->rows()}, column_index_type{diff / matrix_ptr->rows()}};
430 return {row_index_type{diff / matrix_ptr->cols()}, column_index_type{diff % matrix_ptr->cols()}};
435 matrix_t * matrix_ptr{
nullptr};
436 storage_iterator host_iter{};