SeqAn3  3.0.2
The Modern C++ library for sequence analysis.
take.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2020, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2020, 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>
19 #include <seqan3/std/span>
20 #include <seqan3/std/type_traits>
21 
26 #include <seqan3/io/exception.hpp>
27 #include <seqan3/range/concept.hpp>
31 
32 namespace seqan3::detail
33 {
34 
35 // ============================================================================
36 // view_take
37 // ============================================================================
38 
52 template <std::ranges::view urng_t, bool exactly, bool or_throw>
53 class view_take : public std::ranges::view_interface<view_take<urng_t, exactly, or_throw>>
54 {
55 private:
57  urng_t urange;
58 
60  size_t target_size;
61 
63  template <typename rng_t>
64  class basic_iterator;
65 
66 private:
70  using iterator = basic_iterator<urng_t>;
77  using const_iterator = basic_iterator<urng_t const>;
79 
80 public:
84  view_take() = default;
85  view_take(view_take const & rhs) = default;
86  view_take(view_take && rhs) = default;
87  view_take & operator=(view_take const & rhs) = default;
88  view_take & operator=(view_take && rhs) = default;
89  ~view_take() = default;
90 
96  constexpr view_take(urng_t _urange, size_t const _size)
97  : urange{std::move(_urange)}, target_size{_size}
98  {
99  if constexpr (std::ranges::sized_range<urng_t>)
100  {
101  if (std::ranges::size(urange) < target_size)
102  {
103  if constexpr (exactly && or_throw)
104  {
106  {
107  "You are trying to construct a views::take_exactly_or_throw from a range that is strictly "
108  "smaller."
109  };
110  }
111  else
112  {
113  target_size = std::ranges::size(urange);
114  }
115  }
116  }
117  }
118 
125  template <std::ranges::viewable_range rng_t>
127  requires std::constructible_from<rng_t, std::views::all_t<rng_t>>
129  constexpr view_take(rng_t && _urange, size_t const _size)
130  : view_take{std::views::all(std::forward<rng_t>(_urange)), _size}
131  {}
133 
150  constexpr auto begin() noexcept
151  {
152  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
153  return std::ranges::begin(urange);
154  else
155  return iterator{std::ranges::begin(urange), 0, target_size, this};
156  }
157 
159  constexpr auto begin() const noexcept
160  requires const_iterable_range<urng_t>
161  {
162  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
163  return std::ranges::cbegin(urange);
164  else
165  return const_iterator{std::ranges::cbegin(urange), 0, target_size};
166  }
167 
181  constexpr auto end() noexcept
182  {
183  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
184  return std::ranges::begin(urange) + target_size;
185  else
186  return std::ranges::end(urange);
187  }
188 
190  constexpr auto end() const noexcept
191  requires const_iterable_range<urng_t>
192  {
193  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
194  return std::ranges::cbegin(urange) + target_size;
195  else
196  return std::ranges::cend(urange);
197  }
199 
215  constexpr auto size() const noexcept
216  requires exactly || std::ranges::sized_range<urng_t>
217  {
218  return target_size;
219  }
220 };
221 
224 template <typename urng_t,
225  bool exactly = false,
226  bool or_throw = false>
227 view_take(urng_t && , size_t) -> view_take<std::views::all_t<urng_t>, exactly, or_throw>;
228 
231 template <std::ranges::view urng_t, bool exactly, bool or_throw>
232 template <typename rng_t>
233 class view_take<urng_t, exactly, or_throw>::basic_iterator :
234  public inherited_iterator_base<basic_iterator<rng_t>, std::ranges::iterator_t<rng_t>>
235 {
236 private:
238  using base_base_t = std::ranges::iterator_t<rng_t>;
240  using base_t = inherited_iterator_base<basic_iterator, std::ranges::iterator_t<rng_t>>;
241 
243  using sentinel_type = std::ranges::sentinel_t<urng_t>;
244 
246  size_t pos{};
247 
249  size_t max_pos{};
250 
252  std::conditional_t<exactly && !std::forward_iterator<base_base_t>, view_take *, detail::ignore_t> host_ptr;
253 
254 public:
259  basic_iterator() = default;
260  basic_iterator(basic_iterator const & rhs) = default;
261  basic_iterator(basic_iterator && rhs) = default;
262  basic_iterator & operator=(basic_iterator const & rhs) = default;
263  basic_iterator & operator=(basic_iterator && rhs) = default;
264  ~basic_iterator() = default;
265 
267  constexpr basic_iterator(base_base_t const & it) noexcept(noexcept(base_t{it})) :
268  base_t{std::move(it)}
269  {}
270 
272  constexpr basic_iterator(base_base_t it,
273  size_t const _pos,
274  size_t const _max_pos,
275  view_take * host = nullptr) noexcept(noexcept(base_t{it})) :
276  base_t{std::move(it)}, pos{_pos}, max_pos(_max_pos)
277  {
278  host_ptr = host;
279  }
281 
287  using difference_type = std::iter_difference_t<base_base_t>;
290  using value_type = std::iter_value_t<base_base_t>;
292  using reference = std::iter_reference_t<base_base_t>;
294  using pointer = detail::iter_pointer_t<base_base_t>;
296  using iterator_category = detail::iterator_category_tag_t<base_base_t>;
298  using iterator_concept = detail::iterator_concept_tag_t<base_base_t>;
300 
306  constexpr basic_iterator & operator++() noexcept(noexcept(++std::declval<base_t &>()))
308  {
309  base_t::operator++();
310  ++pos;
311  if constexpr (exactly && !std::forward_iterator<base_base_t>)
312  --host_ptr->target_size;
313  return *this;
314  }
315 
317  constexpr basic_iterator operator++(int) noexcept(noexcept(++std::declval<basic_iterator &>()) &&
318  std::is_nothrow_copy_constructible_v<basic_iterator>)
319  {
320  basic_iterator cpy{*this};
321  ++(*this);
322  return cpy;
323  }
324 
326  constexpr basic_iterator & operator--() noexcept(noexcept(--std::declval<base_base_t &>()))
328  requires std::bidirectional_iterator<base_base_t>
330  {
331  base_t::operator--();
332  --pos;
333  return *this;
334  }
335 
337  constexpr basic_iterator operator--(int) noexcept(noexcept(--std::declval<basic_iterator &>()) &&
338  std::is_nothrow_copy_constructible_v<basic_iterator>)
340  requires std::bidirectional_iterator<base_base_t>
342  {
343  basic_iterator cpy{*this};
344  --(*this);
345  return cpy;
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  }
359 
361  constexpr basic_iterator & operator-=(difference_type const skip)
362  noexcept(noexcept(std::declval<base_t &>() -= skip))
364  requires std::random_access_iterator<base_base_t>
366  {
367  base_t::operator-=(skip);
368  pos -= skip;
369  return *this;
370  }
372 
378  constexpr bool operator==(basic_iterator const & rhs) const
380  noexcept(!or_throw && noexcept(std::declval<base_base_t &>() == std::declval<base_base_t &>()))
382  requires std::forward_iterator<base_base_t>
384  {
385  return *base_t::this_to_base() == *rhs.this_to_base();
386  }
387 
389  constexpr bool operator==(sentinel_type const & rhs) const
390  noexcept(!or_throw && noexcept(std::declval<base_base_t const &>() == std::declval<sentinel_type const &>()))
391  {
392  if (pos >= max_pos)
393  return true;
394 
395  if (*base_t::this_to_base() == rhs)
396  {
397  if constexpr (or_throw)
398  throw unexpected_end_of_input{"Reached end of input before designated size."};
399 
400  return true;
401  }
402  else
403  {
404  return false;
405  }
406  }
407 
409  constexpr friend bool operator==(sentinel_type const & lhs, basic_iterator const & rhs)
410  noexcept(noexcept(rhs == lhs))
411  {
412  return rhs == lhs;
413  }
414 
416  constexpr bool operator!=(sentinel_type const & rhs) const
417  noexcept(noexcept(std::declval<basic_iterator &>() == rhs))
418  {
419  return !(*this == rhs);
420  }
421 
423  constexpr bool operator!=(basic_iterator const & rhs) const
424  noexcept(noexcept(std::declval<basic_iterator &>() == rhs))
426  requires std::forward_iterator<base_base_t>
428  {
429  return !(*this == rhs);
430  }
431 
433  constexpr friend bool operator!=(sentinel_type const & lhs, basic_iterator const & rhs)
434  noexcept(noexcept(rhs != lhs))
435  {
436  return rhs != lhs;
437  }
439 
449  constexpr reference operator[](std::make_unsigned_t<difference_type> const n) const
450  noexcept(noexcept(std::declval<base_base_t &>()[0]))
452  requires std::random_access_iterator<base_base_t>
454  {
455  return base_base_t::operator[](n);
456  }
458 };
459 
460 // ============================================================================
461 // take_fn (adaptor definition)
462 // ============================================================================
463 
467 template <bool exactly, bool or_throw>
468 struct take_fn
469 {
471  constexpr auto operator()(size_t const size) const
472  {
473  return adaptor_from_functor{*this, size};
474  }
475 
479  template <std::ranges::range urng_t>
480  constexpr auto operator()(urng_t && urange, size_t target_size) const
481  {
482  static_assert(std::ranges::viewable_range<urng_t>,
483  "The views::take adaptor can only be passed viewable_ranges, i.e. Views or &-to-non-View.");
484 
485  // safeguard against wrong size
486  if constexpr (std::ranges::sized_range<urng_t>)
487  {
488  if constexpr (or_throw)
489  {
490  if (target_size > std::ranges::size(urange))
491  {
492  throw std::invalid_argument{"You are trying to construct a views::take_exactly_or_throw from a "
493  "range that is strictly smaller."};
494  }
495  }
496  else
497  {
498  target_size = std::min<size_t>(target_size, std::ranges::size(urange));
499  }
500  }
501 
502  // string_view
503  if constexpr (is_type_specialisation_of_v<std::remove_cvref_t<urng_t>, std::basic_string_view>)
504  {
505  return urange.substr(0, target_size);
506  }
507  // string const &
508  else if constexpr (is_type_specialisation_of_v<std::remove_cvref_t<urng_t>, std::basic_string> &&
510  {
511  return std::basic_string_view{std::ranges::data(urange), target_size};
512  }
513  // contiguous
514  else if constexpr (std::ranges::borrowed_range<urng_t> &&
515  std::ranges::contiguous_range<urng_t> &&
516  std::ranges::sized_range<urng_t>)
517  {
518  return std::span{std::ranges::data(urange), target_size};
519  }
520  // random_access
521  else if constexpr (std::ranges::borrowed_range<urng_t> &&
522  std::ranges::random_access_range<urng_t> &&
523  std::ranges::sized_range<urng_t>)
524  {
525  return std::ranges::subrange<std::ranges::iterator_t<urng_t>, std::ranges::iterator_t<urng_t>>
526  {
527  std::ranges::begin(urange),
528  std::ranges::begin(urange) + target_size,
529  target_size
530  };
531  }
532  // our type
533  else
534  {
535  return view_take<std::views::all_t<urng_t>, exactly, or_throw>
536  {
537  std::forward<urng_t>(urange),
538  target_size
539  };
540  }
541  }
542 };
543 
544 } // namespace seqan3::detail
545 
546 // ============================================================================
547 // views::take (adaptor instance definition)
548 // ============================================================================
549 
550 namespace seqan3::views
551 {
552 
611 inline auto constexpr take = detail::take_fn<false, false>{};
612 
614 
615 } // namespace seqan3::views
seqan3::views
The SeqAn namespace for views.
Definition: view_iota_simd.hpp:218
span
Provides std::span from the C++20 standard library.
std::basic_string
type_traits
Provides C++20 additions to the type_traits header.
std::basic_string_view
std::rel_ops::operator!=
T operator!=(T... args)
iterator
Provides C++20 additions to the <iterator> header.
template_inspection.hpp
Provides seqan3::type_list and auxiliary type traits.
concept.hpp
Adaptations of concepts from the standard library.
algorithm
Adaptations of algorithms from the Ranges TS.
concepts
The Concepts library.
concept.hpp
Additional non-standard concepts for ranges.
seqan3::views::move
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:68
range.hpp
Provides various transformation traits used by the range module.
const_iterable_range
Specifies requirements of an input range type for which the const version of that type satisfies the ...
transformation_trait_or.hpp
Provides seqan3::detail::transformation_trait_or.
exception.hpp
Provides exceptions used in the I/O module.
std::iter_difference_t
std::invalid_argument
iterator.hpp
Provides various transformation traits for use on iterators.
seqan3::views::take
constexpr auto take
A view adaptor that returns the first size elements from the underlying range (or less if the underly...
Definition: take.hpp:611
seqan3::pack_traits::size
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:116
ranges
Adaptations of concepts from the Ranges TS.
std::remove_reference_t
std::is_const_v
T is_const_v
std::begin
T begin(T... args)
std
SeqAn specific customisations in the standard namespace.
std::remove_cvref_t
std::end
T end(T... args)
std::conditional_t
inherited_iterator_base.hpp
Provides the seqan3::detail::inherited_iterator_base template.
detail.hpp
Auxiliary header for the views submodule .
std::make_unsigned_t