SeqAn3 3.4.0-rc.1
The Modern C++ library for sequence analysis.
Loading...
Searching...
No Matches
take_exactly_view.hpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2006-2024 Knut Reinert & Freie Universität Berlin
2// SPDX-FileCopyrightText: 2016-2024 Knut Reinert & MPI für molekulare Genetik
3// SPDX-License-Identifier: BSD-3-Clause
4
10#pragma once
11
12#include <algorithm>
13#include <concepts>
14#include <iterator>
15#include <ranges>
16#include <span>
17#include <type_traits>
18
27
28namespace seqan3::detail
29{
30
31// ============================================================================
32// view_take_exactly
33// ============================================================================
34
48template <std::ranges::view urng_t, bool or_throw>
49class view_take_exactly : public std::ranges::view_interface<view_take_exactly<urng_t, or_throw>>
50{
51private:
53 urng_t urange;
54
57
59 template <bool const_range>
60 class basic_iterator;
61
62private:
75
76public:
80 view_take_exactly() = default;
81 view_take_exactly(view_take_exactly const & rhs) = default;
85 ~view_take_exactly() = default;
86
92 constexpr view_take_exactly(urng_t _urange, size_t const _size) : urange{std::move(_urange)}, target_size{_size}
93 {
94 if constexpr (std::ranges::sized_range<urng_t>)
95 {
96 if (std::ranges::size(urange) < target_size)
97 {
98 if constexpr (or_throw)
99 {
101 "You are trying to construct a detail::take_exactly_or_throw from a range that is strictly "
102 "smaller."};
103 }
104 else
105 {
106 target_size = std::ranges::size(urange);
107 }
108 }
109 }
110 }
111
118 template <std::ranges::viewable_range rng_t>
119 requires std::constructible_from<rng_t, std::views::all_t<rng_t>>
120 constexpr view_take_exactly(rng_t && _urange, size_t const _size) :
121 view_take_exactly{std::views::all(std::forward<rng_t>(_urange)), _size}
122 {}
124
141 constexpr auto begin() noexcept
142 {
143 if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
145 else
147 }
148
150 constexpr auto begin() const noexcept
151 requires const_iterable_range<urng_t> && std::ranges::forward_range<urng_t>
152 {
153 if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
155 else
156 {
157 // const_iterator does not work if the underlying iterator is a std::input_iterator (it needs to access
158 // target_size)
160 }
161 }
162
176 constexpr auto end() noexcept
177 {
178 if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
180 else
181 return std::ranges::end(urange);
182 }
183
185 constexpr auto end() const noexcept
186 requires const_iterable_range<urng_t> && std::ranges::forward_range<urng_t>
187 {
188 if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
190 else
191 return std::ranges::cend(urange);
192 }
194
206 constexpr auto size() const noexcept
207 {
208 return target_size;
209 }
210};
211
214template <typename urng_t, bool or_throw = false>
216
219template <std::ranges::view urng_t, bool or_throw>
220template <bool const_range>
221class view_take_exactly<urng_t, or_throw>::basic_iterator :
222 public inherited_iterator_base<basic_iterator<const_range>, maybe_const_iterator_t<const_range, urng_t>>
223{
224private:
229
232
234 size_t pos{};
235
237 size_t max_pos{};
238
241
242public:
247 basic_iterator() = default;
248 basic_iterator(basic_iterator const & rhs) = default;
249 basic_iterator(basic_iterator && rhs) = default;
250 basic_iterator & operator=(basic_iterator const & rhs) = default;
252 ~basic_iterator() = default;
253
255 constexpr basic_iterator(base_base_t it) noexcept(noexcept(base_t{it})) : base_t{std::move(it)}
256 {}
257
260 size_t const _pos,
261 size_t const _max_pos,
262 view_take_exactly * host = nullptr) noexcept(noexcept(base_t{it})) :
263 base_t{std::move(it)},
264 pos{_pos},
265 max_pos(_max_pos)
266 {
267 host_ptr = host;
268
269 if constexpr (!std::forward_iterator<base_base_t>)
270 {
271 assert(host_ptr != nullptr);
272 }
273 }
275
276 using typename base_t::difference_type;
277 using typename base_t::reference;
278
285 constexpr basic_iterator & operator++() noexcept(noexcept(++std::declval<base_t &>()))
286 {
287 base_t::operator++();
288 ++pos;
289 if constexpr (!std::forward_iterator<base_base_t>)
290 --host_ptr->target_size;
291 return *this;
292 }
293
295 constexpr decltype(auto) operator++(int) noexcept(noexcept(++std::declval<basic_iterator &>())
296 && (std::same_as<decltype(std::declval<base_base_t &>()++), void>
297 || std::is_nothrow_copy_constructible_v<basic_iterator>))
298 {
299 // if underlying iterator is a C++20 input iterator (i.e. returns void), return void too.
300 if constexpr (std::same_as<decltype(std::declval<base_base_t &>()++), void>)
301 {
302 ++(*this);
303 }
304 else
305 {
306 basic_iterator cpy{*this};
307 ++(*this);
308 return cpy;
309 }
310 }
311
313 constexpr basic_iterator & operator--() noexcept(noexcept(--std::declval<base_base_t &>()))
314 requires std::bidirectional_iterator<base_base_t>
315 {
316 base_t::operator--();
317 --pos;
318 return *this;
319 }
320
322 constexpr basic_iterator operator--(int) noexcept(noexcept(--std::declval<basic_iterator &>())
323 && std::is_nothrow_copy_constructible_v<basic_iterator>)
324 requires std::bidirectional_iterator<base_base_t>
325 {
326 basic_iterator cpy{*this};
327 --(*this);
328 return cpy;
329 }
330
332 constexpr basic_iterator & operator+=(difference_type const skip) noexcept(noexcept(std::declval<base_t &>() +=
333 skip))
334 requires std::random_access_iterator<base_base_t>
335 {
336 base_t::operator+=(skip);
337 pos += skip;
338 return *this;
339 }
340
342 constexpr basic_iterator & operator-=(difference_type const skip) noexcept(noexcept(std::declval<base_t &>() -=
343 skip))
344 requires std::random_access_iterator<base_base_t>
345 {
346 base_t::operator-=(skip);
347 pos -= skip;
348 return *this;
349 }
351
358 constexpr bool operator==(basic_iterator const & rhs) const
359 noexcept(!or_throw && noexcept(std::declval<base_base_t &>() == std::declval<base_base_t &>()))
360 requires std::forward_iterator<base_base_t>
361 {
362 return this->base() == rhs.base();
363 }
364
366 constexpr bool operator==(sentinel_type const & rhs) const
367 noexcept(!or_throw && noexcept(std::declval<base_base_t const &>() == std::declval<sentinel_type const &>()))
368 {
369 if (pos >= max_pos)
370 return true;
371
372 if (this->base() == rhs)
373 {
374 if constexpr (or_throw)
375 throw unexpected_end_of_input{"Reached end of input before designated size."};
376
377 return true;
378 }
379 else
380 {
381 return false;
382 }
383 }
384
386 constexpr friend bool operator==(sentinel_type const & lhs,
387 basic_iterator const & rhs) noexcept(noexcept(rhs == lhs))
388 {
389 return rhs == lhs;
390 }
391
393 constexpr bool operator!=(sentinel_type const & rhs) const
394 noexcept(noexcept(std::declval<basic_iterator &>() == rhs))
395 {
396 return !(*this == rhs);
397 }
398
400 constexpr bool operator!=(basic_iterator const & rhs) const
401 noexcept(noexcept(std::declval<basic_iterator &>() == rhs))
402 requires std::forward_iterator<base_base_t>
403 {
404 return !(*this == rhs);
405 }
406
408 constexpr friend bool operator!=(sentinel_type const & lhs,
409 basic_iterator const & rhs) noexcept(noexcept(rhs != lhs))
410 {
411 return rhs != lhs;
412 }
414
425 noexcept(noexcept(std::declval<base_base_t &>()[0]))
426 requires std::random_access_iterator<base_base_t>
427 {
428 return base_t::operator[](n);
429 }
431};
432
433// ============================================================================
434// take_fn (adaptor definition)
435// ============================================================================
436
440template <bool or_throw>
442{
444 constexpr auto operator()(size_t const size) const
445 {
446 return adaptor_from_functor{*this, size};
447 }
448
452 template <std::ranges::range urng_t>
453 constexpr auto operator()(urng_t && urange, size_t target_size) const
454 {
455 static_assert(std::ranges::viewable_range<urng_t>,
456 "The views::take adaptor can only be passed viewable_ranges, i.e. Views or &-to-non-View.");
457
458 // safeguard against wrong size
459 if constexpr (std::ranges::sized_range<urng_t>)
460 {
461 if constexpr (or_throw)
462 {
463 if (target_size > std::ranges::size(urange))
464 {
465 throw std::invalid_argument{"You are trying to construct a detail::take_exactly_or_throw from a "
466 "range that is strictly smaller."};
467 }
468 }
469 else
470 {
471 target_size = std::min<size_t>(target_size, std::ranges::size(urange));
472 }
473 }
474
475 // string_view
476 if constexpr (is_type_specialisation_of_v<std::remove_cvref_t<urng_t>, std::basic_string_view>)
477 {
478 // in standard
479 return urange.substr(0, target_size);
480 }
481 // string const &
482 else if constexpr (is_type_specialisation_of_v<std::remove_cvref_t<urng_t>, std::basic_string>
483 && std::is_const_v<std::remove_reference_t<urng_t>>)
484 {
485 // not in standard
486 // seqan3::views::type_reduce does this too
487 return std::basic_string_view{std::ranges::data(urange), target_size};
488 }
489 // contiguous
490 else if constexpr (std::ranges::borrowed_range<urng_t> && std::ranges::contiguous_range<urng_t>
491 && std::ranges::sized_range<urng_t>)
492 {
493 // not in standard (special case for std::span in standard)
494 // seqan3::views::type_reduce does this too
495 return std::span{std::ranges::data(urange), target_size};
496 }
497 // random_access
498 else if constexpr (std::ranges::borrowed_range<urng_t> && std::ranges::random_access_range<urng_t>
499 && std::ranges::sized_range<urng_t>)
500 {
501 // not in standard
502 // seqan3::views::type_reduce does this too
503 return std::ranges::subrange<std::ranges::iterator_t<urng_t>, std::ranges::iterator_t<urng_t>>{
504 std::ranges::begin(urange),
505 std::ranges::begin(urange) + target_size,
506 target_size};
507 }
508 // our type
509 else
510 {
511 return view_take_exactly<std::views::all_t<urng_t>, or_throw>{std::forward<urng_t>(urange), target_size};
512 }
513 }
514};
515
516} // namespace seqan3::detail
517
518// ============================================================================
519// detail::take_exactly (adaptor instance definition)
520// ============================================================================
521
522namespace seqan3::detail
523{
573inline constexpr auto take_exactly = take_exactly_fn<false>{};
574
575// ============================================================================
576// detail::take_exactly_or_throw (adaptor instance definition)
577// ============================================================================
578
588} // namespace seqan3::detail
Provides seqan3::detail::adaptor_from_functor.
T begin(T... args)
Template for range adaptor closure objects that store arguments and wrap a proto-adaptor.
Definition adaptor_from_functor.hpp:54
A CRTP base template for creating iterators that inherit from other iterators.
Definition inherited_iterator_base.hpp:49
The forward declared iterator type.
Definition take_exactly_view.hpp:223
constexpr basic_iterator(base_base_t it) noexcept(noexcept(base_t{it}))
Constructor that delegates to the CRTP layer.
Definition take_exactly_view.hpp:255
basic_iterator(basic_iterator &&rhs)=default
Defaulted.
constexpr basic_iterator & operator--() noexcept(noexcept(--std::declval< base_base_t & >()))
Decrements the iterator by one.
Definition take_exactly_view.hpp:313
constexpr bool operator!=(sentinel_type const &rhs) const noexcept(noexcept(std::declval< basic_iterator & >()==rhs))
Checks whether *this is not equal to rhs.
Definition take_exactly_view.hpp:393
constexpr basic_iterator & operator-=(difference_type const skip) noexcept(noexcept(std::declval< base_t & >() -=skip))
Advances the iterator by -skip positions.
Definition take_exactly_view.hpp:342
constexpr basic_iterator operator--(int) noexcept(noexcept(--std::declval< basic_iterator & >()) &&std::is_nothrow_copy_constructible_v< basic_iterator >)
Returns an iterator decremented by one.
Definition take_exactly_view.hpp:322
basic_iterator & operator=(basic_iterator const &rhs)=default
Defaulted.
constexpr basic_iterator & operator+=(difference_type const skip) noexcept(noexcept(std::declval< base_t & >()+=skip))
Advances the iterator by skip positions.
Definition take_exactly_view.hpp:332
constexpr friend bool operator!=(sentinel_type const &lhs, basic_iterator const &rhs) noexcept(noexcept(rhs !=lhs))
Checks whether lhs is not equal to rhs.
Definition take_exactly_view.hpp:408
maybe_const_iterator_t< const_range, urng_t > base_base_t
The iterator type of the underlying range.
Definition take_exactly_view.hpp:226
constexpr bool operator==(sentinel_type const &rhs) const noexcept(!or_throw &&noexcept(std::declval< base_base_t const & >()==std::declval< sentinel_type const & >()))
Checks whether lhs is equal to rhs.
Definition take_exactly_view.hpp:366
constexpr bool operator!=(basic_iterator const &rhs) const noexcept(noexcept(std::declval< basic_iterator & >()==rhs))
Checks whether lhs is not equal to rhs.
Definition take_exactly_view.hpp:400
basic_iterator & operator=(basic_iterator &&rhs)=default
Defaulted.
constexpr friend bool operator==(sentinel_type const &lhs, basic_iterator const &rhs) noexcept(noexcept(rhs==lhs))
Checks whether lhs is equal to rhs.
Definition take_exactly_view.hpp:386
std::conditional_t<!std::forward_iterator< base_base_t >, view_take_exactly *, detail::ignore_t > host_ptr
A pointer to host, s.t. the size of the view can shrink on pure input ranges.
Definition take_exactly_view.hpp:240
constexpr basic_iterator & operator++() noexcept(noexcept(++std::declval< base_t & >()))
Increments the iterator by one.
Definition take_exactly_view.hpp:285
constexpr reference operator[](std::make_unsigned_t< difference_type > const n) const noexcept(noexcept(std::declval< base_base_t & >()[0]))
Accesses an element by index.
Definition take_exactly_view.hpp:424
maybe_const_sentinel_t< const_range, urng_t > sentinel_type
The sentinel type is identical to that of the underlying range.
Definition take_exactly_view.hpp:231
constexpr bool operator==(basic_iterator const &rhs) const noexcept(!or_throw &&noexcept(std::declval< base_base_t & >()==std::declval< base_base_t & >()))
Checks whether *this is equal to rhs.
Definition take_exactly_view.hpp:358
constexpr basic_iterator(base_base_t it, size_t const _pos, size_t const _max_pos, view_take_exactly *host=nullptr) noexcept(noexcept(base_t{it}))
Constructor that delegates to the CRTP layer and initialises the members.
Definition take_exactly_view.hpp:259
basic_iterator(basic_iterator const &rhs)=default
Defaulted.
The type returned by seqan3::views::take, seqan3::detail::take_exactly and seqan3::detail::take_exact...
Definition take_exactly_view.hpp:50
size_t target_size
The desired target_size.
Definition take_exactly_view.hpp:56
view_take_exactly & operator=(view_take_exactly const &rhs)=default
Defaulted.
view_take_exactly & operator=(view_take_exactly &&rhs)=default
Defaulted.
view_take_exactly(view_take_exactly const &rhs)=default
Defaulted.
view_take_exactly(view_take_exactly &&rhs)=default
Defaulted.
constexpr auto begin() noexcept
Returns an iterator to the first element of the container.
Definition take_exactly_view.hpp:141
view_take_exactly()=default
Defaulted.
constexpr view_take_exactly(urng_t _urange, size_t const _size)
Construct from another View.
Definition take_exactly_view.hpp:92
~view_take_exactly()=default
Defaulted.
view_take_exactly(urng_t &&, size_t) -> view_take_exactly< std::views::all_t< urng_t >, or_throw >
Template argument type deduction guide that strips references.
constexpr view_take_exactly(rng_t &&_urange, size_t const _size)
Construct from another viewable_range.
Definition take_exactly_view.hpp:120
constexpr auto end() noexcept
Returns an iterator to the element following the last element of the range.
Definition take_exactly_view.hpp:176
urng_t urange
The underlying range.
Definition take_exactly_view.hpp:53
constexpr auto begin() const noexcept
Returns an iterator to the first element of the container.
Definition take_exactly_view.hpp:150
constexpr auto size() const noexcept
Returns the number of elements in the view.
Definition take_exactly_view.hpp:206
constexpr auto end() const noexcept
Returns an iterator to the element following the last element of the range.
Definition take_exactly_view.hpp:185
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:46
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:41
seqan::stl::views::all all
Returns a view that includes all elements of the range argument.
Definition all_view.hpp:35
constexpr auto take_exactly_or_throw
A view adaptor that returns the first size elements from the underlying range and also exposes size i...
Definition take_exactly_view.hpp:587
constexpr auto take_exactly
A view adaptor that returns the first size elements from the underlying range (or less if the underly...
Definition take_exactly_view.hpp:573
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:26
SeqAn specific customisations in the standard namespace.
View adaptor definition for views::take and views::take_or_throw.
Definition take_exactly_view.hpp:442
constexpr auto operator()(size_t const size) const
Store the arguments and return a range adaptor closure object.
Definition take_exactly_view.hpp:444
constexpr auto operator()(urng_t &&urange, size_t target_size) const
Type erase if possible and return view_take_exactly if not.
Definition take_exactly_view.hpp:453
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:75
Provides type traits for working with templates.
Provides seqan3::detail::transformation_trait_or.
Additional non-standard concepts for ranges.
Hide me