SeqAn3 3.4.0-rc.1
The Modern C++ library for sequence analysis.
Loading...
Searching...
No Matches
deep.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
3// SPDX-License-Identifier: BSD-3-Clause
4
10#pragma once
11
12#include <ranges>
13
16
17namespace seqan3::views
18{
19
99template <typename underlying_adaptor_t>
100class deep : public detail::adaptor_base<deep<underlying_adaptor_t>, underlying_adaptor_t>
101{
102private:
104 using base_type = detail::adaptor_base<deep<underlying_adaptor_t>, underlying_adaptor_t>;
105
107 friend base_type;
108
109public:
113 constexpr deep() noexcept = default;
114 constexpr deep(deep const &) noexcept = default;
115 constexpr deep(deep &&) noexcept = default;
116 constexpr deep & operator=(deep const &) noexcept = default;
117 constexpr deep & operator=(deep &&) noexcept = default;
118 ~deep() noexcept = default;
119
120 using base_type::base_type;
122
124
126 using base_type::operator();
127
135 template <std::ranges::input_range urng_t, typename underlying_adaptor_t_>
136 static constexpr auto impl(urng_t && urange, underlying_adaptor_t_ && deep_adaptor)
137 {
138 static_assert(std::same_as<underlying_adaptor_t_, underlying_adaptor_t>,
139 "Internally stored deep-adaptor does not match!");
140
141 constexpr size_t range_dimension = range_dimension_v<urng_t>;
142
143 // note: if range_dimension == 1, the expression will actually be
144 // `std::forward<underlying_adaptor_t_>(adap)(urange)`, thus allowing the stateful adaptor to move its arguments
145 // into the view that will be constructed.
146 return recursive_adaptor<range_dimension>(std::forward<underlying_adaptor_t_>(deep_adaptor))(urange);
147 }
148
170 template <std::size_t range_dimension>
171 static constexpr decltype(auto) recursive_adaptor(underlying_adaptor_t deep_adaptor)
172 {
173 if constexpr (range_dimension > 1u)
174 {
175 auto transform = [adaptor = recursive_adaptor<range_dimension - 1u>(
176 std::forward<underlying_adaptor_t>(deep_adaptor))](auto && inner_range)
177 {
178 // We don't want to move a stateful adaptor here, as this adaptor will be called on any element of this
179 // std::views::transform range.
180 return adaptor(std::forward<decltype(inner_range)>(inner_range));
181 };
182 return std::views::transform(std::move(transform));
183 }
184 else
185 {
186 // recursion anchor: only the innermost std::views::transform will store the deep_adaptor.
187 // In an earlier version of seqan3 we recursively passed the deep_adaptor through all std::view::transform
188 // instances and each depth stored the same deep_adaptor. The current approach can save memory as it only
189 // stores the deep_adaptor once in the innermost std::views::transform. It will also produce slightly better
190 // stack-traces by defining the recursion over the range_dimension.
191
192 // NOTE: to allow an lvalue to be returned we need to have the return type decltype(auto).
193 return deep_adaptor;
194 }
195 }
196
205 template <typename first_arg_t, typename... stored_arg_types>
206 requires (!std::ranges::input_range<first_arg_t>)
207 constexpr auto operator()(first_arg_t && first, stored_arg_types &&... args) const
208 {
209 // The adaptor currently wrapped is a proto-adaptor and this function has the arguments to "complete" it.
210 // We extract the adaptor that is stored and invoke it with the given arguments.
211 // This returns an adaptor closure object.
212 auto adaptor_closure =
213 std::get<0>(this->arguments)(std::forward<first_arg_t>(first), std::forward<stored_arg_types>(args)...);
214 // Now we wrap this closure object back into a views::deep to get the deep behaviour.
215 return deep<decltype(adaptor_closure)>{std::move(adaptor_closure)};
216 }
217
219 constexpr auto operator()() const
220 {
221 // Proto-adaptors require arguments by definition, but some support defaulting those (e.g. views::translate).
222 // This extracts the proto adaptor and invokes it without args which yields a different object, the closure
223 // with default arguments.
224 auto adaptor_closure = std::get<0>(this->arguments)();
225 // Now we wrap this closure object back into a views::deep to get the deep behaviour.
226 return deep<decltype(adaptor_closure)>{std::move(adaptor_closure)};
227 }
228
241 template <std::ranges::input_range urng_t, typename... stored_arg_types>
242 requires (sizeof...(stored_arg_types) > 0)
243 constexpr auto operator()(urng_t && urange, stored_arg_types &&... args) const
244 {
245 auto adaptor_closure = std::get<0>(this->arguments)(std::forward<stored_arg_types>(args)...);
246 deep<decltype(adaptor_closure)> deep_adaptor{std::move(adaptor_closure)};
247 return deep_adaptor(std::forward<urng_t>(urange));
248 }
249};
250
256template <typename underlying_adaptor_t>
257deep(underlying_adaptor_t && inner) -> deep<underlying_adaptor_t>;
258
260
261} // 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:101
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)
The SeqAn namespace for views.
Definition char_strictly_to.hpp:19
SeqAn specific customisations in the standard namespace.
Hide me