Loading...
Searching...
No Matches
deep.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 <ranges>
#include <seqan3/core/range/detail/adaptor_base.hpp>
#include <seqan3/core/range/type_traits.hpp>
namespace seqan3::views
{
template <typename underlying_adaptor_t>
class deep : public detail::adaptor_base<deep<underlying_adaptor_t>, underlying_adaptor_t>
{
private:
using base_type = detail::adaptor_base<deep<underlying_adaptor_t>, underlying_adaptor_t>;
friend base_type;
public:
constexpr deep() noexcept = default;
constexpr deep(deep const &) noexcept = default;
constexpr deep(deep &&) noexcept = default;
constexpr deep & operator=(deep const &) noexcept = default;
constexpr deep & operator=(deep &&) noexcept = default;
~deep() noexcept = default;
using base_type::base_type;
using base_type::operator();
template <std::ranges::input_range urng_t, typename underlying_adaptor_t_>
static constexpr auto impl(urng_t && urange, underlying_adaptor_t_ && deep_adaptor)
{
static_assert(std::same_as<underlying_adaptor_t_, underlying_adaptor_t>,
"Internally stored deep-adaptor does not match!");
constexpr size_t range_dimension = range_dimension_v<urng_t>;
// note: if range_dimension == 1, the expression will actually be
// `std::forward<underlying_adaptor_t_>(adap)(urange)`, thus allowing the stateful adaptor to move its arguments
// into the view that will be constructed.
return recursive_adaptor<range_dimension>(std::forward<underlying_adaptor_t_>(deep_adaptor))(urange);
}
template <std::size_t range_dimension>
static constexpr decltype(auto) recursive_adaptor(underlying_adaptor_t deep_adaptor)
{
if constexpr (range_dimension > 1u)
{
auto transform = [adaptor = recursive_adaptor<range_dimension - 1u>(
std::forward<underlying_adaptor_t>(deep_adaptor))](auto && inner_range)
{
// We don't want to move a stateful adaptor here, as this adaptor will be called on any element of this
// std::views::transform range.
return adaptor(std::forward<decltype(inner_range)>(inner_range));
};
return std::views::transform(std::move(transform));
}
else
{
// recursion anchor: only the innermost std::views::transform will store the deep_adaptor.
// In an earlier version of seqan3 we recursively passed the deep_adaptor through all std::view::transform
// instances and each depth stored the same deep_adaptor. The current approach can save memory as it only
// stores the deep_adaptor once in the innermost std::views::transform. It will also produce slightly better
// stack-traces by defining the recursion over the range_dimension.
// NOTE: to allow an lvalue to be returned we need to have the return type decltype(auto).
return deep_adaptor;
}
}
template <typename first_arg_t, typename... stored_arg_types>
requires (!std::ranges::input_range<first_arg_t>)
constexpr auto operator()(first_arg_t && first, stored_arg_types &&... args) const
{
// The adaptor currently wrapped is a proto-adaptor and this function has the arguments to "complete" it.
// We extract the adaptor that is stored and invoke it with the given arguments.
// This returns an adaptor closure object.
auto adaptor_closure =
std::get<0>(this->arguments)(std::forward<first_arg_t>(first), std::forward<stored_arg_types>(args)...);
// Now we wrap this closure object back into a views::deep to get the deep behaviour.
return deep<decltype(adaptor_closure)>{std::move(adaptor_closure)};
}
constexpr auto operator()() const
{
// Proto-adaptors require arguments by definition, but some support defaulting those (e.g. views::translate).
// This extracts the proto adaptor and invokes it without args which yields a different object, the closure
// with default arguments.
auto adaptor_closure = std::get<0>(this->arguments)();
// Now we wrap this closure object back into a views::deep to get the deep behaviour.
return deep<decltype(adaptor_closure)>{std::move(adaptor_closure)};
}
template <std::ranges::input_range urng_t, typename... stored_arg_types>
requires (sizeof...(stored_arg_types) > 0)
constexpr auto operator()(urng_t && urange, stored_arg_types &&... args) const
{
auto adaptor_closure = std::get<0>(this->arguments)(std::forward<stored_arg_types>(args)...);
deep<decltype(adaptor_closure)> deep_adaptor{std::move(adaptor_closure)};
return deep_adaptor(std::forward<urng_t>(urange));
}
};
template <typename underlying_adaptor_t>
deep(underlying_adaptor_t && inner) -> deep<underlying_adaptor_t>;
} // namespace seqan3::views
adaptor_base.hpp
Provides seqan3::detail::adaptor_base and seqan3::detail::combined_adaptor.
seqan3::views::deep::deep
deep(underlying_adaptor_t &&inner) -> deep< underlying_adaptor_t >
Template argument deduction helper that preserves lvalue references and turns rvalue references into ...
seqan3::views::deep::deep
constexpr deep() noexcept=default
Defaulted.
type_traits.hpp
Provides various transformation traits used by the range module.
std::forward
T forward(T... args)
seqan3::range_dimension_v
constexpr size_t range_dimension_v
Returns the number of times you can call seqan3::value_type_t recursively on t (type trait).
Definition core/range/type_traits.hpp:112
seqan3::views
The SeqAn namespace for views.
Definition char_strictly_to.hpp:19
std
SeqAn specific customisations in the standard namespace.
Hide me