SeqAn3  3.0.1
The Modern C++ library for sequence analysis.
take_until.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 
18 #include <seqan3/io/exception.hpp>
19 #include <seqan3/range/concept.hpp>
23 #include <seqan3/std/concepts>
24 #include <seqan3/std/ranges>
26 #include <seqan3/std/algorithm>
27 #include <seqan3/std/concepts>
28 #include <seqan3/std/iterator>
29 #include <seqan3/std/type_traits>
30 #include <seqan3/std/ranges>
31 
32 namespace seqan3::detail
33 {
34 
35 // ============================================================================
36 // view_take_until
37 // ============================================================================
38 
52 template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
53 class view_take_until : public std::ranges::view_interface<view_take_until<urng_t, fun_t, or_throw, and_consume>>
54 {
55 private:
56 
57  static_assert(std::invocable<fun_t, reference_t<urng_t>>,
58  "The functor type for views::take_until must model std::invocable<fun_t, reference_t<urng_t>>.");
59  static_assert(std::boolean<std::result_of_t<fun_t&&(reference_t<urng_t>)>>,
60  "The functor type for views::take_until must return std::boolean.");
61 
63  urng_t urange;
64 
66  ranges::semiregular_t<fun_t> fun;
67 
69  static constexpr bool const_iterable = const_iterable_range<urng_t> &&
71 
74  template <typename rng_t>
75  class iterator_type : public inherited_iterator_base<iterator_type<rng_t>, std::ranges::iterator_t<rng_t>>
76  {
77  private:
79  using base_base_t = std::ranges::iterator_t<rng_t>;
81  using base_t = inherited_iterator_base<iterator_type, std::ranges::iterator_t<rng_t>>;
82 
84  using sentinel_type = std::ranges::sentinel_t<rng_t>;
85 
91  ranges::semiregular_t<fun_ref_t> fun;
92 
93  public:
98  constexpr iterator_type() = default;
99  constexpr iterator_type(iterator_type const & rhs) = default;
100  constexpr iterator_type(iterator_type && rhs) = default;
101  constexpr iterator_type & operator=(iterator_type const & rhs) = default;
102  constexpr iterator_type & operator=(iterator_type && rhs) = default;
103  ~iterator_type() = default;
104 
106  iterator_type(base_base_t it) noexcept(noexcept(base_t{it})) :
107  base_t{std::move(it)}
108  {}
109 
111  iterator_type(base_base_t it,
112  fun_ref_t _fun,
113  sentinel_type /*only used by the consuming iterator*/) noexcept(noexcept(base_t{it})) :
114  base_t{std::move(it)}, fun{_fun}
115  {}
117 
123  using difference_type = typename std::iterator_traits<base_base_t>::difference_type;
126  using value_type = typename std::iterator_traits<base_base_t>::value_type;
128  using reference = typename std::iterator_traits<base_base_t>::reference;
130  using pointer = typename std::iterator_traits<base_base_t>::pointer;
132  using iterator_category = iterator_tag_t<base_base_t>;
134 
139  bool operator==(iterator_type const & rhs) const
141  noexcept(noexcept(std::declval<base_base_t &>() == std::declval<base_base_t &>()))
143  requires std::forward_iterator<base_base_t>
145  {
146  return *this->this_to_base() == *rhs.this_to_base();
147  }
148 
150  bool operator==(sentinel_type const & rhs) const
151  noexcept(!or_throw &&
152  noexcept(std::declval<base_base_t &>() == std::declval<sentinel_type &>()) &&
153  noexcept(fun(std::declval<reference>())))
154  {
155  if (*this->this_to_base() == rhs) // [[unlikely]]
156  {
157  if constexpr (or_throw)
158  throw unexpected_end_of_input{"Reached end of input before functor evaluated to true."};
159  else
160  return true;
161  }
162 
163  return fun(**this);
164  }
165 
167  friend bool operator==(sentinel_type const & lhs, iterator_type const & rhs)
168  noexcept(noexcept(rhs == lhs))
169  {
170  return rhs == lhs;
171  }
172 
174  bool operator!=(sentinel_type const & rhs) const
175  noexcept(noexcept(std::declval<iterator_type &>() == rhs))
176  {
177  return !(*this == rhs);
178  }
179 
181  bool operator!=(iterator_type const & rhs) const
182  noexcept(noexcept(std::declval<iterator_type &>() == rhs))
184  requires std::forward_iterator<base_base_t>
186  {
187  return !(*this == rhs);
188  }
189 
191  friend bool operator!=(sentinel_type const & lhs, iterator_type const & rhs)
192  noexcept(noexcept(rhs != lhs))
193  {
194  return rhs != lhs;
195  }
197  }; // class iterator_type
198 
201  template <typename rng_t>
202  class iterator_type_consume_input : public inherited_iterator_base<iterator_type_consume_input<rng_t>, std::ranges::iterator_t<rng_t>>
203  {
204  private:
206  using base_base_t = std::ranges::iterator_t<rng_t>;
208  using base_t = inherited_iterator_base<iterator_type_consume_input, std::ranges::iterator_t<rng_t>>;
209 
215  ranges::semiregular_t<fun_ref_t> fun;
216 
218  using sentinel_type = std::ranges::sentinel_t<rng_t>;
219 
221  sentinel_type stored_end;
222 
224  bool at_end_gracefully = false;
225 
226  public:
231  constexpr iterator_type_consume_input() = default;
234  constexpr iterator_type_consume_input(iterator_type_consume_input const & rhs) = default;
236  constexpr iterator_type_consume_input(iterator_type_consume_input && rhs) = default;
238  constexpr iterator_type_consume_input & operator=(iterator_type_consume_input const & rhs) = default;
240  constexpr iterator_type_consume_input & operator=(iterator_type_consume_input && rhs) = default;
242  ~iterator_type_consume_input() = default;
243 
245  iterator_type_consume_input(base_base_t it,
246  fun_ref_t _fun,
247  sentinel_type sen) noexcept(noexcept(base_t{it})) :
248  base_t{std::move(it)}, fun{_fun}, stored_end{std::move(sen)}
249  {
250  if ((*this->this_to_base() != stored_end) && fun(**this))
251  {
252  at_end_gracefully = true;
253  ++(*this);
254  }
255  }
257 
262  using difference_type = typename std::iterator_traits<base_base_t>::difference_type;
263  using value_type = typename std::iterator_traits<base_base_t>::value_type;
264  using reference = typename std::iterator_traits<base_base_t>::reference;
265  using pointer = typename std::iterator_traits<base_base_t>::pointer;
266  using iterator_category = std::input_iterator_tag;
267 
273  iterator_type_consume_input & operator++()
275  noexcept(noexcept(++std::declval<base_t &>()) &&
276  noexcept(std::declval<base_base_t &>() != std::declval<sentinel_type &>()) &&
277  noexcept(fun(std::declval<reference>())))
278  {
279  base_t::operator++();
280 
281  while ((*this->this_to_base() != stored_end) && fun(**this))
282  {
283  at_end_gracefully = true;
284  base_t::operator++();
285  }
286 
287  return *this;
288  }
289 
291  iterator_type_consume_input operator++(int)
292  noexcept(noexcept(++std::declval<iterator_type_consume_input &>()) &&
293  std::is_nothrow_copy_constructible_v<iterator_type_consume_input>)
294  {
295  iterator_type_consume_input cpy{*this};
296  ++(*this);
297  return cpy;
298  }
300 
305  bool operator==(sentinel_type const & rhs) const
307  noexcept(!or_throw &&
308  noexcept(std::declval<base_base_t &>() != std::declval<sentinel_type &>()) &&
309  noexcept(fun(std::declval<reference>())))
310  {
311  if (at_end_gracefully)
312  return true;
313 
314  if (*this->this_to_base() == rhs)
315  {
316  if constexpr (or_throw)
317  throw unexpected_end_of_input{"Reached end of input before functor evaluated to true."};
318  else
319  return true;
320  }
321 
322  return fun(**this);
323  }
324 
326  friend bool operator==(sentinel_type const & lhs, iterator_type_consume_input const & rhs)
327  noexcept(noexcept(rhs == lhs))
328  {
329  return rhs == lhs;
330  }
331 
333  bool operator!=(sentinel_type const & rhs) const
334  noexcept(noexcept(std::declval<iterator_type_consume_input &>() == rhs))
335  {
336  return !(*this == rhs);
337  }
338 
340  friend bool operator!=(sentinel_type const & lhs, iterator_type_consume_input const & rhs)
341  noexcept(noexcept(rhs != lhs))
342  {
343  return rhs != lhs;
344  }
346  }; // class iterator_type_consume_input
347 
348 public:
352  using reference = reference_t<urng_t>;
355  using const_reference = detail::transformation_trait_or_t<seqan3::reference<urng_t const>, void>;
357  using value_type = value_type_t<urng_t>;
359  using size_type = void;
361  using difference_type = difference_type_t<urng_t>;
364  iterator_type_consume_input<urng_t>,
365  iterator_type<urng_t>>;
366 
369  void,
370  detail::transformation_trait_or_t<
373 
377  view_take_until() = default;
378  constexpr view_take_until(view_take_until const & rhs) = default;
379  constexpr view_take_until(view_take_until && rhs) = default;
380  constexpr view_take_until & operator=(view_take_until const & rhs) = default;
381  constexpr view_take_until & operator=(view_take_until && rhs) = default;
382  ~view_take_until() = default;
383 
388  view_take_until(urng_t _urange, fun_t _fun)
389  : urange{std::move(_urange)}, fun{std::forward<fun_t>(_fun)}
390  {}
391 
397  template <std::ranges::viewable_range rng_t>
401  view_take_until(rng_t && _urange, fun_t _fun)
402  : view_take_until{std::views::all(std::forward<rng_t>(_urange)), std::move(_fun)}
403  {}
405 
422  iterator begin() noexcept
423  {
424  return {std::ranges::begin(urange), static_cast<fun_t &>(fun), std::ranges::end(urange)};
425  }
426 
428  const_iterator begin() const noexcept
429  requires const_iterable
430  {
431  return {std::ranges::begin(urange), static_cast<fun_t const &>(fun), std::ranges::end(urange)};
432  }
433 
435  const_iterator cbegin() const noexcept
436  requires const_iterable
437  {
438  return {std::ranges::begin(urange), static_cast<fun_t const &>(fun), std::ranges::end(urange)};
439  }
440 
454  auto end() noexcept
455  {
456  return std::ranges::end(urange);
457  }
458 
460  auto end() const noexcept
461  requires const_iterable
462  {
463  return std::ranges::cend(urange);
464  }
465 
467  auto cend() const noexcept
468  requires const_iterable
469  {
470  return std::ranges::cend(urange);
471  }
473 };
474 
477 template <typename urng_t, typename fun_t, bool or_throw = false, bool and_consume = false>
478 view_take_until(urng_t &&, fun_t) -> view_take_until<std::ranges::all_view<urng_t>, fun_t, or_throw, and_consume>;
479 
480 // ============================================================================
481 // take_until_fn (adaptor definition)
482 // ============================================================================
483 
487 template <bool or_throw, bool and_consume>
488 struct take_until_fn
489 {
491  template <typename fun_t>
492  constexpr auto operator()(fun_t && fun) const
493  {
494  return adaptor_from_functor{*this, std::forward<fun_t>(fun)};
495  }
496 
504  template <std::ranges::viewable_range urng_t, typename fun_t>
505  constexpr auto operator()(urng_t && urange, fun_t && fun) const
506  {
507  return view_take_until<std::ranges::all_view<urng_t>, fun_t, or_throw, and_consume>
508  {
509  std::views::all(std::forward<urng_t>(urange)),
510  std::forward<fun_t>(fun)
511  };
512  }
513 };
514 
515 } // namespace seqan3::detail
516 
517 // ============================================================================
518 // views::take_until (adaptor instance definition)
519 // ============================================================================
520 
521 namespace seqan3::views
522 {
523 
585 inline auto constexpr take_until = detail::take_until_fn<false, false>{};
586 
587 // ============================================================================
588 // views::take_until_or_throw (adaptor instance definition)
589 // ============================================================================
590 
599 inline auto constexpr take_until_or_throw = detail::take_until_fn<true, false>{};
600 
601 // ============================================================================
602 // views::take_until_and_consume (adaptor instance definition)
603 // ============================================================================
604 
613 inline auto constexpr take_until_and_consume = detail::take_until_fn<false, true>{};
614 
615 // ============================================================================
616 // views::take_until_or_throw_and_consume (adaptor instance definition)
617 // ============================================================================
618 
627 inline auto constexpr take_until_or_throw_and_consume = detail::take_until_fn<true, true>{};
628 
630 
631 } // namespace seqan3::views
shortcuts.hpp
Provides various shortcuts for common std::ranges functions.
seqan3::views::take_until_and_consume
constexpr auto take_until_and_consume
A view adaptor that returns elements from the underlying range until the functor evaluates to true (o...
Definition: take_until.hpp:613
seqan3::views
The SeqAn namespace for views.
Definition: view_to_simd.hpp:672
type_traits
Provides C++20 additions to the type_traits header.
constructible_from
The std::constructible_from concept specifies that a variable of type T can be initialized with the g...
std::rel_ops::operator!=
T operator!=(T... args)
iterator
Provides C++20 additions to the <iterator> header.
std::input_iterator_tag
seqan3::views::move
const auto move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:68
concept.hpp
Adaptations of concepts from the standard library.
algorithm
Adaptations of algorithms from the Ranges TS.
concepts
The Concepts library.
concept.hpp
Additional non-standard concepts for ranges.
boolean
Specifies that a type can be used in boolean contexts.
seqan3::views::take_until_or_throw_and_consume
constexpr auto take_until_or_throw_and_consume
A view adaptor that returns elements from the underlying range until the functor evaluates to true (t...
Definition: take_until.hpp:627
regular_invocable
Specifies whether the given callable is invocable with the given arguments and equality preserving (i...
range.hpp
Provides various transformation traits used by the range module.
std::iterator_traits
const_iterable_range
Specifies requirements of an input range type for which the const version of that type satisfies the ...
transformation_trait_or.hpp
Provides seqan3::detail::transformation_trait_or.
exception.hpp
Provides exceptions used in the I/O module.
seqan3::views::take_until
constexpr auto take_until
A view adaptor that returns elements from the underlying range until the functor evaluates to true (o...
Definition: take_until.hpp:585
iterator.hpp
Provides various transformation traits for use on iterators.
seqan3::search_cfg::all
constexpr detail::search_mode_all all
Configuration element to receive all hits within the error bounds.
Definition: mode.hpp:43
ranges
Adaptations of concepts from the Ranges TS.
std::remove_reference_t
seqan3::views::take_until_or_throw
constexpr auto take_until_or_throw
A view adaptor that returns elements from the underlying range until the functor evaluates to true (t...
Definition: take_until.hpp:599
std::type_identity
The identity transformation (a transformation_trait that returns the input).
Definition: type_traits:31
std::begin
T begin(T... args)
std
SeqAn specific customisations in the standard namespace.
std::result_of_t
std::end
T end(T... args)
std::conditional_t
inherited_iterator_base.hpp
Provides the seqan3::detail::inherited_iterator_base template.
invocable
Specifies whether the given callable is invocable with the given arguments.
detail.hpp
Auxiliary header for the views submodule .