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>
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()}
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>
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 >= 0u);
194 assert(coordinate.row >= 0u);
195 assert(coordinate.col < cols());
196 assert(coordinate.row < rows());
198 return *(
begin() + matrix_offset{row_index_type{static_cast<std::ptrdiff_t>(coordinate.row)},
199 column_index_type{static_cast<std::ptrdiff_t>(coordinate.col)}});
203 constexpr const_reference operator[](matrix_coordinate
const & coordinate)
const noexcept
205 assert(coordinate.col >= 0);
206 assert(coordinate.row >= 0);
207 assert(static_cast<size_t>(coordinate.col) < cols());
208 assert(static_cast<size_t>(coordinate.row) < rows());
210 return *(
begin() + matrix_offset{row_index_type{static_cast<std::ptrdiff_t>(coordinate.row)},
211 column_index_type{static_cast<std::ptrdiff_t>(coordinate.col)}});
215 constexpr reference
at(matrix_coordinate
const & coordinate)
217 if (static_cast<size_t>(coordinate.col) >= cols())
218 throw std::invalid_argument{
"Column index is out of range. Please check the dimensions of the matrix."};
219 if (static_cast<size_t>(coordinate.row) >= rows())
220 throw std::invalid_argument{
"Row index is out of range. Please check the dimensions of the matrix."};
222 return (*
this)[coordinate];
226 constexpr const_reference
at(matrix_coordinate
const & coordinate)
const
228 if (static_cast<size_t>(coordinate.col) >= cols())
229 throw std::invalid_argument{
"Column index is out of range. Please check the dimensions of the matrix."};
230 if (static_cast<size_t>(coordinate.row) >= rows())
231 throw std::invalid_argument{
"Row index is out of range. Please check the dimensions of the matrix."};
233 return (*
this)[coordinate];
237 size_t rows() const noexcept
243 size_t cols() const noexcept
249 constexpr pointer
data() noexcept
251 return storage.data();
255 constexpr const_pointer
data() const noexcept
257 return storage.data();
264 constexpr iterator
begin() noexcept
267 return {*
this, storage.begin()};
270 constexpr const_iterator
begin() const noexcept
272 return {*
this, storage.begin()};
276 constexpr const_iterator
cbegin() const noexcept
282 constexpr iterator
end() noexcept
284 return {*
this, storage.end()};
288 constexpr const_iterator
end() const noexcept
290 return {*
this, storage.end()};
294 constexpr const_iterator
cend() const noexcept
302 storage_type storage;
315 template <
typename value_t,
typename allocator_t, matrix_major_order order>
316 template <
typename matrix_t>
317 class two_dimensional_matrix<value_t, allocator_t, order>::iterator_type :
318 public two_dimensional_matrix_iterator_base<iterator_type<matrix_t>, order>
322 using base_t = two_dimensional_matrix_iterator_base<iterator_type<matrix_t>, order>;
325 template <
typename derived_t, matrix_major_order other_order>
326 requires is_type_specialisation_of_v<derived_t, iterator_type> && other_order == order
327 friend class two_dimensional_matrix_iterator_base;
330 template <
typename other_matrix_t>
332 std::is_const_v<matrix_t>
333 friend class iterator_type;
336 using storage_iterator = std::ranges::iterator_t<
338 std::is_const_v<matrix_t>, storage_type
const, storage_type
347 using value_type = value_type_t<storage_iterator>;
350 using reference = reference_t<storage_iterator>;
352 using pointer =
typename storage_iterator::pointer;
354 using difference_type = difference_type_t<storage_iterator>;
362 constexpr iterator_type() =
default;
363 constexpr iterator_type(iterator_type
const &) =
default;
364 constexpr iterator_type(iterator_type &&) =
default;
365 constexpr iterator_type & operator=(iterator_type
const &) =
default;
366 constexpr iterator_type & operator=(iterator_type &&) =
default;
367 ~iterator_type() =
default;
373 constexpr iterator_type(matrix_t & matrix, storage_iterator iter) :
379 template <
typename other_matrix_t>
383 constexpr iterator_type(
384 iterator_type<other_matrix_t> other) noexcept :
385 matrix_ptr{other.matrix_ptr},
386 host_iter{other.host_iter}
391 using base_t::operator+=;
394 constexpr iterator_type & operator+=(matrix_offset
const &
offset) noexcept
396 assert(matrix_ptr !=
nullptr);
398 if constexpr (order == matrix_major_order::column)
400 host_iter += (
offset.col * matrix_ptr->rows());
406 host_iter += (
offset.row * matrix_ptr->cols());
412 matrix_coordinate coordinate() const noexcept
414 assert(matrix_ptr !=
nullptr);
416 auto diff = *
this - matrix_ptr->begin();
417 if constexpr (order == matrix_major_order::column)
418 return {row_index_type{diff % matrix_ptr->rows()}, column_index_type{diff / matrix_ptr->rows()}};
420 return {row_index_type{diff / matrix_ptr->cols()}, column_index_type{diff % matrix_ptr->cols()}};
425 matrix_t * matrix_ptr{
nullptr};
426 storage_iterator host_iter{};