Loading...
Searching...
No Matches
enforce_random_access.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 <iterator>
#include <ranges>
#include <type_traits>
#include <seqan3/core/range/detail/adaptor_base.hpp>
#include <seqan3/core/range/detail/inherited_iterator_base.hpp>
#include <seqan3/utility/range/concept.hpp>
namespace seqan3::detail
{
// ============================================================================
// view_pseudo_random_access
// ============================================================================
template <std::ranges::view urng_t>
requires pseudo_random_access_range<urng_t>
class view_enforce_random_access : public std::ranges::view_interface<view_enforce_random_access<urng_t>>
{
private:
// Iterator declaration.
template <typename underlying_iter_t>
class basic_iterator;
public:
constexpr view_enforce_random_access() = default;
constexpr view_enforce_random_access(view_enforce_random_access const &) = default;
constexpr view_enforce_random_access(view_enforce_random_access &&) = default;
constexpr view_enforce_random_access & operator=(view_enforce_random_access const &) = default;
constexpr view_enforce_random_access & operator=(view_enforce_random_access &&) = default;
~view_enforce_random_access() = default;
explicit constexpr view_enforce_random_access(urng_t && range) : urng{std::move(range)}
{}
template <typename viewable_rng_t>
requires (!std::same_as<std::remove_cvref_t<viewable_rng_t>, view_enforce_random_access>)
&& std::ranges::viewable_range<viewable_rng_t>
&& std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<viewable_rng_t>>>
explicit constexpr view_enforce_random_access(viewable_rng_t && range) :
view_enforce_random_access{std::views::all(std::forward<viewable_rng_t>(range))}
{}
constexpr auto begin() noexcept
{
return basic_iterator<decltype(std::ranges::begin(urng))>{std::ranges::begin(urng)};
}
constexpr auto begin() const noexcept
requires const_iterable_range<urng_t>
{
return basic_iterator<decltype(std::ranges::begin(urng))>{std::ranges::begin(urng)};
}
constexpr auto end() noexcept
{
if constexpr (std::ranges::common_range<urng_t>)
return basic_iterator<decltype(std::ranges::end(urng))>{std::ranges::end(urng)};
else
return urng.end();
}
constexpr auto end() const noexcept
requires const_iterable_range<urng_t>
{
if constexpr (std::ranges::common_range<urng_t>)
return basic_iterator<decltype(std::ranges::end(urng))>{std::ranges::end(urng)};
else
return std::ranges::cend(urng);
}
urng_t urng;
};
template <std::ranges::view urng_t>
requires pseudo_random_access_range<urng_t>
template <typename underlying_iter_t>
class view_enforce_random_access<urng_t>::basic_iterator :
public inherited_iterator_base<basic_iterator<underlying_iter_t>, underlying_iter_t>
{
private:
using base_t = inherited_iterator_base<basic_iterator<underlying_iter_t>, underlying_iter_t>;
public:
using iterator_category = std::random_access_iterator_tag;
using iterator_concept = iterator_category;
// Importing base's constructors.
using base_t::base_t;
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;
// Importing base's equality operators
using base_t::operator==;
using base_t::operator!=;
friend constexpr bool operator==(basic_iterator const & lhs, std::ranges::sentinel_t<urng_t> const & rhs)
noexcept(noexcept(std::declval<underlying_iter_t const &>()
== std::declval<std::ranges::sentinel_t<urng_t> const &>()))
{
return lhs.base() == rhs;
}
friend constexpr bool operator==(std::ranges::sentinel_t<urng_t> const & lhs, basic_iterator const & rhs)
noexcept(noexcept(std::declval<underlying_iter_t const &>()
== std::declval<std::ranges::sentinel_t<urng_t> const &>()))
{
return rhs == lhs;
}
friend constexpr bool operator!=(basic_iterator const & lhs, std::ranges::sentinel_t<urng_t> const & rhs)
noexcept(noexcept(std::declval<underlying_iter_t const &>()
!= std::declval<std::ranges::sentinel_t<urng_t> const &>()))
{
return !(lhs == rhs);
}
friend constexpr bool operator!=(std::ranges::sentinel_t<urng_t> const & lhs, basic_iterator const & rhs)
noexcept(noexcept(std::declval<underlying_iter_t const &>()
!= std::declval<std::ranges::sentinel_t<urng_t> const &>()))
{
return rhs != lhs;
}
// Import operator from base.
using base_t::operator-;
constexpr typename base_t::difference_type operator-(std::ranges::sentinel_t<urng_t> const & rhs) const
noexcept(noexcept(std::declval<underlying_iter_t const &>()
- std::declval<std::ranges::sentinel_t<urng_t> const &>()))
requires std::sized_sentinel_for<std::ranges::sentinel_t<urng_t>, underlying_iter_t>
{
return this->base() - rhs;
}
constexpr friend typename base_t::difference_type operator-(std::ranges::sentinel_t<urng_t> const & lhs,
basic_iterator const & rhs)
noexcept(noexcept(std::declval<std::ranges::sentinel_t<urng_t> const &>()
- std::declval<underlying_iter_t const &>()))
requires std::sized_sentinel_for<std::ranges::sentinel_t<urng_t>, underlying_iter_t>
{
return lhs - rhs.base();
}
};
template <std::ranges::viewable_range rng_t>
view_enforce_random_access(rng_t &&) -> view_enforce_random_access<std::views::all_t<rng_t>>;
// ============================================================================
// pseudo_random_access_fn (adaptor definition)
// ============================================================================
struct pseudo_random_access_fn : public adaptor_base<pseudo_random_access_fn>
{
private:
using base_t = adaptor_base<pseudo_random_access_fn>;
public:
using base_t::base_t;
private:
friend base_t;
template <std::ranges::viewable_range urng_t>
static constexpr auto impl(urng_t && urange)
{
static_assert(std::ranges::random_access_range<urng_t> || pseudo_random_access_range<urng_t>,
"The adapted range must either model std::ranges::random_access_range or must be "
"a specific SeqAn range type that supports pseudo random access.");
static_assert(std::ranges::forward_range<urng_t>,
"The underlying range must model std::ranges::forward_range.");
if constexpr (std::ranges::random_access_range<urng_t>)
{ // Nothing to do, just return as ref_view or original view.
return std::views::all(std::forward<urng_t>(urange));
}
else
{ // Get a subrange using the random access iterators of the container.
return view_enforce_random_access{std::forward<urng_t>(urange)};
}
}
};
} // namespace seqan3::detail
namespace seqan3::views
{
inline constexpr auto enforce_random_access = detail::pseudo_random_access_fn{};
} // namespace seqan3::views
adaptor_base.hpp
Provides seqan3::detail::adaptor_base and seqan3::detail::combined_adaptor.
std::declval
T declval(T... args)
std::forward
T forward(T... args)
seqan3::views::enforce_random_access
constexpr auto enforce_random_access
A view adaptor that converts a pseudo random access range to a std::ranges::random_access_range.
Definition enforce_random_access.hpp:351
inherited_iterator_base.hpp
Provides the seqan3::detail::inherited_iterator_base template.
iterator
seqan3::views
The SeqAn namespace for views.
Definition char_strictly_to.hpp:19
std::rel_ops::operator!=
T operator!=(T... args)
type_traits
concept.hpp
Additional non-standard concepts for ranges.
Hide me