SeqAn3  3.0.1
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<value_type_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<value_type_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>
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 >= 0u);
194  assert(coordinate.row >= 0u);
195  assert(coordinate.col < cols());
196  assert(coordinate.row < rows());
197 
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)}});
200  }
201 
203  constexpr const_reference operator[](matrix_coordinate const & coordinate) const noexcept
204  {
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());
209 
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)}});
212  }
213 
215  constexpr reference at(matrix_coordinate const & coordinate)
216  {
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."};
221 
222  return (*this)[coordinate];
223  }
224 
226  constexpr const_reference at(matrix_coordinate const & coordinate) const
227  {
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."};
232 
233  return (*this)[coordinate];
234  }
235 
237  size_t rows() const noexcept
238  {
239  return row_dim;
240  }
241 
243  size_t cols() const noexcept
244  {
245  return col_dim;
246  }
247 
249  constexpr pointer data() noexcept
250  {
251  return storage.data();
252  }
253 
255  constexpr const_pointer data() const noexcept
256  {
257  return storage.data();
258  }
259 
264  constexpr iterator begin() noexcept
266  {
267  return {*this, storage.begin()};
268  }
270  constexpr const_iterator begin() const noexcept
271  {
272  return {*this, storage.begin()};
273  }
274 
276  constexpr const_iterator cbegin() const noexcept
277  {
278  return begin();
279  }
280 
282  constexpr iterator end() noexcept
283  {
284  return {*this, storage.end()};
285  }
286 
288  constexpr const_iterator end() const noexcept
289  {
290  return {*this, storage.end()};
291  }
292 
294  constexpr const_iterator cend() const noexcept
295  {
296  return end();
297  }
299 
300 private:
301 
302  storage_type storage;
303  size_type row_dim;
304  size_type col_dim;
305 };
306 
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>
319 {
320 private:
322  using base_t = two_dimensional_matrix_iterator_base<iterator_type<matrix_t>, order>;
323 
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;
328 
330  template <typename other_matrix_t>
332  std::is_const_v<matrix_t>
333  friend class iterator_type;
334 
336  using storage_iterator = std::ranges::iterator_t<
338  std::is_const_v<matrix_t>, storage_type const, storage_type
339  >
340  >;
341 
342 public:
343 
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>;
356  using iterator_category = std::random_access_iterator_tag;
358 
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;
368 
373  constexpr iterator_type(matrix_t & matrix, storage_iterator iter) :
374  matrix_ptr{&matrix},
375  host_iter{iter}
376  {}
377 
379  template <typename other_matrix_t>
381  requires std::same_as<other_matrix_t, std::remove_const_t<matrix_t>> && std::is_const_v<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}
387  {}
389 
390  // Import advance operator from base class.
391  using base_t::operator+=;
392 
394  constexpr iterator_type & operator+=(matrix_offset const & offset) noexcept
395  {
396  assert(matrix_ptr != nullptr);
397 
398  if constexpr (order == matrix_major_order::column)
399  {
400  host_iter += (offset.col * matrix_ptr->rows());
401  host_iter += offset.row;
402  }
403  else
404  {
405  host_iter += offset.col;
406  host_iter += (offset.row * matrix_ptr->cols());
407  }
408  return *this;
409  }
410 
412  matrix_coordinate coordinate() const noexcept
413  {
414  assert(matrix_ptr != nullptr);
415 
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()}};
419  else
420  return {row_index_type{diff / matrix_ptr->cols()}, column_index_type{diff % matrix_ptr->cols()}};
421  }
422 
423 private:
424 
425  matrix_t * matrix_ptr{nullptr};
426  storage_iterator host_iter{};
427 };
428 
429 } // namespace seqan3::detail
matrix_coordinate.hpp
Provides seqan3::detail::alignment_coordinate and associated strong types.
seqan3::field::offset
Sequence (SEQ) relative start position (0-based), unsigned value.
vector
std::random_access_iterator_tag
seqan3::views::move
const auto move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:68
template_inspection.hpp
Provides seqan3::type_list and auxiliary type traits.
move_constructible
The concept std::move_constructible is satisfied if T is a reference type, or if it is an object type...
algorithm
Adaptations of algorithms from the Ranges TS.
same_as
The concept std::same_as<T, U> is satisfied if and only if T and U denote the same type.
assignable_from
The concept std::assignable_from<LHS, RHS> specifies that an expression of the type and value categor...
std::invalid_argument
convertible_to
The concept std::convertible_to<From, To> specifies that an expression of the type and value category...
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::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)