SeqAn3  3.0.3
The Modern C++ library for sequence analysis.
take_until_view.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/algorithm>
16 #include <seqan3/std/concepts>
17 #include <seqan3/std/iterator>
18 #include <seqan3/std/ranges>
19 #include <seqan3/std/type_traits>
20 
26 #include <seqan3/io/exception.hpp>
29 
30 namespace seqan3::detail
31 {
32 
33 // ============================================================================
34 // view_take_until
35 // ============================================================================
36 
50 template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
51 class view_take_until : public std::ranges::view_interface<view_take_until<urng_t, fun_t, or_throw, and_consume>>
52 {
53 private:
54 
55  static_assert(std::invocable<fun_t, std::ranges::range_reference_t<urng_t>>,
56  "The functor type for detail::take_until must model"
57  "std::invocable<fun_t, std::ranges::range_reference_t<urng_t>>.");
58  static_assert(std::convertible_to<std::result_of_t<fun_t&&(std::ranges::range_reference_t<urng_t>)>, bool>,
59  "The result type of the functor for detail::take_until must be a boolean.");
60 
62  urng_t urange;
63 
65  ranges::semiregular_t<fun_t> fun;
66 
68  static constexpr bool const_iterable = const_iterable_range<urng_t> &&
69  std::regular_invocable<fun_t, std::ranges::range_reference_t<urng_t>>;
70 
71  template <typename rng_t>
72  class basic_iterator;
73 
74  template <bool is_const_range>
75  class basic_sentinel;
76 
77  template <typename rng_t>
78  class basic_consume_iterator;
79 
80 private:
86  basic_consume_iterator<urng_t>,
87  basic_iterator<urng_t>>;
88 
90  using const_iterator = basic_iterator<urng_t const>;
92 
93 public:
97  view_take_until() = default;
98  constexpr view_take_until(view_take_until const & rhs) = default;
99  constexpr view_take_until(view_take_until && rhs) = default;
100  constexpr view_take_until & operator=(view_take_until const & rhs) = default;
101  constexpr view_take_until & operator=(view_take_until && rhs) = default;
102  ~view_take_until() = default;
103 
108  view_take_until(urng_t _urange, fun_t _fun)
109  : urange{std::move(_urange)}, fun{std::forward<fun_t>(_fun)}
110  {}
111 
117  template <std::ranges::viewable_range rng_t>
119  requires std::constructible_from<rng_t, std::views::all_t<rng_t>>
121  view_take_until(rng_t && _urange, fun_t _fun)
122  : view_take_until{std::views::all(std::forward<rng_t>(_urange)), std::move(_fun)}
123  {}
125 
142  iterator begin() noexcept
143  {
144  return {std::ranges::begin(urange), static_cast<fun_t &>(fun), std::ranges::end(urange)};
145  }
146 
148  const_iterator begin() const noexcept
149  requires const_iterable
150  {
151  return {std::ranges::cbegin(urange), static_cast<fun_t const &>(fun), std::ranges::cend(urange)};
152  }
153 
167  auto end() noexcept
168  {
169  if constexpr (and_consume && !std::ranges::forward_range<urng_t>)
170  return std::ranges::end(urange);
171  else
172  return basic_sentinel<false>{std::ranges::end(urange), fun};
173  }
174 
176  auto end() const noexcept
177  requires const_iterable
178  {
179  if constexpr (and_consume && !std::ranges::forward_range<urng_t>)
180  return std::ranges::cend(urange);
181  else
182  return basic_sentinel<true>{std::ranges::cend(urange), static_cast<fun_t const &>(fun)};
183  }
185 };
186 
189 template <typename urng_t, typename fun_t, bool or_throw = false, bool and_consume = false>
190 view_take_until(urng_t &&, fun_t) -> view_take_until<std::views::all_t<urng_t>, fun_t, or_throw, and_consume>;
191 
194 template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
195 template <typename rng_t>
196 class view_take_until<urng_t, fun_t, or_throw, and_consume>::basic_iterator :
197  public inherited_iterator_base<basic_iterator<rng_t>, std::ranges::iterator_t<rng_t>>
198 {
199 private:
201  using base_base_t = std::ranges::iterator_t<rng_t>;
203  using base_t = inherited_iterator_base<basic_iterator, std::ranges::iterator_t<rng_t>>;
205  using sentinel_type = std::ranges::sentinel_t<rng_t>;
212 
213 public:
218  constexpr basic_iterator() = default;
219  constexpr basic_iterator(basic_iterator const & rhs) = default;
220  constexpr basic_iterator(basic_iterator && rhs) = default;
221  constexpr basic_iterator & operator=(basic_iterator const & rhs) = default;
222  constexpr basic_iterator & operator=(basic_iterator && rhs) = default;
223  ~basic_iterator() = default;
224 
226  basic_iterator(base_base_t it) noexcept(noexcept(base_t{it})) :
227  base_t{std::move(it)}
228  {}
229 
231  basic_iterator(base_base_t it,
232  fun_ref_t _fun,
233  sentinel_type /*only used by the consuming iterator*/) noexcept(noexcept(base_t{it})) :
234  base_t{std::move(it)}, fun{_fun}
235  {}
237 };
238 
241 template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
242 template <typename rng_t>
243 class view_take_until<urng_t, fun_t, or_throw, and_consume>::basic_consume_iterator :
244  public inherited_iterator_base<basic_consume_iterator<rng_t>, std::ranges::iterator_t<rng_t>>
245 {
246 private:
248  using base_base_t = std::ranges::iterator_t<rng_t>;
250  using base_t = inherited_iterator_base<basic_consume_iterator, std::ranges::iterator_t<rng_t>>;
251 
258 
260  using sentinel_type = std::ranges::sentinel_t<rng_t>;
261 
263  sentinel_type stored_end;
264 
266  bool at_end_gracefully = false;
267 
268 public:
273  constexpr basic_consume_iterator() = default;
274  constexpr basic_consume_iterator(basic_consume_iterator const & rhs) = default;
275  constexpr basic_consume_iterator(basic_consume_iterator && rhs) = default;
276  constexpr basic_consume_iterator & operator=(basic_consume_iterator const & rhs) = default;
277  constexpr basic_consume_iterator & operator=(basic_consume_iterator && rhs) = default;
278  ~basic_consume_iterator() = default;
279 
281  basic_consume_iterator(base_base_t it,
282  fun_ref_t _fun,
283  sentinel_type sen) noexcept(noexcept(base_t{it})) :
284  base_t{std::move(it)}, fun{_fun}, stored_end{std::move(sen)}
285  {
286  if ((this->base() != stored_end) && fun(**this))
287  {
288  at_end_gracefully = true;
289  ++(*this);
290  }
291  }
293 
298  using difference_type = std::iter_difference_t<base_base_t>;
299  using value_type = std::iter_value_t<base_base_t>;
300  using reference = std::iter_reference_t<base_base_t>;
301  using pointer = detail::iter_pointer_t<base_base_t>;
302  using iterator_category = std::input_iterator_tag;
304 
310  basic_consume_iterator & operator++()
311  noexcept(noexcept(++std::declval<base_t &>()) &&
312  noexcept(std::declval<base_base_t &>() != std::declval<sentinel_type &>()) &&
313  noexcept(fun(std::declval<reference>())))
314  {
315  base_t::operator++();
316 
317  while ((this->base() != stored_end) && fun(**this))
318  {
319  at_end_gracefully = true;
320  base_t::operator++();
321  }
322 
323  return *this;
324  }
325 
327  basic_consume_iterator operator++(int)
328  noexcept(noexcept(++std::declval<basic_consume_iterator &>()) &&
329  std::is_nothrow_copy_constructible_v<basic_consume_iterator>)
330  {
331  basic_consume_iterator cpy{*this};
332  ++(*this);
333  return cpy;
334  }
336 
341  bool operator==(sentinel_type const & rhs) const
342  noexcept(!or_throw &&
343  noexcept(std::declval<base_base_t &>() != std::declval<sentinel_type &>()) &&
344  noexcept(fun(std::declval<reference>())))
345  {
346  if (at_end_gracefully)
347  return true;
348 
349  if (this->base() == rhs)
350  {
351  if constexpr (or_throw)
352  throw unexpected_end_of_input{"Reached end of input before functor evaluated to true."};
353  else
354  return true;
355  }
356 
357  return fun(**this);
358  }
359 
361  friend bool operator==(sentinel_type const & lhs, basic_consume_iterator const & rhs)
362  noexcept(noexcept(rhs == lhs))
363  {
364  return rhs == lhs;
365  }
366 
368  bool operator!=(sentinel_type const & rhs) const
369  noexcept(noexcept(std::declval<basic_consume_iterator &>() == rhs))
370  {
371  return !(*this == rhs);
372  }
373 
375  friend bool operator!=(sentinel_type const & lhs, basic_consume_iterator const & rhs)
376  noexcept(noexcept(rhs != lhs))
377  {
378  return rhs != lhs;
379  }
381 };
382 
384 template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
385 template <bool is_const_range>
386 class view_take_until<urng_t, fun_t, or_throw, and_consume>::basic_sentinel
387 {
388 private:
390  using urng_base_type = std::conditional_t<is_const_range, std::add_const_t<urng_t>, urng_t>;
392  using urng_sentinel_type = std::ranges::sentinel_t<urng_base_type>;
394  using predicate_ref_t = std::conditional_t<is_const_range,
397 
399  urng_sentinel_type urng_sentinel{};
400 
403 
404 public:
408  basic_sentinel() = default;
409  basic_sentinel(basic_sentinel const &) = default;
410  basic_sentinel(basic_sentinel &&) = default;
411  basic_sentinel & operator=(basic_sentinel const &) = default;
412  basic_sentinel & operator=(basic_sentinel &&) = default;
413  ~basic_sentinel() = default;
414 
419  explicit basic_sentinel(urng_sentinel_type urng_sentinel, predicate_ref_t predicate) :
420  urng_sentinel{std::move(urng_sentinel)},
421  predicate{predicate}
422  {}
423 
425  basic_sentinel(basic_sentinel<!is_const_range> other)
426  requires is_const_range && std::convertible_to<std::ranges::sentinel_t<urng_t>, urng_sentinel_type>
427  : urng_sentinel{std::move(other.urng_sentinel)},
428  predicate{other.predicate}
429  {}
431 
437  template <typename rng_t>
438  friend bool operator==(basic_iterator<rng_t> const & lhs, basic_sentinel const & rhs)
439  {
440  // Actual comparison delegated to lhs base
441  if (lhs.base() == rhs.urng_sentinel)
442  {
443  if constexpr (or_throw)
444  throw unexpected_end_of_input{"Reached end of input before functor evaluated to true."};
445  else
446  return true;
447  }
448 
449  return rhs.predicate(*lhs);
450  }
451 
453  template <typename rng_t>
454  friend bool operator==(basic_sentinel const & lhs, basic_iterator<rng_t> const & rhs)
455  {
456  return rhs == lhs;
457  }
458 
460  template <typename rng_t>
461  friend bool operator!=(basic_iterator<rng_t> const & lhs, basic_sentinel const & rhs)
462  {
463  return !(lhs == rhs);
464  }
465 
467  template <typename rng_t>
468  friend bool operator!=(basic_sentinel const & lhs, basic_iterator<rng_t> const & rhs)
469  {
470  return rhs != lhs;
471  }
473 };
474 
475 // ============================================================================
476 // take_until_fn (adaptor definition)
477 // ============================================================================
478 
482 template <bool or_throw, bool and_consume>
483 struct take_until_fn
484 {
486  template <typename fun_t>
487  constexpr auto operator()(fun_t && fun) const
488  {
489  return adaptor_from_functor{*this, std::forward<fun_t>(fun)};
490  }
491 
499  template <std::ranges::viewable_range urng_t, typename fun_t>
500  constexpr auto operator()(urng_t && urange, fun_t && fun) const
501  {
502  return view_take_until<std::views::all_t<urng_t>, fun_t, or_throw, and_consume>
503  {
504  std::views::all(std::forward<urng_t>(urange)),
505  std::forward<fun_t>(fun)
506  };
507  }
508 };
509 
510 } // namespace seqan3::detail
511 
512 // ============================================================================
513 // detail::take_until (adaptor instance definition)
514 // ============================================================================
515 
516 namespace seqan3::detail
517 {
518 
580 inline auto constexpr take_until = take_until_fn<false, false>{};
581 
582 // ============================================================================
583 // detail::take_until_or_throw (adaptor instance definition)
584 // ============================================================================
585 
594 inline auto constexpr take_until_or_throw = take_until_fn<true, false>{};
595 
596 // ============================================================================
597 // detail::take_until_and_consume (adaptor instance definition)
598 // ============================================================================
599 
608 inline auto constexpr take_until_and_consume = take_until_fn<false, true>{};
609 
610 // ============================================================================
611 // detail::take_until_or_throw_and_consume (adaptor instance definition)
612 // ============================================================================
613 
622 inline auto constexpr take_until_or_throw_and_consume = take_until_fn<true, true>{};
623 
625 
626 } // namespace seqan3::detail
627 
628 #ifdef SEQAN3_DEPRECATED_310
629 namespace seqan3::views
630 {
631 
638 
646 
654 
661 SEQAN3_DEPRECATED_310 inline auto constexpr take_until_or_throw_and_consume = detail::take_until_fn<true, true>{};
662 
663 } // namespace seqan3::views
664 #endif // SEQAN3_DEPRECATED_310
Provides seqan3::detail::adaptor_from_functor.
Adaptations of algorithms from the Ranges TS.
T begin(T... args)
The Concepts library.
Provides the seqan3::detail::inherited_iterator_base template.
Provides various transformation traits used by the range module.
T end(T... args)
T forward(T... args)
::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
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_view.hpp:645
constexpr auto take_until
A view adaptor that returns elements from the underlying range until the functor evaluates to true (o...
Definition: take_until_view.hpp:637
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_view.hpp:661
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:74
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_view.hpp:653
Specifies requirements of an input range type for which the const version of that type satisfies the ...
Provides exceptions used in the I/O module.
Provides various transformation traits for use on iterators.
Provides C++20 additions to the <iterator> header.
The SeqAn namespace for views.
Definition: char_to.hpp:22
SeqAn specific customisations in the standard namespace.
T operator!=(T... args)
#define SEQAN3_DEPRECATED_310
Deprecation message for SeqAn 3.1.0 release.
Definition: platform.hpp:203
Adaptations of concepts from the Ranges TS.
Provides seqan3::semiregular_box.
Provides C++20 additions to the type_traits header.
Additional non-standard concepts for ranges.
Provides seqan3::detail::transformation_trait_or.