SeqAn3 3.1.0
The Modern C++ library for sequence analysis.
deep.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/ranges>
16
19
20namespace seqan3::views
21{
22
102template <typename underlying_adaptor_t>
103class deep : public detail::adaptor_base<deep<underlying_adaptor_t>, underlying_adaptor_t>
104{
105private:
107 using base_type = detail::adaptor_base<deep<underlying_adaptor_t>, underlying_adaptor_t>;
108
110 friend base_type;
111
112public:
116 constexpr deep() noexcept = default;
117 constexpr deep(deep const &) noexcept = default;
118 constexpr deep(deep &&) noexcept = default;
119 constexpr deep & operator=(deep const &) noexcept = default;
120 constexpr deep & operator=(deep &&) noexcept = default;
121 ~deep() noexcept = default;
122
123 using base_type::base_type;
125
127
129 using base_type::operator();
130
138 template <std::ranges::input_range urng_t, typename underlying_adaptor_t_>
139 static constexpr auto impl(urng_t && urange, underlying_adaptor_t_ && deep_adaptor)
140 {
141 static_assert(std::same_as<underlying_adaptor_t_, underlying_adaptor_t>,
142 "Internally stored deep-adaptor does not match!");
143
144 constexpr size_t range_dimension = range_dimension_v<urng_t>;
145
146 // note: if range_dimension == 1, the expression will actually be
147 // `std::forward<underlying_adaptor_t_>(adap)(urange)`, thus allowing the stateful adaptor to move its arguments
148 // into the view that will be constructed.
149 return recursive_adaptor<range_dimension>(std::forward<underlying_adaptor_t_>(deep_adaptor))(urange);
150 }
151
173 template <std::size_t range_dimension>
174 static constexpr decltype(auto) recursive_adaptor(underlying_adaptor_t deep_adaptor)
175 {
176 if constexpr (range_dimension > 1u)
177 {
178 auto transform
179 = [adaptor = recursive_adaptor<range_dimension - 1u>(std::forward<underlying_adaptor_t>(deep_adaptor))]
180 (auto && inner_range)
181 {
182 // We don't want to move a stateful adaptor here, as this adaptor will be called on any element of this
183 // std::views::transform range.
184 return adaptor(std::forward<decltype(inner_range)>(inner_range));
185 };
186 return std::views::transform(std::move(transform));
187 }
188 else
189 {
190 // recursion anchor: only the innermost std::views::transform will store the deep_adaptor.
191 // In an earlier version of seqan3 we recursively passed the deep_adaptor through all std::view::transform
192 // instances and each depth stored the same deep_adaptor. The current approach can save memory as it only
193 // stores the deep_adaptor once in the innermost std::views::transform. It will also produce slightly better
194 // stack-traces by defining the recursion over the range_dimension.
195
196 // NOTE: to allow an lvalue to be returned we need to have the return type decltype(auto).
197 return deep_adaptor;
198 }
199 }
200
209 template <typename first_arg_t, typename ...stored_arg_types>
211 requires (!std::ranges::input_range<first_arg_t>)
213 constexpr auto operator()(first_arg_t && first, stored_arg_types && ...args) const
214 {
215 // The adaptor currently wrapped is a proto-adaptor and this function has the arguments to "complete" it.
216 // We extract the adaptor that is stored and invoke it with the given arguments.
217 // This returns an adaptor closure object.
218 auto adaptor_closure = std::get<0>(this->arguments)(std::forward<first_arg_t>(first),
219 std::forward<stored_arg_types>(args)...);
220 // Now we wrap this closure object back into a views::deep to get the deep behaviour.
221 return deep<decltype(adaptor_closure)>{std::move(adaptor_closure)};
222 }
223
225 constexpr auto operator()() const
226 {
227 // Proto-adaptors require arguments by definition, but some support defaulting those (e.g. views::translate).
228 // This extracts the proto adaptor and invokes it without args which yields a different object, the closure
229 // with default arguments.
230 auto adaptor_closure = std::get<0>(this->arguments)();
231 // Now we wrap this closure object back into a views::deep to get the deep behaviour.
232 return deep<decltype(adaptor_closure)>{std::move(adaptor_closure)};
233 }
234
247 template <std::ranges::input_range urng_t, typename ...stored_arg_types>
249 requires (sizeof...(stored_arg_types) > 0)
251 constexpr auto operator()(urng_t && urange, stored_arg_types && ...args) const
252 {
253 auto adaptor_closure = std::get<0>(this->arguments)(std::forward<stored_arg_types>(args)...);
254 deep<decltype(adaptor_closure)> deep_adaptor{std::move(adaptor_closure)};
255 return deep_adaptor(std::forward<urng_t>(urange));
256 }
257};
258
264template <typename underlying_adaptor_t>
265deep(underlying_adaptor_t && inner) -> deep<underlying_adaptor_t>;
266
268
269} // namespace seqan3::views
Provides seqan3::detail::adaptor_base and seqan3::detail::combined_adaptor.
A wrapper type around an existing view adaptor that enables "deep view" behaviour for that view.
Definition: deep.hpp:104
deep(underlying_adaptor_t &&inner) -> deep< underlying_adaptor_t >
Template argument deduction helper that preserves lvalue references and turns rvalue references into ...
constexpr deep() noexcept=default
Defaulted.
Provides various transformation traits used by the range module.
T forward(T... args)
decltype(detail::transform< trait_t >(list_t{})) transform
Apply a transformation trait to every type in the list and return a seqan3::type_list of the results.
Definition: traits.hpp:471
The SeqAn namespace for views.
Definition: char_to.hpp:22
SeqAn specific customisations in the standard namespace.
The <ranges> header from C++20's standard library.