SeqAn3 3.2.0
The Modern C++ library for sequence analysis.
two_dimensional_matrix.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
3// Copyright (c) 2016-2022, Knut Reinert & MPI für molekulare Genetik
4// This file may be used, modified and/or redistributed under the terms of the 3-clause BSD-License
5// shipped with this file and also available at: https://github.com/seqan/seqan3/blob/master/LICENSE.md
6// -----------------------------------------------------------------------------------------------------
7
13#pragma once
14
15#include <algorithm>
16#include <memory>
17#include <ranges>
18#include <vector>
19
25
26namespace seqan3::detail
27{
28
31struct number_cols : strong_type<size_t, number_cols>
32{
34 using strong_type<size_t, number_cols>::strong_type;
35};
36
39struct number_rows : strong_type<size_t, number_rows>
40{
42 using strong_type<size_t, number_rows>::strong_type;
43};
44
61template <typename value_t,
62 typename allocator_t = std::allocator<value_t>,
63 matrix_major_order order = matrix_major_order::row>
64class two_dimensional_matrix
65{
66private:
70 using storage_type = std::vector<value_t, allocator_t>;
72
73 // Forward declaration. For definition see below.
74 template <bool const_range>
75 class basic_iterator;
76
77public:
81 using value_type = typename storage_type::value_type;
82 using reference = typename storage_type::reference;
83 using const_reference = typename storage_type::const_reference;
84 using pointer = typename storage_type::pointer;
85 using const_pointer = typename storage_type::const_pointer;
86 using difference_type = typename storage_type::difference_type;
87 using size_type = typename storage_type::size_type;
88 using iterator = basic_iterator<false>;
89 using const_iterator = basic_iterator<true>;
91
95 two_dimensional_matrix() = default;
96 two_dimensional_matrix(two_dimensional_matrix const &) = default;
97 two_dimensional_matrix(two_dimensional_matrix &&) = default;
98 two_dimensional_matrix & operator=(two_dimensional_matrix const &) = default;
99 two_dimensional_matrix & operator=(two_dimensional_matrix &&) = default;
100 ~two_dimensional_matrix() = default;
101
106 two_dimensional_matrix(number_rows const row_dim, number_cols const col_dim) :
107 row_dim{row_dim.get()},
108 col_dim{col_dim.get()}
109 {
110 storage.resize(row_dim.get() * col_dim.get());
111 }
112
119 template <std::ranges::forward_range entries_t>
120 requires (std::convertible_to<std::ranges::range_value_t<entries_t>, value_type>)
121 two_dimensional_matrix(number_rows const row_dim, number_cols const col_dim, entries_t entries) :
122 row_dim{row_dim.get()},
123 col_dim{col_dim.get()}
124 {
125 static_assert(std::move_constructible<std::ranges::range_value_t<entries_t>>,
126 "The value type must be moveable.");
127
128 assert(static_cast<size_t>(std::ranges::distance(entries)) == (row_dim.get() * col_dim.get()));
129 storage.resize(row_dim.get() * col_dim.get());
130 std::ranges::move(entries, storage.begin());
131 }
132
134 two_dimensional_matrix(number_rows const row_dim, number_cols const col_dim, storage_type entries) :
135 row_dim{row_dim.get()},
136 col_dim{col_dim.get()}
137 {
138 assert(static_cast<size_t>(std::ranges::distance(entries)) == (row_dim.get() * col_dim.get()));
139 storage = std::move(entries);
140 }
141
167 template <typename other_value_t, typename other_allocator_t, matrix_major_order other_order>
168 requires std::assignable_from<other_value_t &, value_t &>
169 explicit constexpr two_dimensional_matrix(
170 two_dimensional_matrix<other_value_t, other_allocator_t, other_order> const & matrix) :
171 two_dimensional_matrix{number_rows{matrix.rows()}, number_cols{matrix.cols()}}
172 {
173 for (size_t i = 0; i < cols(); ++i)
174 {
175 for (size_t j = 0; j < rows(); ++j)
176 {
177 matrix_coordinate coord{row_index_type{j}, column_index_type{i}};
178 (*this)[coord] = matrix[coord];
179 }
180 }
181 }
183
187 constexpr reference operator[](matrix_coordinate const & coordinate) noexcept
188 {
189 assert(coordinate.col < cols());
190 assert(coordinate.row < rows());
191
192 return *(begin()
193 + matrix_offset{row_index_type{static_cast<std::ptrdiff_t>(coordinate.row)},
194 column_index_type{static_cast<std::ptrdiff_t>(coordinate.col)}});
195 }
196
198 constexpr const_reference operator[](matrix_coordinate const & coordinate) const noexcept
199 {
200 assert(coordinate.col < cols());
201 assert(coordinate.row < rows());
202
203 return *(begin()
204 + matrix_offset{row_index_type{static_cast<std::ptrdiff_t>(coordinate.row)},
205 column_index_type{static_cast<std::ptrdiff_t>(coordinate.col)}});
206 }
207
209 constexpr reference at(matrix_coordinate const & coordinate)
210 {
211 if (coordinate.col >= cols())
212 throw std::invalid_argument{"Column index is out of range. Please check the dimensions of the matrix."};
213 if (coordinate.row >= rows())
214 throw std::invalid_argument{"Row index is out of range. Please check the dimensions of the matrix."};
215
216 return (*this)[coordinate];
217 }
218
220 constexpr const_reference at(matrix_coordinate const & coordinate) const
221 {
222 if (coordinate.col >= cols())
223 throw std::invalid_argument{"Column index is out of range. Please check the dimensions of the matrix."};
224 if (coordinate.row >= rows())
225 throw std::invalid_argument{"Row index is out of range. Please check the dimensions of the matrix."};
226
227 return (*this)[coordinate];
228 }
229
235 void resize(number_rows const row_dim, number_cols const col_dim)
236 {
237 this->row_dim = row_dim.get();
238 this->col_dim = col_dim.get();
239 storage.resize(this->row_dim * this->col_dim);
240 }
241
243 size_t rows() const noexcept
244 {
245 return row_dim;
246 }
247
249 size_t cols() const noexcept
250 {
251 return col_dim;
252 }
253
255 constexpr pointer data() noexcept
256 {
257 return storage.data();
258 }
259
261 constexpr const_pointer data() const noexcept
262 {
263 return storage.data();
264 }
265
271 constexpr iterator begin() noexcept
272 {
273 return {*this, storage.begin()};
274 }
276 constexpr const_iterator begin() const noexcept
277 {
278 return {*this, storage.begin()};
279 }
280
282 constexpr const_iterator cbegin() const noexcept
283 {
284 return begin();
285 }
286
288 constexpr iterator end() noexcept
289 {
290 return {*this, storage.end()};
291 }
292
294 constexpr const_iterator end() const noexcept
295 {
296 return {*this, storage.end()};
297 }
298
300 constexpr const_iterator cend() const noexcept
301 {
302 return end();
303 }
305
306private:
307 storage_type storage;
308 size_type row_dim;
309 size_type col_dim;
310};
311
320template <typename value_t, typename allocator_t, matrix_major_order order>
321template <bool const_range>
322class two_dimensional_matrix<value_t, allocator_t, order>::basic_iterator :
323 public two_dimensional_matrix_iterator_base<basic_iterator<const_range>, order>
324{
325private:
327 using parent_t = detail::maybe_const_range_t<const_range, two_dimensional_matrix>;
328
330 using base_t = two_dimensional_matrix_iterator_base<basic_iterator, order>;
331
333 template <typename derived_t, matrix_major_order other_order>
334 requires is_value_specialisation_of_v<derived_t, basic_iterator> && (other_order == order)
335 friend class two_dimensional_matrix_iterator_base;
336
338 template <bool other_const_range>
339 friend class basic_iterator;
340
342 using storage_iterator = detail::maybe_const_iterator_t<const_range, storage_type>;
343
344public:
349 using value_type = std::iter_value_t<storage_iterator>;
353 using pointer = typename storage_iterator::pointer;
355 using difference_type = std::iter_difference_t<storage_iterator>;
357 using iterator_category = std::random_access_iterator_tag;
359
363 constexpr basic_iterator() = default;
364 constexpr basic_iterator(basic_iterator const &) = default;
365 constexpr basic_iterator(basic_iterator &&) = default;
366 constexpr basic_iterator & operator=(basic_iterator const &) = default;
367 constexpr basic_iterator & operator=(basic_iterator &&) = default;
368 ~basic_iterator() = default;
369
374 constexpr basic_iterator(parent_t & matrix, storage_iterator iter) : matrix_ptr{&matrix}, host_iter{iter}
375 {}
376
378 constexpr basic_iterator(basic_iterator<!const_range> const & other) noexcept
379 requires const_range
380 : matrix_ptr{other.matrix_ptr}, host_iter{other.host_iter}
381 {}
383
384 // Import advance operator from base class.
385 using base_t::operator+=;
386
388 constexpr basic_iterator & operator+=(matrix_offset const & offset) noexcept
389 {
390 assert(matrix_ptr != nullptr);
391
392 if constexpr (order == matrix_major_order::column)
393 {
394 host_iter += (offset.col * matrix_ptr->rows());
395 host_iter += offset.row;
396 }
397 else
398 {
399 host_iter += offset.col;
400 host_iter += (offset.row * matrix_ptr->cols());
401 }
402 return *this;
403 }
404
406 matrix_coordinate coordinate() const noexcept
407 {
408 assert(matrix_ptr != nullptr);
409
410 auto diff = *this - matrix_ptr->begin();
411 if constexpr (order == matrix_major_order::column)
412 return {row_index_type{diff % matrix_ptr->rows()}, column_index_type{diff / matrix_ptr->rows()}};
413 else
414 return {row_index_type{diff / matrix_ptr->cols()}, column_index_type{diff % matrix_ptr->cols()}};
415 }
416
417private:
418 parent_t * matrix_ptr{nullptr};
419 storage_iterator host_iter{};
420};
421
422} // namespace seqan3::detail
T begin(T... args)
Provides various transformation traits used by the range module.
T data(T... args)
Provides seqan3::detail::deferred_crtp_base.
T end(T... args)
@ offset
Sequence (seqan3::field::seq) relative start position (0-based), unsigned value.
typename decltype(detail::at< idx >(list_t{}))::type at
Return the type at given index from the type list.
Definition: traits.hpp:279
Provides seqan3::detail::matrix_index, seqan3::detail::matrix_coordinate and associated strong types.
T move(T... args)
constexpr auto const & get(configuration< configs_t... > const &config) noexcept
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: configuration.hpp:415
Provides type traits for working with templates.
Provides seqan3::detail::two_dimensional_matrix_iterator_base.