SeqAn3  3.0.2
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 
19 #include <seqan3/io/exception.hpp>
20 #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, std::ranges::range_reference_t<urng_t>>,
58  "The functor type for views::take_until must model"
59  "std::invocable<fun_t, std::ranges::range_reference_t<urng_t>>.");
60  static_assert(std::convertible_to<std::result_of_t<fun_t&&(std::ranges::range_reference_t<urng_t>)>, bool>,
61  "The result type of the functor for views::take_until must be a boolean.");
62 
64  urng_t urange;
65 
67  ranges::semiregular_t<fun_t> fun;
68 
70  static constexpr bool const_iterable = const_iterable_range<urng_t> &&
71  std::regular_invocable<fun_t, std::ranges::range_reference_t<urng_t>>;
72 
73  template <typename rng_t>
74  class basic_iterator;
75 
76  template <bool is_const_range>
77  class basic_sentinel;
78 
79  template <typename rng_t>
80  class basic_consume_iterator;
81 
82 private:
88  basic_consume_iterator<urng_t>,
89  basic_iterator<urng_t>>;
90 
92  using const_iterator = basic_iterator<urng_t const>;
94 
95 public:
99  view_take_until() = default;
100  constexpr view_take_until(view_take_until const & rhs) = default;
101  constexpr view_take_until(view_take_until && rhs) = default;
102  constexpr view_take_until & operator=(view_take_until const & rhs) = default;
103  constexpr view_take_until & operator=(view_take_until && rhs) = default;
104  ~view_take_until() = default;
105 
110  view_take_until(urng_t _urange, fun_t _fun)
111  : urange{std::move(_urange)}, fun{std::forward<fun_t>(_fun)}
112  {}
113 
119  template <std::ranges::viewable_range rng_t>
121  requires std::constructible_from<rng_t, std::views::all_t<rng_t>>
123  view_take_until(rng_t && _urange, fun_t _fun)
124  : view_take_until{std::views::all(std::forward<rng_t>(_urange)), std::move(_fun)}
125  {}
127 
144  iterator begin() noexcept
145  {
146  return {std::ranges::begin(urange), static_cast<fun_t &>(fun), std::ranges::end(urange)};
147  }
148 
150  const_iterator begin() const noexcept
151  requires const_iterable
152  {
153  return {std::ranges::cbegin(urange), static_cast<fun_t const &>(fun), std::ranges::cend(urange)};
154  }
155 
169  auto end() noexcept
170  {
171  if constexpr (and_consume && !std::ranges::forward_range<urng_t>)
172  return std::ranges::end(urange);
173  else
174  return basic_sentinel<false>{std::ranges::end(urange), fun};
175  }
176 
178  auto end() const noexcept
179  requires const_iterable
180  {
181  if constexpr (and_consume && !std::ranges::forward_range<urng_t>)
182  return std::ranges::cend(urange);
183  else
184  return basic_sentinel<true>{std::ranges::cend(urange), static_cast<fun_t const &>(fun)};
185  }
187 };
188 
191 template <typename urng_t, typename fun_t, bool or_throw = false, bool and_consume = false>
192 view_take_until(urng_t &&, fun_t) -> view_take_until<std::views::all_t<urng_t>, fun_t, or_throw, and_consume>;
193 
196 template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
197 template <typename rng_t>
198 class view_take_until<urng_t, fun_t, or_throw, and_consume>::basic_iterator :
199  public inherited_iterator_base<basic_iterator<rng_t>, std::ranges::iterator_t<rng_t>>
200 {
201 private:
203  using base_base_t = std::ranges::iterator_t<rng_t>;
205  using base_t = inherited_iterator_base<basic_iterator, std::ranges::iterator_t<rng_t>>;
207  using sentinel_type = std::ranges::sentinel_t<rng_t>;
214 
215 public:
220  constexpr basic_iterator() = default;
221  constexpr basic_iterator(basic_iterator const & rhs) = default;
222  constexpr basic_iterator(basic_iterator && rhs) = default;
223  constexpr basic_iterator & operator=(basic_iterator const & rhs) = default;
224  constexpr basic_iterator & operator=(basic_iterator && rhs) = default;
225  ~basic_iterator() = default;
226 
228  basic_iterator(base_base_t it) noexcept(noexcept(base_t{it})) :
229  base_t{std::move(it)}
230  {}
231 
233  basic_iterator(base_base_t it,
234  fun_ref_t _fun,
235  sentinel_type /*only used by the consuming iterator*/) noexcept(noexcept(base_t{it})) :
236  base_t{std::move(it)}, fun{_fun}
237  {}
239 
245  using difference_type = std::iter_difference_t<base_base_t>;
248  using value_type = std::iter_value_t<base_base_t>;
250  using reference = std::iter_reference_t<base_base_t>;
252  using pointer = detail::iter_pointer_t<base_base_t>;
254  using iterator_category = detail::iterator_category_tag_t<base_base_t>;
256  using iterator_concept = detail::iterator_concept_tag_t<base_base_t>;
258 
260  base_base_t base() const
262  requires std::copy_constructible<base_base_t>
264  {
265  return *this->this_to_base();
266  }
267 };
268 
271 template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
272 template <typename rng_t>
273 class view_take_until<urng_t, fun_t, or_throw, and_consume>::basic_consume_iterator :
274  public inherited_iterator_base<basic_consume_iterator<rng_t>, std::ranges::iterator_t<rng_t>>
275 {
276 private:
278  using base_base_t = std::ranges::iterator_t<rng_t>;
280  using base_t = inherited_iterator_base<basic_consume_iterator, std::ranges::iterator_t<rng_t>>;
281 
288 
290  using sentinel_type = std::ranges::sentinel_t<rng_t>;
291 
293  sentinel_type stored_end;
294 
296  bool at_end_gracefully = false;
297 
298 public:
303  constexpr basic_consume_iterator() = default;
304  constexpr basic_consume_iterator(basic_consume_iterator const & rhs) = default;
305  constexpr basic_consume_iterator(basic_consume_iterator && rhs) = default;
306  constexpr basic_consume_iterator & operator=(basic_consume_iterator const & rhs) = default;
307  constexpr basic_consume_iterator & operator=(basic_consume_iterator && rhs) = default;
308  ~basic_consume_iterator() = default;
309 
311  basic_consume_iterator(base_base_t it,
312  fun_ref_t _fun,
313  sentinel_type sen) noexcept(noexcept(base_t{it})) :
314  base_t{std::move(it)}, fun{_fun}, stored_end{std::move(sen)}
315  {
316  if ((*this->this_to_base() != stored_end) && fun(**this))
317  {
318  at_end_gracefully = true;
319  ++(*this);
320  }
321  }
323 
328  using difference_type = std::iter_difference_t<base_base_t>;
329  using value_type = std::iter_value_t<base_base_t>;
330  using reference = std::iter_reference_t<base_base_t>;
331  using pointer = detail::iter_pointer_t<base_base_t>;
332  using iterator_category = std::input_iterator_tag;
333 
339  basic_consume_iterator & operator++()
341  noexcept(noexcept(++std::declval<base_t &>()) &&
342  noexcept(std::declval<base_base_t &>() != std::declval<sentinel_type &>()) &&
343  noexcept(fun(std::declval<reference>())))
344  {
345  base_t::operator++();
346 
347  while ((*this->this_to_base() != stored_end) && fun(**this))
348  {
349  at_end_gracefully = true;
350  base_t::operator++();
351  }
352 
353  return *this;
354  }
355 
357  basic_consume_iterator operator++(int)
358  noexcept(noexcept(++std::declval<basic_consume_iterator &>()) &&
359  std::is_nothrow_copy_constructible_v<basic_consume_iterator>)
360  {
361  basic_consume_iterator cpy{*this};
362  ++(*this);
363  return cpy;
364  }
366 
370  bool operator==(sentinel_type const & rhs) const
372  noexcept(!or_throw &&
373  noexcept(std::declval<base_base_t &>() != std::declval<sentinel_type &>()) &&
374  noexcept(fun(std::declval<reference>())))
375  {
376  if (at_end_gracefully)
377  return true;
378 
379  if (*this->this_to_base() == rhs)
380  {
381  if constexpr (or_throw)
382  throw unexpected_end_of_input{"Reached end of input before functor evaluated to true."};
383  else
384  return true;
385  }
386 
387  return fun(**this);
388  }
389 
391  friend bool operator==(sentinel_type const & lhs, basic_consume_iterator const & rhs)
392  noexcept(noexcept(rhs == lhs))
393  {
394  return rhs == lhs;
395  }
396 
398  bool operator!=(sentinel_type const & rhs) const
399  noexcept(noexcept(std::declval<basic_consume_iterator &>() == rhs))
400  {
401  return !(*this == rhs);
402  }
403 
405  friend bool operator!=(sentinel_type const & lhs, basic_consume_iterator const & rhs)
406  noexcept(noexcept(rhs != lhs))
407  {
408  return rhs != lhs;
409  }
411 };
412 
414 template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
415 template <bool is_const_range>
416 class view_take_until<urng_t, fun_t, or_throw, and_consume>::basic_sentinel
417 {
418 private:
420  using urng_base_type = std::conditional_t<is_const_range, std::add_const_t<urng_t>, urng_t>;
422  using urng_sentinel_type = std::ranges::sentinel_t<urng_base_type>;
424  using predicate_ref_t = std::conditional_t<is_const_range,
427 
429  urng_sentinel_type urng_sentinel{};
430 
433 
434 public:
438  basic_sentinel() = default;
439  basic_sentinel(basic_sentinel const &) = default;
440  basic_sentinel(basic_sentinel &&) = default;
441  basic_sentinel & operator=(basic_sentinel const &) = default;
442  basic_sentinel & operator=(basic_sentinel &&) = default;
443  ~basic_sentinel() = default;
444 
449  explicit basic_sentinel(urng_sentinel_type urng_sentinel, predicate_ref_t predicate) :
450  urng_sentinel{std::move(urng_sentinel)},
451  predicate{predicate}
452  {}
453 
455  basic_sentinel(basic_sentinel<!is_const_range> other)
456  requires is_const_range && std::convertible_to<std::ranges::sentinel_t<urng_t>, urng_sentinel_type>
457  : urng_sentinel{std::move(other.urng_sentinel)},
458  predicate{other.predicate}
459  {}
461 
466  template <typename rng_t>
468  friend bool operator==(basic_iterator<rng_t> const & lhs, basic_sentinel const & rhs)
469  {
470  // Actual comparison delegated to lhs base
471  if (lhs.base() == rhs.urng_sentinel)
472  {
473  if constexpr (or_throw)
474  throw unexpected_end_of_input{"Reached end of input before functor evaluated to true."};
475  else
476  return true;
477  }
478 
479  return rhs.predicate(*lhs);
480  }
481 
483  template <typename rng_t>
484  friend bool operator==(basic_sentinel const & lhs, basic_iterator<rng_t> const & rhs)
485  {
486  return rhs == lhs;
487  }
488 
490  template <typename rng_t>
491  friend bool operator!=(basic_iterator<rng_t> const & lhs, basic_sentinel const & rhs)
492  {
493  return !(lhs == rhs);
494  }
495 
497  template <typename rng_t>
498  friend bool operator!=(basic_sentinel const & lhs, basic_iterator<rng_t> const & rhs)
499  {
500  return rhs != lhs;
501  }
503 };
504 
505 // ============================================================================
506 // take_until_fn (adaptor definition)
507 // ============================================================================
508 
512 template <bool or_throw, bool and_consume>
513 struct take_until_fn
514 {
516  template <typename fun_t>
517  constexpr auto operator()(fun_t && fun) const
518  {
519  return adaptor_from_functor{*this, std::forward<fun_t>(fun)};
520  }
521 
529  template <std::ranges::viewable_range urng_t, typename fun_t>
530  constexpr auto operator()(urng_t && urange, fun_t && fun) const
531  {
532  return view_take_until<std::views::all_t<urng_t>, fun_t, or_throw, and_consume>
533  {
534  std::views::all(std::forward<urng_t>(urange)),
535  std::forward<fun_t>(fun)
536  };
537  }
538 };
539 
540 } // namespace seqan3::detail
541 
542 // ============================================================================
543 // views::take_until (adaptor instance definition)
544 // ============================================================================
545 
546 namespace seqan3::views
547 {
548 
610 inline auto constexpr take_until = detail::take_until_fn<false, false>{};
611 
612 // ============================================================================
613 // views::take_until_or_throw (adaptor instance definition)
614 // ============================================================================
615 
624 inline auto constexpr take_until_or_throw = detail::take_until_fn<true, false>{};
625 
626 // ============================================================================
627 // views::take_until_and_consume (adaptor instance definition)
628 // ============================================================================
629 
638 inline auto constexpr take_until_and_consume = detail::take_until_fn<false, true>{};
639 
640 // ============================================================================
641 // views::take_until_or_throw_and_consume (adaptor instance definition)
642 // ============================================================================
643 
652 inline auto constexpr take_until_or_throw_and_consume = detail::take_until_fn<true, true>{};
653 
655 
656 } // namespace seqan3::views
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:638
seqan3::views
The SeqAn namespace for views.
Definition: view_iota_simd.hpp:218
type_traits
Provides C++20 additions to the type_traits header.
std::rel_ops::operator!=
T operator!=(T... args)
iterator
Provides C++20 additions to the <iterator> header.
std::input_iterator_tag
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.
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:652
seqan3::views::move
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:68
range.hpp
Provides various transformation traits used by the range module.
const_iterable_range
Specifies requirements of an input range type for which the const version of that type satisfies the ...
seqan3::semiregular_box_t
::ranges::semiregular_box_t semiregular_box_t
Utility transformation trait to get a wrapper type that models std::semiregular. Imported from ranges...
Definition: semiregular_box.hpp:35
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:610
std::iter_difference_t
iterator.hpp
Provides various transformation traits for use on iterators.
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:624
std::begin
T begin(T... args)
std
SeqAn specific customisations in the standard namespace.
std::result_of_t
std::end
T end(T... args)
semiregular_box.hpp
Provides seqan3::semiregular_box.
std::conditional_t
inherited_iterator_base.hpp
Provides the seqan3::detail::inherited_iterator_base template.
detail.hpp
Auxiliary header for the views submodule .