32 namespace seqan3::detail
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>>
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.");
67 ranges::semiregular_t<fun_t> fun;
71 std::regular_invocable<fun_t, std::ranges::range_reference_t<urng_t>>;
73 template <
typename rng_t>
76 template <
bool is_const_range>
79 template <
typename rng_t>
80 class basic_consume_iterator;
88 basic_consume_iterator<urng_t>,
89 basic_iterator<urng_t>>;
92 using const_iterator = basic_iterator<urng_t const>;
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;
110 view_take_until(urng_t _urange, fun_t _fun)
111 : urange{
std::move(_urange)}, fun{std::forward<fun_t>(_fun)}
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)}
144 iterator
begin() noexcept
146 return {
std::ranges::begin(urange),
static_cast<fun_t &
>(fun), std::ranges::end(urange)};
150 const_iterator
begin() const noexcept
151 requires const_iterable
153 return {
std::ranges::cbegin(urange),
static_cast<fun_t
const &
>(fun), std::ranges::cend(urange)};
171 if constexpr (and_consume && !std::ranges::forward_range<urng_t>)
172 return std::ranges::end(urange);
174 return basic_sentinel<false>{std::ranges::end(urange), fun};
178 auto end() const noexcept
179 requires const_iterable
181 if constexpr (and_consume && !std::ranges::forward_range<urng_t>)
182 return std::ranges::cend(urange);
184 return basic_sentinel<true>{std::ranges::cend(urange),
static_cast<fun_t
const &
>(fun)};
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>;
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>>
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>;
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;
228 basic_iterator(base_base_t it) noexcept(noexcept(base_t{it})) :
233 basic_iterator(base_base_t it,
235 sentinel_type ) noexcept(noexcept(base_t{it})) :
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>;
260 base_base_t base() const
262 requires
std::copy_constructible<base_base_t>
265 return *this->this_to_base();
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>>
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>>;
290 using sentinel_type = std::ranges::sentinel_t<rng_t>;
293 sentinel_type stored_end;
296 bool at_end_gracefully =
false;
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;
311 basic_consume_iterator(base_base_t it,
313 sentinel_type sen) noexcept(noexcept(base_t{it})) :
316 if ((*this->this_to_base() != stored_end) && fun(**
this))
318 at_end_gracefully =
true;
331 using pointer = detail::iter_pointer_t<base_base_t>;
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>())))
345 base_t::operator++();
347 while ((*this->this_to_base() != stored_end) && fun(**
this))
349 at_end_gracefully =
true;
350 base_t::operator++();
357 basic_consume_iterator operator++(
int)
358 noexcept(noexcept(++std::declval<basic_consume_iterator &>()) &&
359 std::is_nothrow_copy_constructible_v<basic_consume_iterator>)
361 basic_consume_iterator cpy{*
this};
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>())))
376 if (at_end_gracefully)
379 if (*this->this_to_base() == rhs)
381 if constexpr (or_throw)
382 throw unexpected_end_of_input{
"Reached end of input before functor evaluated to true."};
391 friend bool operator==(sentinel_type
const & lhs, basic_consume_iterator
const & rhs)
392 noexcept(noexcept(rhs == lhs))
398 bool operator!=(sentinel_type
const & rhs)
const
399 noexcept(noexcept(std::declval<basic_consume_iterator &>() == rhs))
401 return !(*
this == rhs);
405 friend bool operator!=(sentinel_type
const & lhs, basic_consume_iterator
const & rhs)
406 noexcept(noexcept(rhs != lhs))
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
422 using urng_sentinel_type = std::ranges::sentinel_t<urng_base_type>;
429 urng_sentinel_type urng_sentinel{};
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;
449 explicit basic_sentinel(urng_sentinel_type urng_sentinel, predicate_ref_t predicate) :
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}
466 template <
typename rng_t>
468 friend bool operator==(basic_iterator<rng_t>
const & lhs, basic_sentinel
const & rhs)
471 if (lhs.base() == rhs.urng_sentinel)
473 if constexpr (or_throw)
474 throw unexpected_end_of_input{
"Reached end of input before functor evaluated to true."};
479 return rhs.predicate(*lhs);
483 template <
typename rng_t>
484 friend bool operator==(basic_sentinel
const & lhs, basic_iterator<rng_t>
const & rhs)
490 template <
typename rng_t>
491 friend bool operator!=(basic_iterator<rng_t>
const & lhs, basic_sentinel
const & rhs)
493 return !(lhs == rhs);
497 template <
typename rng_t>
498 friend bool operator!=(basic_sentinel
const & lhs, basic_iterator<rng_t>
const & rhs)
512 template <
bool or_throw,
bool and_consume>
516 template <
typename fun_t>
517 constexpr
auto operator()(fun_t && fun)
const
519 return adaptor_from_functor{*
this, std::forward<fun_t>(fun)};
529 template <std::ranges::viewable_range urng_t,
typename fun_t>
530 constexpr
auto operator()(urng_t && urange, fun_t && fun)
const
532 return view_take_until<std::views::all_t<urng_t>, fun_t, or_throw, and_consume>
534 std::views::all(std::forward<urng_t>(urange)),
535 std::forward<fun_t>(fun)
610 inline auto constexpr
take_until = detail::take_until_fn<false, false>{};