15 #include <range/v3/algorithm/copy.hpp>
34 namespace seqan3::detail
54 template <std::ranges::view urng_t,
bool exactly,
bool or_throw>
55 class view_take :
public std::ranges::view_interface<view_take<urng_t, exactly, or_throw>>
66 template <
typename rng_t>
67 class iterator_type :
public inherited_iterator_base<iterator_type<rng_t>, std::ranges::iterator_t<rng_t>>
71 using base_base_t = std::ranges::iterator_t<rng_t>;
73 using base_t = inherited_iterator_base<iterator_type, std::ranges::iterator_t<rng_t>>;
76 using sentinel_type = std::ranges::sentinel_t<urng_t>;
92 constexpr iterator_type() =
default;
93 constexpr iterator_type(iterator_type
const & rhs) =
default;
94 constexpr iterator_type(iterator_type && rhs) =
default;
95 constexpr iterator_type & operator=(iterator_type
const & rhs) =
default;
96 constexpr iterator_type & operator=(iterator_type && rhs) =
default;
97 ~iterator_type() =
default;
100 constexpr iterator_type(base_base_t
const & it) noexcept(noexcept(base_t{it})) :
105 constexpr iterator_type(base_base_t it,
size_t const _pos,
size_t const _max_pos, view_take * host =
nullptr) noexcept(noexcept(base_t{it})) :
106 base_t{
std::move(it)}, pos{_pos}, max_pos(_max_pos)
126 using iterator_category = iterator_tag_t<base_base_t>;
134 constexpr iterator_type & operator++() noexcept(noexcept(++
std::declval<base_t &>()))
137 base_t::operator++();
139 if constexpr (exactly && !std::forward_iterator<base_base_t>)
140 --host_ptr->target_size;
145 constexpr iterator_type operator++(
int) noexcept(noexcept(++std::declval<iterator_type &>()) &&
146 std::is_nothrow_copy_constructible_v<iterator_type>)
148 iterator_type cpy{*
this};
154 constexpr iterator_type & operator--() noexcept(noexcept(--
std::declval<base_base_t &>()))
156 requires
std::bidirectional_iterator<base_base_t>
159 base_t::operator--();
165 constexpr iterator_type operator--(
int) noexcept(noexcept(--std::declval<iterator_type &>()) &&
166 std::is_nothrow_copy_constructible_v<iterator_type>)
168 requires std::bidirectional_iterator<base_base_t>
171 iterator_type cpy{*
this};
177 constexpr iterator_type & operator+=(difference_type
const skip) noexcept(noexcept(std::declval<base_t &>() += skip))
179 requires std::random_access_iterator<base_base_t>
182 base_t::operator+=(skip);
188 constexpr iterator_type & operator-=(difference_type
const skip) noexcept(noexcept(std::declval<base_t &>() -= skip))
190 requires std::random_access_iterator<base_base_t>
193 base_t::operator-=(skip);
204 constexpr
bool operator==(iterator_type
const & rhs)
const
206 noexcept(!or_throw && noexcept(std::declval<base_base_t &>() == std::declval<base_base_t &>()))
208 requires
std::forward_iterator<base_base_t>
211 return *base_t::this_to_base() == *rhs.this_to_base();
215 constexpr
bool operator==(sentinel_type
const & rhs)
const
216 noexcept(!or_throw && noexcept(std::declval<base_base_t const &>() == std::declval<sentinel_type const &>()))
221 if (*base_t::this_to_base() == rhs)
223 if constexpr (or_throw)
224 throw unexpected_end_of_input{
"Reached end of input before designated size."};
235 constexpr
friend bool operator==(sentinel_type
const & lhs, iterator_type
const & rhs) noexcept(noexcept(rhs == lhs))
241 constexpr
bool operator!=(sentinel_type
const & rhs)
const
242 noexcept(noexcept(std::declval<iterator_type &>() == rhs))
244 return !(*
this == rhs);
248 constexpr
bool operator!=(iterator_type
const & rhs)
const
249 noexcept(noexcept(std::declval<iterator_type &>() == rhs))
251 requires std::forward_iterator<base_base_t>
254 return !(*
this == rhs);
258 constexpr
friend bool operator!=(sentinel_type
const & lhs, iterator_type
const & rhs) noexcept(noexcept(rhs != lhs))
274 noexcept(noexcept(std::declval<base_base_t &>()[0]))
276 requires
std::random_access_iterator<base_base_t>
279 return base_base_t::operator[](n);
287 using reference = reference_t<urng_t>;
290 using const_reference = detail::transformation_trait_or_t<seqan3::reference<urng_t const>,
void>;
292 using value_type = value_type_t<urng_t>;
295 transformation_trait_or_t<seqan3::size_type<urng_t>,
size_t>,
298 using difference_type = difference_type_t<urng_t>;
300 using iterator = iterator_type<urng_t>;
302 using const_iterator = detail::transformation_trait_or_t<std::type_identity<iterator_type<urng_t const>>,
void>;
309 constexpr view_take() =
default;
310 constexpr view_take(view_take
const & rhs) =
default;
311 constexpr view_take(view_take && rhs) =
default;
312 constexpr view_take & operator=(view_take
const & rhs) =
default;
313 constexpr view_take & operator=(view_take && rhs) =
default;
314 ~view_take() =
default;
321 constexpr view_take(urng_t _urange,
size_t const _size)
322 : urange{
std::move(_urange)}, target_size{_size}
324 if constexpr (std::ranges::sized_range<urng_t>)
328 if constexpr (exactly && or_throw)
332 "You are trying to construct a views::take_exactly_or_throw from a range that is strictly "
350 template <std::ranges::viewable_range rng_t>
354 constexpr view_take(rng_t && _urange,
size_t const _size)
375 constexpr
auto begin() noexcept
377 if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
384 constexpr
auto begin() const noexcept
387 if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
394 constexpr
auto cbegin() const noexcept
397 if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
416 constexpr
auto end() noexcept
418 if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
421 return std::ranges::end(urange);
425 constexpr
auto end() const noexcept
428 if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
431 return std::ranges::cend(urange);
435 constexpr
auto cend() const noexcept
438 if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
441 return std::ranges::cend(urange);
459 constexpr size_type
size() const noexcept
460 requires exactly ||
std::ranges::sized_range<urng_t>
468 template <
typename urng_t,
469 bool exactly =
false,
470 bool or_throw =
false>
471 view_take(urng_t && ,
size_t) -> view_take<std::ranges::all_view<urng_t>, exactly, or_throw>;
480 template <
bool exactly,
bool or_throw>
484 constexpr
auto operator()(
size_t const size)
const
486 return adaptor_from_functor{*
this,
size};
492 template <std::ranges::range urng_t>
493 constexpr
auto operator()(urng_t && urange,
size_t target_size)
const
495 static_assert(std::ranges::viewable_range<urng_t>,
496 "The views::take adaptor can only be passed viewable_ranges, i.e. Views or &-to-non-View.");
499 if constexpr (std::ranges::sized_range<urng_t>)
501 if constexpr (or_throw)
506 "range that is strictly smaller."};
518 return urange.substr(0, target_size);
521 else if constexpr (is_type_specialisation_of_v<remove_cvref_t<urng_t>,
std::basic_string> &&
528 std::ranges::contiguous_range<urng_t> &&
529 std::ranges::sized_range<urng_t>)
531 return std::span{std::ranges::data(urange), target_size};
535 std::ranges::random_access_range<urng_t> &&
536 std::ranges::sized_range<urng_t>)
538 return std::ranges::subrange<std::ranges::iterator_t<urng_t>, std::ranges::iterator_t<urng_t>>
548 return view_take<std::ranges::all_view<urng_t>, exactly, or_throw>
550 std::forward<urng_t>(urange),
624 inline auto constexpr
take = detail::take_fn<false, false>{};