SeqAn3 3.1.0
The Modern C++ library for sequence analysis.
two_dimensional_matrix.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2006-2021, Knut Reinert & Freie Universität Berlin
3// Copyright (c) 2016-2021, 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 <seqan3/std/algorithm>
16#include <memory>
17#include <seqan3/std/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:
67
71 using storage_type = std::vector<value_t, allocator_t>;
73
74 // Forward declaration. For definition see below.
75 template <bool const_range>
76 class basic_iterator;
77
78public:
79
83 using value_type = typename storage_type::value_type;
84 using reference = typename storage_type::reference;
85 using const_reference = typename storage_type::const_reference;
86 using pointer = typename storage_type::pointer;
87 using const_pointer = typename storage_type::const_pointer;
88 using difference_type = typename storage_type::difference_type;
89 using size_type = typename storage_type::size_type;
90 using iterator = basic_iterator<false>;
91 using const_iterator = basic_iterator<true>;
93
97 two_dimensional_matrix() = default;
98 two_dimensional_matrix(two_dimensional_matrix const &) = default;
99 two_dimensional_matrix(two_dimensional_matrix &&) = default;
100 two_dimensional_matrix & operator=(two_dimensional_matrix const &) = default;
101 two_dimensional_matrix & operator=(two_dimensional_matrix &&) = default;
102 ~two_dimensional_matrix() = default;
103
108 two_dimensional_matrix(number_rows const row_dim, number_cols const col_dim) :
109 row_dim{row_dim.get()}, col_dim{col_dim.get()}
110 {
111 storage.resize(row_dim.get() * col_dim.get());
112 }
113
120 template <std::ranges::forward_range entries_t>
122 requires (std::convertible_to<std::ranges::range_value_t<entries_t>, value_type>)
124 two_dimensional_matrix(number_rows const row_dim, number_cols const col_dim, entries_t entries) :
125 row_dim{row_dim.get()},
126 col_dim{col_dim.get()}
127 {
128 static_assert(std::move_constructible<std::ranges::range_value_t<entries_t>>, "The value type must be moveable.");
129
130 assert(static_cast<size_t>(std::ranges::distance(entries)) == (row_dim.get() * col_dim.get()));
131 storage.resize(row_dim.get() * col_dim.get());
132 std::ranges::move(entries, storage.begin());
133 }
134
136 two_dimensional_matrix(number_rows const row_dim, number_cols const col_dim, storage_type entries) :
137 row_dim{row_dim.get()},
138 col_dim{col_dim.get()}
139 {
140 assert(static_cast<size_t>(std::ranges::distance(entries)) == (row_dim.get() * col_dim.get()));
141 storage = std::move(entries);
142 }
143
169 template <typename other_value_t, typename other_allocator_t, matrix_major_order other_order>
171 requires std::assignable_from<other_value_t &, value_t &>
173 explicit constexpr two_dimensional_matrix(two_dimensional_matrix<other_value_t,
174 other_allocator_t,
175 other_order> const & matrix) :
176 two_dimensional_matrix{number_rows{matrix.rows()}, number_cols{matrix.cols()}}
177 {
178 for (size_t i = 0; i < cols(); ++i)
179 {
180 for (size_t j = 0; j < rows(); ++j)
181 {
182 matrix_coordinate coord{row_index_type{j}, column_index_type{i}};
183 (*this)[coord] = matrix[coord];
184 }
185 }
186 }
188
192 constexpr reference operator[](matrix_coordinate const & coordinate) noexcept
193 {
194 assert(coordinate.col < cols());
195 assert(coordinate.row < rows());
196
197 return *(begin() + matrix_offset{row_index_type{static_cast<std::ptrdiff_t>(coordinate.row)},
198 column_index_type{static_cast<std::ptrdiff_t>(coordinate.col)}});
199 }
200
202 constexpr const_reference operator[](matrix_coordinate const & coordinate) const noexcept
203 {
204 assert(coordinate.col < cols());
205 assert(coordinate.row < rows());
206
207 return *(begin() + matrix_offset{row_index_type{static_cast<std::ptrdiff_t>(coordinate.row)},
208 column_index_type{static_cast<std::ptrdiff_t>(coordinate.col)}});
209 }
210
212 constexpr reference at(matrix_coordinate const & coordinate)
213 {
214 if (coordinate.col >= cols())
215 throw std::invalid_argument{"Column index is out of range. Please check the dimensions of the matrix."};
216 if (coordinate.row >= rows())
217 throw std::invalid_argument{"Row index is out of range. Please check the dimensions of the matrix."};
218
219 return (*this)[coordinate];
220 }
221
223 constexpr const_reference at(matrix_coordinate const & coordinate) const
224 {
225 if (coordinate.col >= cols())
226 throw std::invalid_argument{"Column index is out of range. Please check the dimensions of the matrix."};
227 if (coordinate.row >= rows())
228 throw std::invalid_argument{"Row index is out of range. Please check the dimensions of the matrix."};
229
230 return (*this)[coordinate];
231 }
232
238 void resize(number_rows const row_dim, number_cols const col_dim)
239 {
240 this->row_dim = row_dim.get();
241 this->col_dim = col_dim.get();
242 storage.resize(this->row_dim * this->col_dim);
243 }
244
246 size_t rows() const noexcept
247 {
248 return row_dim;
249 }
250
252 size_t cols() const noexcept
253 {
254 return col_dim;
255 }
256
258 constexpr pointer data() noexcept
259 {
260 return storage.data();
261 }
262
264 constexpr const_pointer data() const noexcept
265 {
266 return storage.data();
267 }
268
274 constexpr iterator begin() noexcept
275 {
276 return {*this, storage.begin()};
277 }
279 constexpr const_iterator begin() const noexcept
280 {
281 return {*this, storage.begin()};
282 }
283
285 constexpr const_iterator cbegin() const noexcept
286 {
287 return begin();
288 }
289
291 constexpr iterator end() noexcept
292 {
293 return {*this, storage.end()};
294 }
295
297 constexpr const_iterator end() const noexcept
298 {
299 return {*this, storage.end()};
300 }
301
303 constexpr const_iterator cend() const noexcept
304 {
305 return end();
306 }
308
309private:
310
311 storage_type storage;
312 size_type row_dim;
313 size_type col_dim;
314};
315
324template <typename value_t, typename allocator_t, matrix_major_order order>
325template <bool const_range>
326class two_dimensional_matrix<value_t, allocator_t, order>::basic_iterator :
327 public two_dimensional_matrix_iterator_base<basic_iterator<const_range>, order>
328{
329private:
331 using parent_t = detail::maybe_const_range_t<const_range, two_dimensional_matrix>;
332
334 using base_t = two_dimensional_matrix_iterator_base<basic_iterator, order>;
335
337 template <typename derived_t, matrix_major_order other_order>
339 requires is_type_specialisation_of_v<derived_t, basic_iterator> && (other_order == order)
341 friend class two_dimensional_matrix_iterator_base;
342
344 template <bool other_const_range>
345 friend class basic_iterator;
346
348 using storage_iterator = detail::maybe_const_iterator_t<const_range, storage_type>;
349
350public:
351
356 using value_type = std::iter_value_t<storage_iterator>;
360 using pointer = typename storage_iterator::pointer;
362 using difference_type = std::iter_difference_t<storage_iterator>;
364 using iterator_category = std::random_access_iterator_tag;
366
370 constexpr basic_iterator() = default;
371 constexpr basic_iterator(basic_iterator const &) = default;
372 constexpr basic_iterator(basic_iterator &&) = default;
373 constexpr basic_iterator & operator=(basic_iterator const &) = default;
374 constexpr basic_iterator & operator=(basic_iterator &&) = default;
375 ~basic_iterator() = default;
376
381 constexpr basic_iterator(parent_t & matrix, storage_iterator iter) :
382 matrix_ptr{&matrix},
383 host_iter{iter}
384 {}
385
387 constexpr basic_iterator(basic_iterator<!const_range> const & other) noexcept
389 requires const_range
391 : matrix_ptr{other.matrix_ptr},
392 host_iter{other.host_iter}
393 {}
395
396 // Import advance operator from base class.
397 using base_t::operator+=;
398
400 constexpr basic_iterator & operator+=(matrix_offset const & offset) noexcept
401 {
402 assert(matrix_ptr != nullptr);
403
404 if constexpr (order == matrix_major_order::column)
405 {
406 host_iter += (offset.col * matrix_ptr->rows());
407 host_iter += offset.row;
408 }
409 else
410 {
411 host_iter += offset.col;
412 host_iter += (offset.row * matrix_ptr->cols());
413 }
414 return *this;
415 }
416
418 matrix_coordinate coordinate() const noexcept
419 {
420 assert(matrix_ptr != nullptr);
421
422 auto diff = *this - matrix_ptr->begin();
423 if constexpr (order == matrix_major_order::column)
424 return {row_index_type{diff % matrix_ptr->rows()}, column_index_type{diff / matrix_ptr->rows()}};
425 else
426 return {row_index_type{diff / matrix_ptr->cols()}, column_index_type{diff % matrix_ptr->cols()}};
427 }
428
429private:
430
431 parent_t * matrix_ptr{nullptr};
432 storage_iterator host_iter{};
433};
434
435} // namespace seqan3::detail
The <algorithm> header from C++20's standard library.
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:260
Provides seqan3::detail::matrix_index, seqan3::detail::matrix_coordinate and associated strong types.
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:429
The <ranges> header from C++20's standard library.
Provides type traits for working with templates.
Provides seqan3::detail::two_dimensional_matrix_iterator_base.