SeqAn3 3.4.0-rc.1
The Modern C++ library for sequence analysis.
Loading...
Searching...
No Matches
seqan3::views::deep< underlying_adaptor_t > Class Template Reference

A wrapper type around an existing view adaptor that enables "deep view" behaviour for that view. More...

#include <seqan3/utility/views/deep.hpp>

+ Inheritance diagram for seqan3::views::deep< underlying_adaptor_t >:

Public Member Functions

Constructors, destructor and assignment
constexpr deep () noexcept=default
 Defaulted.
 
constexpr deep (deep const &) noexcept=default
 Defaulted.
 
constexpr deep (deep &&) noexcept=default
 Defaulted.
 
constexpr deepoperator= (deep const &) noexcept=default
 Defaulted.
 
constexpr deepoperator= (deep &&) noexcept=default
 Defaulted.
 
 ~deep () noexcept=default
 Defaulted.
 
- Public Member Functions inherited from seqan3::detail::adaptor_base< deep< underlying_adaptor_t >, underlying_adaptor_t >
constexpr auto operator() (urng_t &&urange) &&
 This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
 
constexpr auto operator() (urng_t &&urange) const &
 Function-style overload for ranges.
 
constexpr adaptor_base (adaptor_base const &) noexcept=default
 Defaulted.
 
constexpr adaptor_base (adaptor_base &&) noexcept=default
 Defaulted.
 
constexpr adaptor_base (stored_args_ts... args) noexcept(noexcept(std::tuple< stored_args_ts... >{ std::forward< stored_args_ts >(args)...}))
 Constructor with possible arguments; becomes a default constructor for adaptors without args.
 
constexpr adaptor_baseoperator= (adaptor_base const &) noexcept=default
 Defaulted.
 
constexpr adaptor_baseoperator= (adaptor_base &&) noexcept=default
 Defaulted.
 
 ~adaptor_base () noexcept=default
 Defaulted.
 

Private Types

using base_type = detail::adaptor_base< deep< underlying_adaptor_t >, underlying_adaptor_t >
 Type of the CRTP-base.
 

Private Member Functions

constexpr auto operator() () const
 This is an overloaded member function, provided for convenience. It differs from the above function only in what argument(s) it accepts.
 
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
 Called to produce a range adaptor closure object if the wrapped functor was not a range adaptor closure object before, i.e. requires arguments.
 
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
 Called to produce a range if the wrapped functor was not a range adaptor closure object before but necessary arguments are also provided.
 

Static Private Member Functions

template<std::ranges::input_range urng_t, typename underlying_adaptor_t_ >
static constexpr auto impl (urng_t &&urange, underlying_adaptor_t_ &&deep_adaptor)
 Unwrap the internal adaptor closure object and pipe the range into it.
 
template<std::size_t range_dimension>
static constexpr decltype(auto) recursive_adaptor (underlying_adaptor_t deep_adaptor)
 recursively construct the deep adaptor
 

Private Attributes

friend base_type
 Befriend the base class so it can call impl().
 

Related Symbols

(Note that these are not member symbols.)

Template argument deduction guides.
template<typename underlying_adaptor_t >
 deep (underlying_adaptor_t &&inner) -> deep< underlying_adaptor_t >
 Template argument deduction helper that preserves lvalue references and turns rvalue references into values.
 

Detailed Description

template<typename underlying_adaptor_t>
class seqan3::views::deep< underlying_adaptor_t >

A wrapper type around an existing view adaptor that enables "deep view" behaviour for that view.

Template Parameters
underlying_adaptor_tThe type of the adaptor being wrapped.

Deep views

If you pass a range to a view that view performs some transformation on that range. If the range passed is multi-dimensional (i.e. a range-of-ranges) that transformation happens on the outermost range. So if you call std::views::reverse on a range-of-dna-ranges, it will revert the order of the dna-ranges, but leave the dna-ranges themselves unchanged.

In some cases this is not desirable or even possible, i.e. seqan3::views::complement performs it's operation on nucleotide-ranges and it would be logical to do so, even it is passed a range-of-nucleotide-ranges (it obviously cannot transform the outer range). We call these views "deep views" as they always perform their operation on the innermost ranges of a multi-dimensional range; in case the input is a one-dimensional range, deepness does not modify the behaviour.

