SeqAn3  3.2.0-rc.1
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 
26 namespace seqan3::detail
27 {
28 
31 struct number_cols : strong_type<size_t, number_cols>
32 {
34  using strong_type<size_t, number_cols>::strong_type;
35 };
36 
39 struct number_rows : strong_type<size_t, number_rows>
40 {
42  using strong_type<size_t, number_rows>::strong_type;
43 };
44 
61 template <typename value_t,
62  typename allocator_t = std::allocator<value_t>,
63  matrix_major_order order = matrix_major_order::row>
64 class two_dimensional_matrix
65 {
66 private:
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 
77 public:
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 
306 private:
307  storage_type storage;
308  size_type row_dim;
309  size_type col_dim;
310 };
311 
320 template <typename value_t, typename allocator_t, matrix_major_order order>
321 template <bool const_range>
322 class two_dimensional_matrix<value_t, allocator_t, order>::basic_iterator :
323  public two_dimensional_matrix_iterator_base<basic_iterator<const_range>, order>
324 {
325 private:
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 
344 public:
349  using value_type = std::iter_value_t<storage_iterator>;
351  using reference = std::iter_reference_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 
417 private:
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)
requires requires
The rank_type of the semi-alphabet; defined as the return type of seqan3::to_rank....
Definition: alphabet/concept.hpp:164
@ offset
Sequence (seqan3::field::seq) relative start position (0-based), unsigned value.
Provides seqan3::detail::matrix_index, seqan3::detail::matrix_coordinate and associated strong types.
matrix_index< size_t > matrix_coordinate
A coordinate type to access an element inside of a two-dimensional matrix.
Definition: matrix_coordinate.hpp:178
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
The <ranges> header from C++20's standard library.
Provides type traits for working with templates.
Provides seqan3::detail::two_dimensional_matrix_iterator_base.