SeqAn3  3.0.2
The Modern C++ library for sequence analysis.
two_dimensional_matrix.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2020, 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 <memory>
16 #include <vector>
17 
22 #include <seqan3/std/algorithm>
23 #include <seqan3/std/ranges>
24 
25 namespace seqan3::detail
26 {
27 
30 struct number_cols : strong_type<size_t, number_cols>
31 {
33  using strong_type<size_t, number_cols>::strong_type;
34 };
35 
38 struct number_rows : strong_type<size_t, number_rows>
39 {
41  using strong_type<size_t, number_rows>::strong_type;
42 };
43 
60 template <typename value_t,
61  typename allocator_t = std::allocator<value_t>,
62  matrix_major_order order = matrix_major_order::row>
63 class two_dimensional_matrix
64 {
65 private:
66 
70  using storage_type = std::vector<value_t, allocator_t>;
71 
73  // Forward declaration. For definition see below.
74  template <typename matrix_t>
75  class iterator_type;
76 
77 public:
78 
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>;
91 
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;
102 
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()}
109  {
110  storage.resize(row_dim.get() * col_dim.get());
111  }
112 
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()}
126  {
127  static_assert(std::move_constructible<std::ranges::range_value_t<entries_t>>, "The value type must be moveable.");
128 
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());
131  std::ranges::move(entries, storage.begin());
132  }
133 
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()}
138  {
139  assert(static_cast<size_t>(std::ranges::distance(entries)) == (row_dim.get() * col_dim.get()));
140  storage = std::move(entries);
141  }
142 
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,
173  other_allocator_t,
174  other_order> const & matrix) :
175  two_dimensional_matrix{number_rows{matrix.rows()}, number_cols{matrix.cols()}}
176  {
177  for (size_t i = 0; i < cols(); ++i)
178  {
179  for (size_t j = 0; j < rows(); ++j)
180  {
181  matrix_coordinate coord{row_index_type{j}, column_index_type{i}};
182  (*this)[coord] = matrix[coord];
183  }
184  }
185  }
187 
191  constexpr reference operator[](matrix_coordinate const & coordinate) noexcept
192  {
193  assert(coordinate.col < cols());
194  assert(coordinate.row < rows());
195 
196  return *(begin() + matrix_offset{row_index_type{static_cast<std::ptrdiff_t>(coordinate.row)},
197  column_index_type{static_cast<std::ptrdiff_t>(coordinate.col)}});
198  }
199 
201  constexpr const_reference operator[](matrix_coordinate const & coordinate) const noexcept
202  {
203  assert(coordinate.col < cols());
204  assert(coordinate.row < rows());
205 
206  return *(begin() + matrix_offset{row_index_type{static_cast<std::ptrdiff_t>(coordinate.row)},
207  column_index_type{static_cast<std::ptrdiff_t>(coordinate.col)}});
208  }
209 
211  constexpr reference at(matrix_coordinate const & coordinate)
212  {
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."};
217 
218  return (*this)[coordinate];
219  }
220 
222  constexpr const_reference at(matrix_coordinate const & coordinate) const
223  {
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."};
228 
229  return (*this)[coordinate];
230  }
231 
237  void resize(number_rows const row_dim, number_cols const col_dim)
238  {
239  this->row_dim = row_dim.get();
240  this->col_dim = col_dim.get();
241  storage.resize(this->row_dim * this->col_dim);
242  }
243 
245  size_t rows() const noexcept
246  {
247  return row_dim;
248  }
249 
251  size_t cols() const noexcept
252  {
253  return col_dim;
254  }
255 
257  constexpr pointer data() noexcept
258  {
259  return storage.data();
260  }
261 
263  constexpr const_pointer data() const noexcept
264  {
265  return storage.data();
266  }
267 
272  constexpr iterator begin() noexcept
274  {
275  return {*this, storage.begin()};
276  }
278  constexpr const_iterator begin() const noexcept
279  {
280  return {*this, storage.begin()};
281  }
282 
284  constexpr const_iterator cbegin() const noexcept
285  {
286  return begin();
287  }
288 
290  constexpr iterator end() noexcept
291  {
292  return {*this, storage.end()};
293  }
294 
296  constexpr const_iterator end() const noexcept
297  {
298  return {*this, storage.end()};
299  }
300 
302  constexpr const_iterator cend() const noexcept
303  {
304  return end();
305  }
307 
308 private:
309 
310  storage_type storage;
311  size_type row_dim;
312  size_type col_dim;
313 };
314 
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>
327 {
328 private:
330  using base_t = two_dimensional_matrix_iterator_base<iterator_type<matrix_t>, order>;
331 
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;
338 
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;
344 
346  using storage_iterator = std::ranges::iterator_t<
348  std::is_const_v<matrix_t>, storage_type const, storage_type
349  >
350  >;
351 
352 public:
353 
357  using value_type = std::iter_value_t<storage_iterator>;
360  using reference = std::iter_reference_t<storage_iterator>;
362  using pointer = typename storage_iterator::pointer;
364  using difference_type = std::iter_difference_t<storage_iterator>;
366  using iterator_category = std::random_access_iterator_tag;
368 
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;
378 
383  constexpr iterator_type(matrix_t & matrix, storage_iterator iter) :
384  matrix_ptr{&matrix},
385  host_iter{iter}
386  {}
387 
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}
397  {}
399 
400  // Import advance operator from base class.
401  using base_t::operator+=;
402 
404  constexpr iterator_type & operator+=(matrix_offset const & offset) noexcept
405  {
406  assert(matrix_ptr != nullptr);
407 
408  if constexpr (order == matrix_major_order::column)
409  {
410  host_iter += (offset.col * matrix_ptr->rows());
411  host_iter += offset.row;
412  }
413  else
414  {
415  host_iter += offset.col;
416  host_iter += (offset.row * matrix_ptr->cols());
417  }
418  return *this;
419  }
420 
422  matrix_coordinate coordinate() const noexcept
423  {
424  assert(matrix_ptr != nullptr);
425 
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()}};
429  else
430  return {row_index_type{diff / matrix_ptr->cols()}, column_index_type{diff % matrix_ptr->cols()}};
431  }
432 
433 private:
434 
435  matrix_t * matrix_ptr{nullptr};
436  storage_iterator host_iter{};
437 };
438 
439 } // namespace seqan3::detail
matrix_coordinate.hpp
Provides seqan3::detail::alignment_coordinate and associated strong types.
vector
std::random_access_iterator_tag
template_inspection.hpp
Provides seqan3::type_list and auxiliary type traits.
algorithm
Adaptations of algorithms from the Ranges TS.
seqan3::views::move
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:68
std::iter_value_t
std::invalid_argument
memory
two_dimensional_matrix_iterator_base.hpp
Provides seqan3::detail::two_dimensional_matrix_iterator_base.
ranges
Adaptations of concepts from the Ranges TS.
std::begin
T begin(T... args)
std::ptrdiff_t
std::allocator
std::end
T end(T... args)
std::conditional_t
seqan3::pack_traits::at
typename decltype(detail::at< idx, pack_t... >())::type at
Return the type at given index from the type pack.
Definition: traits.hpp:221
deferred_crtp_base.hpp
Provides seqan3::detail::deferred_crtp_base.
std::data
T data(T... args)