Using views::deep

Strictly speaking, seqan3::views::deep is a view adaptor adaptor, i.e. it gets passed another adaptor when being constructed (not via the pipe!) and returns an adaptor that behaves like the underlying one, except being deep.

You can use it mostly like any other view (adaptor) with some subtle differences, illustrated in the examples below.

View properties

The returned view has the same requirements and guarantees as those of the underlying adaptor type, except that it is also deep, i.e. if the underlying range is range-of-ranges, all transformations apply to the innermost ranges and conversely the requirements also apply to the innermost ranges of the underlying range and guarantees apply to the innermost ranges of the returned range.

For the higher dimensions (all except the innermost ranges) the following properties hold:

Concepts and traits urng_t (underlying range type) rrng_t (returned range type)
std::ranges::input_range required preserved
std::ranges::forward_range preserved
std::ranges::bidirectional_range preserved
std::ranges::random_access_range preserved
std::ranges::contiguous_range lost
std::ranges::viewable_range required guaranteed
std::ranges::view guaranteed
std::ranges::sized_range preserved
std::ranges::common_range preserved
std::ranges::output_range lost
seqan3::const_iterable_range preserved
std::ranges::range_reference_t std::ranges::input_range std::ranges::input_range + std::ranges::view

Examples

Wrapping an adaptor that takes no parameters ("range adaptor <i>closure</i> object"):

// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <ranges>
#include <vector>
namespace my
{
// You can create a permanent alias:
inline auto const deep_reverse = seqan3::views::deep{std::views::reverse};
} // namespace my
int main()
{
using namespace seqan3::literals;
std::vector<seqan3::dna5_vector> sequences{"AAATTT"_dna5, "CCCGGG"_dna5};
seqan3::debug_stream << (sequences | std::views::reverse) << '\n'; // [CCCGGG,AAATTT]
// These two are equivalent:
seqan3::debug_stream << (sequences | my::deep_reverse) << '\n'; // [TTTAAA,GGGCCC]
seqan3::debug_stream << (sequences | seqan3::views::deep{std::views::reverse}) << '\n'; // [TTTAAA,GGGCCC]
}
A wrapper type around an existing view adaptor that enables "deep view" behaviour for that view.
Definition deep.hpp:101
Provides seqan3::debug_stream and related types.
Provides seqan3::views::deep.
Provides seqan3::dna5, container aliases and string literals.
debug_stream_type debug_stream
A global instance of seqan3::debug_stream_type.
Definition debug_stream.hpp:37
The SeqAn namespace for literals.

Wrapping an adaptor that takes parameters:

// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <ranges>
#include <vector>
namespace my
{
inline auto const deep_take = seqan3::views::deep{std::views::take};
}
int main()
{
using namespace seqan3::literals;
std::vector<seqan3::dna5_vector> sequences{"AAATTT"_dna5, "CCCGGG"_dna5};
seqan3::debug_stream << (sequences | std::views::take(1)) << '\n'; // [A,A,A,T,T,T]
seqan3::debug_stream << (sequences | seqan3::views::deep{std::views::take(1)}) << '\n'; // [A,C]
// constructor arguments passed via {} and arguments to underlying view passed via ()
// In this case especially, an alias improves readability:
seqan3::debug_stream << (sequences | my::deep_take(1)) << '\n'; // [A,C]
}

The above example illustrates that views::deep has two sets of arguments, the arguments to construct this adaptor, and the arguments passed to the underlying adaptor when calling this adaptor. You can use () for both, but we highly recommend to use {} to not confuse these; or just use an alias.

Attention
Note that in the case of parameter handling the arguments to views::deep are copied to each invocation of the underlying adaptor if they are temporaries. This is no problem for small objects like the integer above, but might be expensive for larger ones. To avoid this, pass in references to external objects instead of temporaries:
// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <ranges>
#include <vector>
namespace my
{
inline auto const deep_take = seqan3::views::deep{std::views::take};
}
int main()
{
using namespace seqan3::literals;
std::vector<seqan3::dna5_vector> sequences{"AAATTT"_dna5, "CCCGGG"_dna5};
int i = 3;
// takes `i` as a reference:
seqan3::debug_stream << (sequences | my::deep_take(i)) << '\n'; // [AAA,CCC]
}

Wrapping an adaptor including its arguments:

// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
// SPDX-License-Identifier: CC0-1.0
#include <ranges>
#include <vector>
namespace my
{
inline auto const deep_take1 = seqan3::views::deep{std::views::take(1)};
}
int main()
{
using namespace seqan3::literals;
std::vector<seqan3::dna5_vector> sequences{"AAATTT"_dna5, "CCCGGG"_dna5};
seqan3::debug_stream << (sequences | std::views::take(1)) << '\n'; // [A,A,A,T,T,T]
seqan3::debug_stream << (sequences | seqan3::views::deep{std::views::take(1)}) << '\n'; // [A,C]
// constructor arguments passed via {} and arguments to underlying view hardcoded inside
// or with an alias defined previously
seqan3::debug_stream << (sequences | my::deep_take1) << '\n'; // [A,C]
}

In the above example the argument to the underlying adaptor is hardcoded and can't be changed at the call-site. It is less flexible, but does not require workarounds for arguments that are expensive (or impossible) to copy.

Member Function Documentation

◆ impl()

template<typename underlying_adaptor_t >
template<std::ranges::input_range urng_t, typename underlying_adaptor_t_ >
static constexpr auto seqan3::views::deep< underlying_adaptor_t >::impl ( urng_t &&  urange,
underlying_adaptor_t_ &&  deep_adaptor 
)
inlinestaticconstexprprivate

Unwrap the internal adaptor closure object and pipe the range into it.

Template Parameters
urng_tType of the underlying range.
underlying_adaptor_t_Same as underlying_adaptor_t with possibly different cref qualification.
Parameters
[in]urangeThe view's underlying range.
[in]deep_adaptorThe stored adaptor unwrapped by the base-classes explode()-member.
Returns
A view with the inner adaptor applied on the innermost ranges.

◆ operator()() [1/2]

template<typename underlying_adaptor_t >
template<typename first_arg_t , typename... stored_arg_types>
requires (!std::ranges::input_range<first_arg_t>)
constexpr auto seqan3::views::deep< underlying_adaptor_t >::operator() ( first_arg_t &&  first,
stored_arg_types &&...  args 
) const
inlineconstexprprivate

Called to produce a range adaptor closure object if the wrapped functor was not a range adaptor closure object before, i.e. requires arguments.

Template Parameters
first_arg_tThe type of the first argument; must not model std::ranges::input_range.
stored_arg_typesThe argument types, note that temporaries will be copied on recursion!
Parameters
[in]firstFirst argument.
[in]argsFurther arguments (optional).
Returns
A views::deep specialisation of a closure object, i.e. with stored arguments.

◆ operator()() [2/2]

template<typename underlying_adaptor_t >
template<std::ranges::input_range urng_t, typename... stored_arg_types>
requires (sizeof...(stored_arg_types) > 0)
constexpr auto seqan3::views::deep< underlying_adaptor_t >::operator() ( urng_t &&  urange,
stored_arg_types &&...  args 
) const
inlineconstexprprivate

Called to produce a range if the wrapped functor was not a range adaptor closure object before but necessary arguments are also provided.

Template Parameters
urng_tType of the underlying range.
arg_typesThe argument types, note that temporaries will be copied on recursion!
Parameters
[in]urangeThe view's underlying range.
[in]argsFurther arguments.
Returns
A view with the inner adaptor applied on the innermost ranges.

Recurses and calls std::views::transform if the underlying range is a range-of-ranges.

◆ recursive_adaptor()

template<typename underlying_adaptor_t >
template<std::size_t range_dimension>
static constexpr decltype(auto) seqan3::views::deep< underlying_adaptor_t >::recursive_adaptor ( underlying_adaptor_t  deep_adaptor)
inlinestaticconstexprprivate

recursively construct the deep adaptor

this function recursively constructs a range adaptor:

return std::views::transform([](auto && inner_range_depth1)
{
return inner_range_depth1 | std::views::transform([](auto && inner_range_depth2)
{
// ...
return inner_range_depth_n | std::views::transform([adap](auto && innermost_range)
{
// only innermost std::views::transform stores the actual deep-adaptor (stored only once!)
return innermost_range | std::forward<underlying_adaptor_t>(deep_adaptor);
});
// ...
});
});

The documentation for this class was generated from the following file:
Hide me