SeqAn3  3.0.3
The Modern C++ library for sequence analysis.
deep.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2020, 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 
18 
19 namespace seqan3::views
20 {
21 
101 template <typename underlying_adaptor_t>
102 class deep : public detail::adaptor_base<deep<underlying_adaptor_t>, underlying_adaptor_t>
103 {
104 private:
107 
109  friend base_type;
110 
111 public:
115  constexpr deep() noexcept = default;
116  constexpr deep(deep const &) noexcept = default;
117  constexpr deep(deep &&) noexcept = default;
118  constexpr deep & operator=(deep const &) noexcept = default;
119  constexpr deep & operator=(deep &&) noexcept = default;
120  ~deep() noexcept = default;
121 
122  using base_type::base_type;
124 
126 
128  using base_type::operator();
129 
137  template <std::ranges::input_range urng_t, typename underlying_adaptor_t_>
138  static constexpr auto impl(urng_t && urange, underlying_adaptor_t_ && deep_adaptor)
139  {
140  static_assert(std::same_as<underlying_adaptor_t_, underlying_adaptor_t>,
141  "Internally stored deep-adaptor does not match!");
142 
143  constexpr size_t range_dimension = range_dimension_v<urng_t>;
144 
145  // note: if range_dimension == 1, the expression will actually be
146  // `std::forward<underlying_adaptor_t_>(adap)(urange)`, thus allowing the stateful adaptor to move its arguments
147  // into the view that will be constructed.
148  return recursive_adaptor<range_dimension>(std::forward<underlying_adaptor_t_>(deep_adaptor))(urange);
149  }
150 
172  template <std::size_t range_dimension>
173  static constexpr decltype(auto) recursive_adaptor(underlying_adaptor_t deep_adaptor)
174  {
175  if constexpr (range_dimension > 1u)
176  {
177  auto transform
178  = [adaptor = recursive_adaptor<range_dimension - 1u>(std::forward<underlying_adaptor_t>(deep_adaptor))]
179  (auto && inner_range)
180  {
181  // We don't want to move a stateful adaptor here, as this adaptor will be called on any element of this
182  // std::views::transform range.
183  return adaptor(std::forward<decltype(inner_range)>(inner_range));
184  };
186  }
187  else
188  {
189  // recursion anchor: only the innermost std::views::transform will store the deep_adaptor.
190  // In an earlier version of seqan3 we recursively passed the deep_adaptor through all std::view::transform
191  // instances and each depth stored the same deep_adaptor. The current approach can save memory as it only
192  // stores the deep_adaptor once in the innermost std::views::transform. It will also produce slightly better
193  // stack-traces by defining the recursion over the range_dimension.
194 
195  // NOTE: to allow an lvalue to be returned we need to have the return type decltype(auto).
196  return deep_adaptor;
197  }
198  }
199 
208  template <typename first_arg_t, typename ...stored_arg_types>
210  requires (!std::ranges::input_range<first_arg_t>)
212  constexpr auto operator()(first_arg_t && first, stored_arg_types && ...args) const
213  {
214  // The adaptor currently wrapped is a proto-adaptor and this function has the arguments to "complete" it.
215  // We extract the adaptor that is stored and invoke it with the given arguments.
216  // This returns an adaptor closure object.
217  auto adaptor_closure = std::get<0>(this->arguments)(std::forward<first_arg_t>(first),
218  std::forward<stored_arg_types>(args)...);
219  // Now we wrap this closure object back into a views::deep to get the deep behaviour.
220  return deep<decltype(adaptor_closure)>{std::move(adaptor_closure)};
221  }
222 
224  constexpr auto operator()() const
225  {
226  // Proto-adaptors require arguments by definition, but some support defaulting those (e.g. views::translate).
227  // This extracts the proto adaptor and invokes it without args which yields a different object, the closure
228  // with default arguments.
229  auto adaptor_closure = std::get<0>(this->arguments)();
230  // Now we wrap this closure object back into a views::deep to get the deep behaviour.
231  return deep<decltype(adaptor_closure)>{std::move(adaptor_closure)};
232  }
233 
246  template <std::ranges::input_range urng_t, typename ...stored_arg_types>
248  requires (sizeof...(stored_arg_types) > 0)
250  constexpr auto operator()(urng_t && urange, stored_arg_types && ...args) const
251  {
252  auto adaptor_closure = std::get<0>(this->arguments)(std::forward<stored_arg_types>(args)...);
253  deep<decltype(adaptor_closure)> deep_adaptor{std::move(adaptor_closure)};
254  return deep_adaptor(std::forward<urng_t>(urange));
255  }
256 };
257 
263 template <typename underlying_adaptor_t>
264 deep(underlying_adaptor_t && inner) -> deep<underlying_adaptor_t>;
265 
267 
268 } // namespace seqan3::views
CRTP-base to simplify the definition of range adaptor closure objects and similar types.
Definition: detail.hpp:79
std::tuple< stored_args_ts... > arguments
Stores the arguments.
Definition: detail.hpp:82
A wrapper type around an existing view adaptor that enables "deep view" behaviour for that view.
Definition: deep.hpp:103
deep(underlying_adaptor_t &&inner) -> deep< underlying_adaptor_t >
Template argument deduction helper that preserves lvalue references and turns rvalue references into ...
static constexpr auto impl(urng_t &&urange, underlying_adaptor_t_ &&deep_adaptor)
Unwrap the internal adaptor closure object and pipe the range into it.
Definition: deep.hpp:138
constexpr auto operator()() const
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition: deep.hpp:224
friend base_type
Befriend the base class so it can call impl().
Definition: deep.hpp:109
static constexpr decltype(auto) recursive_adaptor(underlying_adaptor_t deep_adaptor)
recursively construct the deep adaptor
Definition: deep.hpp:173
constexpr deep() noexcept=default
Defaulted.
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:434
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:70
The SeqAn namespace for views.
Definition: char_to.hpp:22
SeqAn specific customisations in the standard namespace.
Auxiliary header for the views submodule .
Adaptations of concepts from the Ranges TS.