Loading...
Searching...
No Matches
two_dimensional_matrix.hpp
Go to the documentation of this file.
// SPDX-FileCopyrightText: 2006-2025 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2025 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: BSD-3-Clause
#pragma once
#include <algorithm>
#include <memory>
#include <ranges>
#include <vector>
#include <seqan3/alignment/matrix/detail/matrix_coordinate.hpp>
#include <seqan3/alignment/matrix/detail/two_dimensional_matrix_iterator_base.hpp>
#include <seqan3/core/detail/deferred_crtp_base.hpp>
#include <seqan3/core/detail/template_inspection.hpp>
#include <seqan3/core/range/type_traits.hpp>
namespace seqan3::detail
{
struct number_cols : strong_type<size_t, number_cols>
{
using strong_type<size_t, number_cols>::strong_type;
};
struct number_rows : strong_type<size_t, number_rows>
{
using strong_type<size_t, number_rows>::strong_type;
};
template <typename value_t,
typename allocator_t = std::allocator<value_t>,
matrix_major_order order = matrix_major_order::row>
class two_dimensional_matrix
{
private:
using storage_type = std::vector<value_t, allocator_t>;
// Forward declaration. For definition see below.
template <bool const_range>
class basic_iterator;
public:
// Doxygen: https://github.com/seqan/product_backlog/issues/424
using value_type = typename storage_type::value_type;
using reference = typename storage_type::reference;
using const_reference = typename storage_type::const_reference;
using pointer = typename storage_type::pointer;
using const_pointer = typename storage_type::const_pointer;
using difference_type = typename storage_type::difference_type;
using size_type = typename storage_type::size_type;
using iterator = basic_iterator<false>;
using const_iterator = basic_iterator<true>;
two_dimensional_matrix() = default;
two_dimensional_matrix(two_dimensional_matrix const &) = default;
two_dimensional_matrix(two_dimensional_matrix &&) = default;
two_dimensional_matrix & operator=(two_dimensional_matrix const &) = default;
two_dimensional_matrix & operator=(two_dimensional_matrix &&) = default;
~two_dimensional_matrix() = default;
two_dimensional_matrix(number_rows const row_dim, number_cols const col_dim) :
row_dim{row_dim.get()},
col_dim{col_dim.get()}
{
storage.resize(row_dim.get() * col_dim.get());
}
template <std::ranges::forward_range entries_t>
requires (std::convertible_to<std::ranges::range_value_t<entries_t>, value_type>)
two_dimensional_matrix(number_rows const row_dim, number_cols const col_dim, entries_t entries) :
row_dim{row_dim.get()},
col_dim{col_dim.get()}
{
static_assert(std::move_constructible<std::ranges::range_value_t<entries_t>>,
"The value type must be moveable.");
assert(static_cast<size_t>(std::ranges::distance(entries)) == (row_dim.get() * col_dim.get()));
storage.resize(row_dim.get() * col_dim.get());
std::ranges::move(entries, storage.begin());
}
two_dimensional_matrix(number_rows const row_dim, number_cols const col_dim, storage_type entries) :
row_dim{row_dim.get()},
col_dim{col_dim.get()}
{
assert(static_cast<size_t>(std::ranges::distance(entries)) == (row_dim.get() * col_dim.get()));
storage = std::move(entries);
}
template <typename other_value_t, typename other_allocator_t, matrix_major_order other_order>
requires std::assignable_from<other_value_t &, value_t &>
explicit constexpr two_dimensional_matrix(
two_dimensional_matrix<other_value_t, other_allocator_t, other_order> const & matrix) :
two_dimensional_matrix{number_rows{matrix.rows()}, number_cols{matrix.cols()}}
{
for (size_t i = 0; i < cols(); ++i)
{
for (size_t j = 0; j < rows(); ++j)
{
matrix_coordinate coord{row_index_type{j}, column_index_type{i}};
(*this)[coord] = matrix[coord];
}
}
}
constexpr reference operator[](matrix_coordinate const & coordinate) noexcept
{
assert(coordinate.col < cols());
assert(coordinate.row < rows());
return *(begin()
+ matrix_offset{row_index_type{static_cast<std::ptrdiff_t>(coordinate.row)},
column_index_type{static_cast<std::ptrdiff_t>(coordinate.col)}});
}
constexpr const_reference operator[](matrix_coordinate const & coordinate) const noexcept
{
assert(coordinate.col < cols());
assert(coordinate.row < rows());
return *(begin()
+ matrix_offset{row_index_type{static_cast<std::ptrdiff_t>(coordinate.row)},
column_index_type{static_cast<std::ptrdiff_t>(coordinate.col)}});
}
constexpr reference at(matrix_coordinate const & coordinate)
{
if (coordinate.col >= cols())
throw std::invalid_argument{"Column index is out of range. Please check the dimensions of the matrix."};
if (coordinate.row >= rows())
throw std::invalid_argument{"Row index is out of range. Please check the dimensions of the matrix."};
return (*this)[coordinate];
}
constexpr const_reference at(matrix_coordinate const & coordinate) const
{
if (coordinate.col >= cols())
throw std::invalid_argument{"Column index is out of range. Please check the dimensions of the matrix."};
if (coordinate.row >= rows())
throw std::invalid_argument{"Row index is out of range. Please check the dimensions of the matrix."};
return (*this)[coordinate];
}
void resize(number_rows const row_dim, number_cols const col_dim)
{
this->row_dim = row_dim.get();
this->col_dim = col_dim.get();
storage.resize(this->row_dim * this->col_dim);
}
size_t rows() const noexcept
{
return row_dim;
}
size_t cols() const noexcept
{
return col_dim;
}
constexpr pointer data() noexcept
{
return storage.data();
}
constexpr const_pointer data() const noexcept
{
return storage.data();
}
constexpr iterator begin() noexcept
{
return {*this, storage.begin()};
}
constexpr const_iterator begin() const noexcept
{
return {*this, storage.begin()};
}
constexpr const_iterator cbegin() const noexcept
{
return begin();
}
constexpr iterator end() noexcept
{
return {*this, storage.end()};
}
constexpr const_iterator end() const noexcept
{
return {*this, storage.end()};
}
constexpr const_iterator cend() const noexcept
{
return end();
}
private:
storage_type storage;
size_type row_dim;
size_type col_dim;
};
template <typename value_t, typename allocator_t, matrix_major_order order>
template <bool const_range>
class two_dimensional_matrix<value_t, allocator_t, order>::basic_iterator :
public two_dimensional_matrix_iterator_base<basic_iterator<const_range>, order>
{
private:
using parent_t = detail::maybe_const_range_t<const_range, two_dimensional_matrix>;
using base_t = two_dimensional_matrix_iterator_base<basic_iterator, order>;
template <typename derived_t, matrix_major_order other_order>
friend class two_dimensional_matrix_iterator_base;
template <bool other_const_range>
friend class basic_iterator;
using storage_iterator = detail::maybe_const_iterator_t<const_range, storage_type>;
public:
using value_type = std::iter_value_t<storage_iterator>;
using reference = std::iter_reference_t<storage_iterator>;
using pointer = typename storage_iterator::pointer;
using difference_type = std::iter_difference_t<storage_iterator>;
using iterator_category = std::random_access_iterator_tag;
constexpr basic_iterator() = default;
constexpr basic_iterator(basic_iterator const &) = default;
constexpr basic_iterator(basic_iterator &&) = default;
constexpr basic_iterator & operator=(basic_iterator const &) = default;
constexpr basic_iterator & operator=(basic_iterator &&) = default;
~basic_iterator() = default;
constexpr basic_iterator(parent_t & matrix, storage_iterator iter) : matrix_ptr{&matrix}, host_iter{iter}
{}
constexpr basic_iterator(basic_iterator<!const_range> const & other) noexcept
requires const_range
: matrix_ptr{other.matrix_ptr}, host_iter{other.host_iter}
{}
// Import advance operator from base class.
using base_t::operator+=;
constexpr basic_iterator & operator+=(matrix_offset const & offset) noexcept
{
assert(matrix_ptr != nullptr);
if constexpr (order == matrix_major_order::column)
{
host_iter += (offset.col * matrix_ptr->rows());
host_iter += offset.row;
}
else
{
host_iter += offset.col;
host_iter += (offset.row * matrix_ptr->cols());
}
return *this;
}
matrix_coordinate coordinate() const noexcept
{
assert(matrix_ptr != nullptr);
auto diff = *this - matrix_ptr->begin();
if constexpr (order == matrix_major_order::column)
return {row_index_type{diff % matrix_ptr->rows()}, column_index_type{diff / matrix_ptr->rows()}};
else
return {row_index_type{diff / matrix_ptr->cols()}, column_index_type{diff % matrix_ptr->cols()}};
}
private:
parent_t * matrix_ptr{nullptr};
storage_iterator host_iter{};
};
} // namespace seqan3::detail
algorithm
type_traits.hpp
Provides various transformation traits used by the range module.
deferred_crtp_base.hpp
Provides seqan3::detail::deferred_crtp_base.
seqan3::field::offset
@ offset
Sequence (seqan3::field::seq) relative start position (0-based), unsigned value.
Definition record.hpp:66
matrix_coordinate.hpp
Provides seqan3::detail::matrix_index, seqan3::detail::matrix_coordinate and associated strong types.
memory
seqan3::get
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:412
template_inspection.hpp
Provides type traits for working with templates.
two_dimensional_matrix_iterator_base.hpp
Provides seqan3::detail::two_dimensional_matrix_iterator_base.
vector
Hide me