SeqAn3 3.3.0-rc.1
The Modern C++ library for sequence analysis.
take_until_view.hpp
Go to the documentation of this file.
1// -----------------------------------------------------------------------------------------------------
2// Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
3// Copyright (c) 2016-2022, 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 <algorithm>
16#include <concepts>
17#include <iterator>
18#include <ranges>
19#include <type_traits>
20
29
30namespace seqan3::detail
31{
32
33// ============================================================================
34// view_take_until
35// ============================================================================
36
50template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
51class view_take_until : public std::ranges::view_interface<view_take_until<urng_t, fun_t, or_throw, and_consume>>
52{
53private:
54 static_assert(std::invocable<fun_t, std::ranges::range_reference_t<urng_t>>,
55 "The functor type for detail::take_until must model"
56 "std::invocable<fun_t, std::ranges::range_reference_t<urng_t>>.");
57 static_assert(std::convertible_to<std::result_of_t<fun_t && (std::ranges::range_reference_t<urng_t>)>, bool>,
58 "The result type of the functor for detail::take_until must be a boolean.");
59
61 urng_t urange;
62
65
67 static constexpr bool const_iterable =
68 const_iterable_range<urng_t> && indirect_unary_predicate_on_range<fun_t const, urng_t const>;
69
72 template <bool const_range>
74
77 template <bool const_range>
78 class basic_sentinel;
79
82 template <bool const_range>
84
87 template <bool const_range>
88 using basic_consume_sentinel = std::default_sentinel_t;
89
90public:
94 view_take_until() = default;
95 constexpr view_take_until(view_take_until const & rhs) = default;
96 constexpr view_take_until(view_take_until && rhs) = default;
97 constexpr view_take_until & operator=(view_take_until const & rhs) = default;
98 constexpr view_take_until & operator=(view_take_until && rhs) = default;
99 ~view_take_until() = default;
100
105 view_take_until(urng_t && _urange, fun_t && _fun) :
106 urange{std::forward<urng_t>(_urange)},
107 fun{std::forward<fun_t>(_fun)}
108 {}
109
115 template <std::ranges::viewable_range rng_t>
116 requires std::constructible_from<urng_t, std::views::all_t<rng_t>>
117 view_take_until(rng_t && _urange, fun_t && _fun) :
118 view_take_until{std::views::all(std::forward<rng_t>(_urange)), std::forward<fun_t>(_fun)}
119 {}
121
138 auto begin() noexcept
139 {
140 if constexpr (and_consume && !std::ranges::forward_range<urng_t>)
142 else
144 }
145
147 auto begin() const noexcept
148 requires const_iterable
149 {
150 if constexpr (and_consume && !std::ranges::forward_range<urng_t const>)
152 else
154 }
155
169 auto end() noexcept
170 {
171 if constexpr (and_consume && !std::ranges::forward_range<urng_t>)
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 const>)
183 else
184 return basic_sentinel<true>{std::ranges::cend(urange), fun};
185 }
187};
188
191template <typename urng_t, typename fun_t, bool or_throw = false, bool and_consume = false>
192view_take_until(urng_t &&, fun_t &&) -> view_take_until<std::views::all_t<urng_t>, fun_t, or_throw, and_consume>;
193
194template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
195template <bool const_range>
196class view_take_until<urng_t, fun_t, or_throw, and_consume>::basic_consume_iterator :
197 public inherited_iterator_base<basic_consume_iterator<const_range>,
198 seqan3::detail::maybe_const_iterator_t<const_range, urng_t>>
199{
200private:
205
208
211
214
216 bool at_end_gracefully = false;
217
218public:
223 constexpr basic_consume_iterator() = default;
224 constexpr basic_consume_iterator(basic_consume_iterator const & rhs) = default;
225 constexpr basic_consume_iterator(basic_consume_iterator && rhs) = default;
226 constexpr basic_consume_iterator & operator=(basic_consume_iterator const & rhs) = default;
229
232 copyable_wrapper_t<fun_t> const & _fun,
233 underlying_sentinel_t sen) noexcept(noexcept(base_t{it})) :
234 base_t{std::move(it)},
235 fun{std::addressof(_fun)},
236 underlying_sentinel{std::move(sen)}
237 {
238 if ((this->base() != underlying_sentinel) && fun->operator()(**this))
239 {
240 at_end_gracefully = true;
241 ++(*this);
242 }
243 }
245
256
262 basic_consume_iterator & operator++() noexcept(noexcept(++std::declval<base_t &>()) && noexcept(
263 std::declval<underlying_iterator_t &>()
264 != std::declval<underlying_sentinel_t &>()) && noexcept(fun->operator()(std::declval<reference>())))
265 {
266 base_t::operator++();
267
268 while ((this->base() != underlying_sentinel) && fun->operator()(**this))
269 {
270 at_end_gracefully = true;
271 base_t::operator++();
272 }
273
274 return *this;
275 }
276
278 decltype(auto) operator++(int) noexcept(noexcept(++std::declval<basic_consume_iterator &>())
279 && (std::same_as<decltype(std::declval<underlying_iterator_t &>()++), void>
280 || std::is_nothrow_copy_constructible_v<basic_consume_iterator>))
281 {
282 // if underlying iterator is a C++20 input iterator (i.e. returns void), return void too.
283 if constexpr (std::same_as<decltype(std::declval<underlying_iterator_t &>()++), void>)
284 {
285 ++(*this);
286 }
287 else
288 {
289 basic_consume_iterator cpy{*this};
290 ++(*this);
291 return cpy;
292 }
293 }
295
300 bool operator==(basic_consume_sentinel<const_range> const &) const noexcept(!or_throw && noexcept(
301 std::declval<underlying_iterator_t &>()
302 != std::declval<underlying_sentinel_t &>()) && noexcept(fun->operator()(std::declval<reference>())))
303 {
304 if (at_end_gracefully)
305 return true;
306
307 if (this->base() == underlying_sentinel)
308 {
309 if constexpr (or_throw)
310 throw unexpected_end_of_input{"Reached end of input before functor evaluated to true."};
311 else
312 return true;
313 }
314
315 return fun->operator()(**this);
316 }
317
320 basic_consume_iterator const & rhs) noexcept(noexcept(rhs == lhs))
321 {
322 return rhs == lhs;
323 }
324
327 noexcept(noexcept(std::declval<basic_consume_iterator &>() == rhs))
328 {
329 return !(*this == rhs);
330 }
331
334 basic_consume_iterator const & rhs) noexcept(noexcept(rhs != lhs))
335 {
336 return rhs != lhs;
337 }
339};
340
341template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
342template <bool const_range>
343class view_take_until<urng_t, fun_t, or_throw, and_consume>::basic_sentinel
344{
345private:
348
350 underlying_sentinel_t underlying_sentinel{};
351
354
355public:
359 basic_sentinel() = default;
360 basic_sentinel(basic_sentinel const &) = default;
364 ~basic_sentinel() = default;
365
370 explicit basic_sentinel(underlying_sentinel_t underlying_sentinel, copyable_wrapper_t<fun_t> const & _fun) :
371 underlying_sentinel{std::move(underlying_sentinel)},
372 fun{std::addressof(_fun)}
373 {}
374
377 requires const_range && std::convertible_to<std::ranges::sentinel_t<urng_t>, underlying_sentinel_t>
378 : underlying_sentinel{std::move(other.underlying_sentinel)}, fun{other.fun}
379 {}
381
387 friend bool operator==(basic_iterator<const_range> const & lhs, basic_sentinel const & rhs)
388 {
389 // Actual comparison delegated to lhs base
390 if (lhs == rhs.underlying_sentinel)
391 {
392 if constexpr (or_throw)
393 throw unexpected_end_of_input{"Reached end of input before functor evaluated to true."};
394 else
395 return true;
396 }
397
398 return rhs.fun->operator()(*lhs);
399 }
400
402 friend bool operator==(basic_sentinel const & lhs, basic_iterator<const_range> const & rhs)
403 {
404 return rhs == lhs;
405 }
406
408 friend bool operator!=(basic_iterator<const_range> const & lhs, basic_sentinel const & rhs)
409 {
410 return !(lhs == rhs);
411 }
412
414 friend bool operator!=(basic_sentinel const & lhs, basic_iterator<const_range> const & rhs)
415 {
416 return rhs != lhs;
417 }
418
420 template <bool other_const_range = !const_range>
421 requires (std::sentinel_for<underlying_sentinel_t, basic_iterator<other_const_range>>)
422 friend bool operator==(basic_iterator<other_const_range> const & lhs, basic_sentinel const & rhs)
423 {
424 // Actual comparison delegated to lhs base
425 if (lhs == rhs.underlying_sentinel)
426 {
427 if constexpr (or_throw)
428 throw unexpected_end_of_input{"Reached end of input before functor evaluated to true."};
429 else
430 return true;
431 }
432
433 return rhs.fun->operator()(*lhs);
434 }
435
437 template <bool other_const_range = !const_range>
438 requires (std::sentinel_for<underlying_sentinel_t, basic_iterator<other_const_range>>)
439 friend bool operator==(basic_sentinel const & lhs, basic_iterator<other_const_range> const & rhs)
440 {
441 return rhs == lhs;
442 }
443
445 template <bool other_const_range = !const_range>
446 requires (std::sentinel_for<underlying_sentinel_t, basic_iterator<other_const_range>>)
447 friend bool operator!=(basic_iterator<other_const_range> const & lhs, basic_sentinel const & rhs)
448 {
449 return !(lhs == rhs);
450 }
451
453 template <bool other_const_range = !const_range>
454 requires (std::sentinel_for<underlying_sentinel_t, basic_iterator<other_const_range>>)
455 friend bool operator!=(basic_sentinel const & lhs, basic_iterator<other_const_range> const & rhs)
456 {
457 return rhs != lhs;
458 }
460};
461
462// ============================================================================
463// take_until_fn (adaptor definition)
464// ============================================================================
465
469template <bool or_throw, bool and_consume>
471{
473 template <typename fun_t>
474 constexpr auto operator()(fun_t && fun) const
475 {
476 return adaptor_from_functor{*this, std::forward<fun_t>(fun)};
477 }
478
486 template <std::ranges::viewable_range urng_t, typename fun_t>
487 constexpr auto operator()(urng_t && urange, fun_t && fun) const
488 {
489 return view_take_until<std::views::all_t<urng_t>, fun_t, or_throw, and_consume>{
490 std::views::all(std::forward<urng_t>(urange)),
491 std::forward<fun_t>(fun)};
492 }
493};
494
495} // namespace seqan3::detail
496
497// ============================================================================
498// detail::take_until (adaptor instance definition)
499// ============================================================================
500
501namespace seqan3::detail
502{
560inline constexpr auto take_until = take_until_fn<false, false>{};
561
562// ============================================================================
563// detail::take_until_or_throw (adaptor instance definition)
564// ============================================================================
565
575
576// ============================================================================
577// detail::take_until_and_consume (adaptor instance definition)
578// ============================================================================
579
589
590// ============================================================================
591// detail::take_until_or_throw_and_consume (adaptor instance definition)
592// ============================================================================
593
603
604} // namespace seqan3::detail
Provides seqan3::detail::adaptor_from_functor.
T addressof(T... args)
T begin(T... args)
Template for range adaptor closure objects that store arguments and wrap a proto-adaptor.
Definition: adaptor_from_functor.hpp:57
Utility wrapper that behaves like std::optional but makes the type conform with the std::copyable con...
Definition: copyable_wrapper.hpp:37
A CRTP base template for creating iterators that inherit from other iterators.
Definition: inherited_iterator_base.hpp:52
Special iterator type used when consuming behaviour is selected.
Definition: take_until_view.hpp:199
seqan3::detail::maybe_const_sentinel_t< const_range, urng_t > underlying_sentinel_t
The sentinel type is identical to that of the underlying range.
Definition: take_until_view.hpp:210
seqan3::detail::maybe_const_iterator_t< const_range, urng_t > underlying_iterator_t
The iterator type of the underlying range.
Definition: take_until_view.hpp:202
detail::iter_pointer_t< underlying_iterator_t > pointer
From base.
Definition: take_until_view.hpp:253
constexpr basic_consume_iterator & operator=(basic_consume_iterator const &rhs)=default
Defaulted.
constexpr basic_consume_iterator(basic_consume_iterator const &rhs)=default
Defaulted.
constexpr basic_consume_iterator & operator=(basic_consume_iterator &&rhs)=default
Defaulted.
basic_consume_iterator(underlying_iterator_t it, copyable_wrapper_t< fun_t > const &_fun, underlying_sentinel_t sen) noexcept(noexcept(base_t{it}))
Constructor that delegates to the CRTP layer and initialises the callable.
Definition: take_until_view.hpp:231
constexpr basic_consume_iterator(basic_consume_iterator &&rhs)=default
Defaulted.
bool operator==(basic_consume_sentinel< const_range > const &) const noexcept(!or_throw &&noexcept(std::declval< underlying_iterator_t & >() !=std::declval< underlying_sentinel_t & >()) &&noexcept(fun->operator()(std::declval< reference >())))
Return the saved at_end state.
Definition: take_until_view.hpp:300
friend bool operator!=(basic_consume_sentinel< const_range > const &lhs, basic_consume_iterator const &rhs) noexcept(noexcept(rhs !=lhs))
Return the saved at_end state.
Definition: take_until_view.hpp:333
friend bool operator==(basic_consume_sentinel< const_range > const &lhs, basic_consume_iterator const &rhs) noexcept(noexcept(rhs==lhs))
Return the saved at_end state.
Definition: take_until_view.hpp:319
bool operator!=(basic_consume_sentinel< const_range > const &rhs) const noexcept(noexcept(std::declval< basic_consume_iterator & >()==rhs))
Return the saved at_end state.
Definition: take_until_view.hpp:326
underlying_sentinel_t underlying_sentinel
Whether this iterator has reached the end (cache is only used on pure input ranges).
Definition: take_until_view.hpp:213
basic_consume_iterator & operator++() noexcept(noexcept(++std::declval< base_t & >()) &&noexcept(std::declval< underlying_iterator_t & >() !=std::declval< underlying_sentinel_t & >()) &&noexcept(fun->operator()(std::declval< reference >())))
Override pre-increment to implement consuming behaviour.
Definition: take_until_view.hpp:262
The sentinel type of take_until, provides the comparison operators.
Definition: take_until_view.hpp:344
friend bool operator!=(basic_sentinel const &lhs, basic_iterator< const_range > const &rhs)
Compares lhs with rhs for inequality.
Definition: take_until_view.hpp:414
basic_sentinel(basic_sentinel<!const_range > other) &&std
Construct from a not const range a const range.
Definition: take_until_view.hpp:376
copyable_wrapper_t< fun_t > const * fun
Pointer to the functor stored in the view.
Definition: take_until_view.hpp:353
basic_sentinel(basic_sentinel &&)=default
Defaulted.
underlying_sentinel_t underlying_sentinel
The actual end of the underlying range.
Definition: take_until_view.hpp:350
seqan3::detail::maybe_const_sentinel_t< const_range, urng_t > underlying_sentinel_t
The sentinel type of the underlying range.
Definition: take_until_view.hpp:347
friend bool operator==(basic_sentinel const &lhs, basic_iterator< const_range > const &rhs)
Compares lhs with rhs for equality.
Definition: take_until_view.hpp:402
friend bool operator==(basic_iterator< const_range > const &lhs, basic_sentinel const &rhs)
Compares lhs with rhs for equality.
Definition: take_until_view.hpp:387
basic_sentinel(underlying_sentinel_t underlying_sentinel, copyable_wrapper_t< fun_t > const &_fun)
Construct from a sentinel and a functor.
Definition: take_until_view.hpp:370
friend bool operator!=(basic_iterator< const_range > const &lhs, basic_sentinel const &rhs)
Compares lhs with rhs for inequality.
Definition: take_until_view.hpp:408
basic_sentinel & operator=(basic_sentinel const &)=default
Defaulted.
basic_sentinel & operator=(basic_sentinel &&)=default
Defaulted.
basic_sentinel(basic_sentinel const &)=default
Defaulted.
The type returned by seqan3::detail::take_until and seqan3::detail::take_until_or_throw.
Definition: take_until_view.hpp:52
constexpr view_take_until(view_take_until &&rhs)=default
Defaulted.
view_take_until(rng_t &&_urange, fun_t &&_fun)
Construct from another viewable_range.
Definition: take_until_view.hpp:117
std::default_sentinel_t basic_consume_sentinel
The sentinel type of take_until when consuming behaviour is selected.
Definition: take_until_view.hpp:88
constexpr view_take_until & operator=(view_take_until &&rhs)=default
Defaulted.
auto begin() noexcept
Returns an iterator to the first element of the container.
Definition: take_until_view.hpp:138
view_take_until()=default
Defaulted.
auto end() const noexcept
Returns an iterator to the element following the last element of the range.
Definition: take_until_view.hpp:178
view_take_until(urng_t &&_urange, fun_t &&_fun)
Construct from another range.
Definition: take_until_view.hpp:105
copyable_wrapper_t< fun_t > fun
The functor.
Definition: take_until_view.hpp:64
constexpr view_take_until & operator=(view_take_until const &rhs)=default
Defaulted.
auto begin() const noexcept
Returns an iterator to the first element of the container.
Definition: take_until_view.hpp:147
urng_t urange
The underlying range.
Definition: take_until_view.hpp:61
static constexpr bool const_iterable
Whether this view is const_iterable or not.
Definition: take_until_view.hpp:67
constexpr view_take_until(view_take_until const &rhs)=default
Defaulted.
~view_take_until()=default
Defaulted.
seqan3::detail::maybe_const_iterator_t< const_range, urng_t > basic_iterator
Iterator of the underlying range (urng_t).
Definition: take_until_view.hpp:73
view_take_until(urng_t &&, fun_t &&) -> view_take_until< std::views::all_t< urng_t >, fun_t, or_throw, and_consume >
Type deduction guide that strips references.
auto end() noexcept
Returns an iterator to the element following the last element of the range.
Definition: take_until_view.hpp:169
Provides seqan3::detail::copyable_wrapper.
Provides various transformation traits used by the range module.
std::ranges::sentinel_t< maybe_const_range_t< const_v, range_t > > maybe_const_sentinel_t
Returns the const sentinel of range_t if const_range is true; otherwise the non-const sentinel.
Definition: core/range/type_traits.hpp:49
std::ranges::iterator_t< maybe_const_range_t< const_range, range_t > > maybe_const_iterator_t
Returns the const iterator of range_t if const_range is true; otherwise the non-const iterator.
Definition: core/range/type_traits.hpp:44
typename iter_pointer< it_t >::type iter_pointer_t
Return the pointer type of the input type (transformation_trait shortcut).
Definition: iterator_traits.hpp:166
constexpr auto all
Returns a view that includes all elements of the range argument.
Definition: all_view.hpp:204
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:560
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:602
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:588
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:574
Provides the seqan3::detail::inherited_iterator_base template.
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.
The internal SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
SeqAn specific customisations in the standard namespace.
View adaptor definition for detail::take_until and detail::take_until_or_throw.
Definition: take_until_view.hpp:471
constexpr auto operator()(fun_t &&fun) const
Store the arguments and return a range adaptor closure object.
Definition: take_until_view.hpp:474
constexpr auto operator()(urng_t &&urange, fun_t &&fun) const
Call the view's constructor with the given parameters.
Definition: take_until_view.hpp:487
Thrown if I/O was expecting more input (e.g. a delimiter or a new line), but the end of input was rea...
Definition: io/exception.hpp:78
Provides seqan3::detail::transformation_trait_or.
Additional non-standard concepts for ranges.