SeqAn3  3.0.3
The Modern C++ library for sequence analysis.
take_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 
14 #pragma once
15 
16 #include <seqan3/std/algorithm>
17 #include <seqan3/std/concepts>
18 #include <seqan3/std/iterator>
19 #include <seqan3/std/ranges>
20 #include <seqan3/std/span>
21 #include <seqan3/std/type_traits>
22 
28 #include <seqan3/io/exception.hpp>
31 
32 namespace seqan3::detail
33 {
34 
35 // ============================================================================
36 // view_take
37 // ============================================================================
38 
53 template <std::ranges::view urng_t, bool exactly, bool or_throw>
54 class view_take : public std::ranges::view_interface<view_take<urng_t, exactly, or_throw>>
55 {
56 #if SEQAN3_VERSION_MAJOR == 3 && SEQAN3_VERSION_MINOR == 1
57  #pragma warning "Move this class to seqan3/io/detail/take_exactly_view.hpp and name it view_take_exactly; substitute exactly with = true."
58 #endif
59 private:
61  urng_t urange;
62 
64  size_t target_size;
65 
67  template <bool const_range>
68  class basic_iterator;
69 
70 private:
75  using iterator = basic_iterator<false>;
81  using const_iterator = basic_iterator<true>;
83 
84 public:
88  view_take() = default;
89  view_take(view_take const & rhs) = default;
90  view_take(view_take && rhs) = default;
91  view_take & operator=(view_take const & rhs) = default;
92  view_take & operator=(view_take && rhs) = default;
93  ~view_take() = default;
94 
100  constexpr view_take(urng_t _urange, size_t const _size)
101  : urange{std::move(_urange)}, target_size{_size}
102  {
103  if constexpr (std::ranges::sized_range<urng_t>)
104  {
105  if (std::ranges::size(urange) < target_size)
106  {
107  if constexpr (exactly && or_throw)
108  {
110  {
111  "You are trying to construct a detail::take_exactly_or_throw from a range that is strictly "
112  "smaller."
113  };
114  }
115  else
116  {
117  target_size = std::ranges::size(urange);
118  }
119  }
120  }
121  }
122 
129  template <std::ranges::viewable_range rng_t>
131  requires std::constructible_from<rng_t, std::views::all_t<rng_t>>
133  constexpr view_take(rng_t && _urange, size_t const _size)
134  : view_take{std::views::all(std::forward<rng_t>(_urange)), _size}
135  {}
137 
154  constexpr auto begin() noexcept
155  {
156  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
157  return std::ranges::begin(urange);
158  else
159  return iterator{std::ranges::begin(urange), 0, target_size, this};
160  }
161 
163  constexpr auto begin() const noexcept
164  requires const_iterable_range<urng_t>
165  {
166  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
167  return std::ranges::cbegin(urange);
168  else
169  return const_iterator{std::ranges::cbegin(urange), 0, target_size};
170  }
171 
185  constexpr auto end() noexcept
186  {
187  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
188  return std::ranges::begin(urange) + target_size;
189  else
190  return std::ranges::end(urange);
191  }
192 
194  constexpr auto end() const noexcept
195  requires const_iterable_range<urng_t>
196  {
197  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
198  return std::ranges::cbegin(urange) + target_size;
199  else
200  return std::ranges::cend(urange);
201  }
203 
219  constexpr auto size() const noexcept
220  requires exactly || std::ranges::sized_range<urng_t>
221  {
222  return target_size;
223  }
224 };
225 
228 template <typename urng_t,
229  bool exactly = false,
230  bool or_throw = false>
231 view_take(urng_t && , size_t) -> view_take<std::views::all_t<urng_t>, exactly, or_throw>;
232 
235 template <std::ranges::view urng_t, bool exactly, bool or_throw>
236 template <bool const_range>
237 class view_take<urng_t, exactly, or_throw>::basic_iterator :
238  public inherited_iterator_base<basic_iterator<const_range>, maybe_const_iterator_t<const_range, urng_t>>
239 {
240 private:
242  using base_base_t = maybe_const_iterator_t<const_range, urng_t>;
244  using base_t = inherited_iterator_base<basic_iterator, maybe_const_iterator_t<const_range, urng_t>>;
245 
247  using sentinel_type = maybe_const_sentinel_t<const_range, urng_t>;
248 
250  size_t pos{};
251 
253  size_t max_pos{};
254 
256  std::conditional_t<exactly && !std::forward_iterator<base_base_t>, view_take *, detail::ignore_t> host_ptr;
257 
258 public:
263  basic_iterator() = default;
264  basic_iterator(basic_iterator const & rhs) = default;
265  basic_iterator(basic_iterator && rhs) = default;
266  basic_iterator & operator=(basic_iterator const & rhs) = default;
267  basic_iterator & operator=(basic_iterator && rhs) = default;
268  ~basic_iterator() = default;
269 
271  constexpr basic_iterator(base_base_t const & it) noexcept(noexcept(base_t{it})) :
272  base_t{std::move(it)}
273  {}
274 
276  constexpr basic_iterator(base_base_t it,
277  size_t const _pos,
278  size_t const _max_pos,
279  view_take * host = nullptr) noexcept(noexcept(base_t{it})) :
280  base_t{std::move(it)}, pos{_pos}, max_pos(_max_pos)
281  {
282  host_ptr = host;
283  }
285 
286  using typename base_t::difference_type;
287  using typename base_t::reference;
288 
295  constexpr basic_iterator & operator++() noexcept(noexcept(++std::declval<base_t &>()))
296  {
297  base_t::operator++();
298  ++pos;
299  if constexpr (exactly && !std::forward_iterator<base_base_t>)
300  --host_ptr->target_size;
301  return *this;
302  }
303 
305  constexpr basic_iterator operator++(int) noexcept(noexcept(++std::declval<basic_iterator &>()) &&
306  std::is_nothrow_copy_constructible_v<basic_iterator>)
307  {
308  basic_iterator cpy{*this};
309  ++(*this);
310  return cpy;
311  }
312 
314  constexpr basic_iterator & operator--() noexcept(noexcept(--std::declval<base_base_t &>()))
316  requires std::bidirectional_iterator<base_base_t>
318  {
319  base_t::operator--();
320  --pos;
321  return *this;
322  }
323 
325  constexpr basic_iterator operator--(int) noexcept(noexcept(--std::declval<basic_iterator &>()) &&
326  std::is_nothrow_copy_constructible_v<basic_iterator>)
328  requires std::bidirectional_iterator<base_base_t>
330  {
331  basic_iterator cpy{*this};
332  --(*this);
333  return cpy;
334  }
335 
337  constexpr basic_iterator & operator+=(difference_type const skip)
338  noexcept(noexcept(std::declval<base_t &>() += skip))
340  requires std::random_access_iterator<base_base_t>
342  {
343  base_t::operator+=(skip);
344  pos += skip;
345  return *this;
346  }
347 
349  constexpr basic_iterator & operator-=(difference_type const skip)
350  noexcept(noexcept(std::declval<base_t &>() -= skip))
352  requires std::random_access_iterator<base_base_t>
354  {
355  base_t::operator-=(skip);
356  pos -= skip;
357  return *this;
358  }
360 
367  constexpr bool operator==(basic_iterator const & rhs) const
368  noexcept(!or_throw && noexcept(std::declval<base_base_t &>() == std::declval<base_base_t &>()))
370  requires std::forward_iterator<base_base_t>
372  {
373  return this->base() == rhs.base();
374  }
375 
377  constexpr bool operator==(sentinel_type const & rhs) const
378  noexcept(!or_throw && noexcept(std::declval<base_base_t const &>() == std::declval<sentinel_type const &>()))
379  {
380  if (pos >= max_pos)
381  return true;
382 
383  if (this->base() == rhs)
384  {
385  if constexpr (or_throw)
386  throw unexpected_end_of_input{"Reached end of input before designated size."};
387 
388  return true;
389  }
390  else
391  {
392  return false;
393  }
394  }
395 
397  constexpr friend bool operator==(sentinel_type const & lhs, basic_iterator const & rhs)
398  noexcept(noexcept(rhs == lhs))
399  {
400  return rhs == lhs;
401  }
402 
404  constexpr bool operator!=(sentinel_type const & rhs) const
405  noexcept(noexcept(std::declval<basic_iterator &>() == rhs))
406  {
407  return !(*this == rhs);
408  }
409 
411  constexpr bool operator!=(basic_iterator const & rhs) const
412  noexcept(noexcept(std::declval<basic_iterator &>() == rhs))
414  requires std::forward_iterator<base_base_t>
416  {
417  return !(*this == rhs);
418  }
419 
421  constexpr friend bool operator!=(sentinel_type const & lhs, basic_iterator const & rhs)
422  noexcept(noexcept(rhs != lhs))
423  {
424  return rhs != lhs;
425  }
427 
437  constexpr reference operator[](std::make_unsigned_t<difference_type> const n) const
438  noexcept(noexcept(std::declval<base_base_t &>()[0]))
440  requires std::random_access_iterator<base_base_t>
442  {
443  return base_t::operator[](n);
444  }
446 };
447 
448 // ============================================================================
449 // take_fn (adaptor definition)
450 // ============================================================================
451 
455 template <bool exactly, bool or_throw>
456 struct take_fn
457 {
459  constexpr auto operator()(size_t const size) const
460  {
461  return adaptor_from_functor{*this, size};
462  }
463 
467  template <std::ranges::range urng_t>
468  constexpr auto operator()(urng_t && urange, size_t target_size) const
469  {
470  static_assert(std::ranges::viewable_range<urng_t>,
471  "The views::take adaptor can only be passed viewable_ranges, i.e. Views or &-to-non-View.");
472 
473  // safeguard against wrong size
474  if constexpr (std::ranges::sized_range<urng_t>)
475  {
476  if constexpr (or_throw)
477  {
478  if (target_size > std::ranges::size(urange))
479  {
480  throw std::invalid_argument{"You are trying to construct a detail::take_exactly_or_throw from a "
481  "range that is strictly smaller."};
482  }
483  }
484  else
485  {
486  target_size = std::min<size_t>(target_size, std::ranges::size(urange));
487  }
488  }
489 
490  // string_view
491  if constexpr (is_type_specialisation_of_v<std::remove_cvref_t<urng_t>, std::basic_string_view>)
492  {
493  // in standard
494  return urange.substr(0, target_size);
495  }
496  // string const &
497  else if constexpr (is_type_specialisation_of_v<std::remove_cvref_t<urng_t>, std::basic_string> &&
499  {
500  // not in standard
501  // seqan3::views::type_reduce does this too
502  return std::basic_string_view{std::ranges::data(urange), target_size};
503  }
504  // contiguous
505  else if constexpr (std::ranges::borrowed_range<urng_t> &&
506  std::ranges::contiguous_range<urng_t> &&
507  std::ranges::sized_range<urng_t>)
508  {
509  // not in standard (special case for std::span in standard)
510  // seqan3::views::type_reduce does this too
511  return std::span{std::ranges::data(urange), target_size};
512  }
513  // random_access
514  else if constexpr (std::ranges::borrowed_range<urng_t> &&
515  std::ranges::random_access_range<urng_t> &&
516  std::ranges::sized_range<urng_t>)
517  {
518  // not in standard
519  // seqan3::views::type_reduce does this too
520  return std::ranges::subrange<std::ranges::iterator_t<urng_t>, std::ranges::iterator_t<urng_t>>
521  {
522  std::ranges::begin(urange),
523  std::ranges::begin(urange) + target_size,
524  target_size
525  };
526  }
527  // our type
528  else
529  {
530  return view_take<std::views::all_t<urng_t>, exactly, or_throw>
531  {
532  std::forward<urng_t>(urange),
533  target_size
534  };
535  }
536  }
537 };
538 
539 } // namespace seqan3::detail
540 
541 #ifdef SEQAN3_DEPRECATED_310
542 // ============================================================================
543 // views::take (adaptor instance definition)
544 // ============================================================================
545 
546 namespace seqan3::views
547 {
548 
609 SEQAN3_DEPRECATED_310 inline auto constexpr take = detail::take_fn<false, false>{};
610 
612 
613 } // namespace seqan3::views
614 #endif // SEQAN3_DEPRECATED_310
Provides seqan3::detail::adaptor_from_functor.
Adaptations of algorithms from the Ranges TS.
T begin(T... args)
The Concepts library.
Provides the seqan3::detail::inherited_iterator_base template.
Provides various transformation traits used by the range module.
Provides type traits for working with templates.
T end(T... args)
T forward(T... args)
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:151
constexpr auto take
A view adaptor that returns the first size elements from the underlying range (or less if the underly...
Definition: take_view.hpp:609
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:74
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.
T is_const_v
Provides various transformation traits for use on iterators.
Provides C++20 additions to the <iterator> header.
The SeqAn namespace for views.
Definition: char_to.hpp:22
SeqAn specific customisations in the standard namespace.
T operator!=(T... args)
#define SEQAN3_DEPRECATED_310
Deprecation message for SeqAn 3.1.0 release.
Definition: platform.hpp:203
Adaptations of concepts from the Ranges TS.
Provides std::span from the C++20 standard library.
Provides C++20 additions to the type_traits header.
Additional non-standard concepts for ranges.
Provides seqan3::detail::transformation_trait_or.