SeqAn3 3.1.0
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>
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
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
80private:
86 basic_consume_iterator<urng_t>,
87 basic_iterator<urng_t>>;
88
90 using const_iterator = basic_iterator<urng_t const>;
92
93public:
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
189template <typename urng_t, typename fun_t, bool or_throw = false, bool and_consume = false>
190view_take_until(urng_t &&, fun_t) -> view_take_until<std::views::all_t<urng_t>, fun_t, or_throw, and_consume>;
191
194template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
195template <typename rng_t>
196class 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{
199private:
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
213public:
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
241template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
242template <typename rng_t>
243class 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{
246private:
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
268public:
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
384template <std::ranges::view urng_t, typename fun_t, bool or_throw, bool and_consume>
385template <bool is_const_range>
386class view_take_until<urng_t, fun_t, or_throw, and_consume>::basic_sentinel
387{
388private:
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
404public:
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
482template <bool or_throw, bool and_consume>
483struct 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
516namespace seqan3::detail
517{
575inline auto constexpr take_until = take_until_fn<false, false>{};
576
577// ============================================================================
578// detail::take_until_or_throw (adaptor instance definition)
579// ============================================================================
580
589inline auto constexpr take_until_or_throw = take_until_fn<true, false>{};
590
591// ============================================================================
592// detail::take_until_and_consume (adaptor instance definition)
593// ============================================================================
594
603inline auto constexpr take_until_and_consume = take_until_fn<false, true>{};
604
605// ============================================================================
606// detail::take_until_or_throw_and_consume (adaptor instance definition)
607// ============================================================================
608
617inline auto constexpr take_until_or_throw_and_consume = take_until_fn<true, true>{};
618
619} // namespace seqan3::detail
Provides seqan3::detail::adaptor_from_functor.
The <algorithm> header from C++20's standard library.
T begin(T... args)
The <concepts> header from C++20's standard library.
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
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 <iterator> header from C++20's standard library.
SeqAn specific customisations in the standard namespace.
T operator!=(T... args)
The <ranges> header from C++20's standard library.
Provides seqan3::semiregular_box.
Provides seqan3::detail::transformation_trait_or.
The <type_traits> header from C++20's standard library.
Additional non-standard concepts for ranges.