SeqAn3  3.0.1
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 <range/v3/algorithm/copy.hpp>
16 
21 #include <seqan3/io/exception.hpp>
22 #include <seqan3/range/concept.hpp>
27 #include <seqan3/std/algorithm>
28 #include <seqan3/std/concepts>
29 #include <seqan3/std/iterator>
30 #include <seqan3/std/ranges>
31 #include <seqan3/std/span>
32 #include <seqan3/std/type_traits>
33 
34 namespace seqan3::detail
35 {
36 
37 // ============================================================================
38 // view_take
39 // ============================================================================
40 
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>>
56 {
57 private:
59  urng_t urange;
60 
62  size_t target_size;
63 
66  template <typename rng_t>
67  class iterator_type : public inherited_iterator_base<iterator_type<rng_t>, std::ranges::iterator_t<rng_t>>
68  {
69  private:
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>>;
74 
76  using sentinel_type = std::ranges::sentinel_t<urng_t>;
77 
79  size_t pos{};
80 
82  size_t max_pos{};
83 
85  std::conditional_t<exactly && !std::forward_iterator<base_base_t>, view_take *, detail::ignore_t> host_ptr;
86 
87  public:
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;
98 
100  constexpr iterator_type(base_base_t const & it) noexcept(noexcept(base_t{it})) :
101  base_t{std::move(it)}
102  {}
103 
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)
107  {
108  host_ptr = host;
109  }
111 
117  using difference_type = typename std::iterator_traits<base_base_t>::difference_type;
120  using value_type = typename std::iterator_traits<base_base_t>::value_type;
122  using reference = typename std::iterator_traits<base_base_t>::reference;
124  using pointer = typename std::iterator_traits<base_base_t>::pointer;
126  using iterator_category = iterator_tag_t<base_base_t>;
128 
134  constexpr iterator_type & operator++() noexcept(noexcept(++std::declval<base_t &>()))
136  {
137  base_t::operator++();
138  ++pos;
139  if constexpr (exactly && !std::forward_iterator<base_base_t>)
140  --host_ptr->target_size;
141  return *this;
142  }
143 
145  constexpr iterator_type operator++(int) noexcept(noexcept(++std::declval<iterator_type &>()) &&
146  std::is_nothrow_copy_constructible_v<iterator_type>)
147  {
148  iterator_type cpy{*this};
149  ++(*this);
150  return cpy;
151  }
152 
154  constexpr iterator_type & operator--() noexcept(noexcept(--std::declval<base_base_t &>()))
156  requires std::bidirectional_iterator<base_base_t>
158  {
159  base_t::operator--();
160  --pos;
161  return *this;
162  }
163 
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>
170  {
171  iterator_type cpy{*this};
172  --(*this);
173  return cpy;
174  }
175 
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>
181  {
182  base_t::operator+=(skip);
183  pos += skip;
184  return *this;
185  }
186 
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>
192  {
193  base_t::operator-=(skip);
194  pos -= skip;
195  return *this;
196  }
198 
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>
210  {
211  return *base_t::this_to_base() == *rhs.this_to_base();
212  }
213 
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 &>()))
217  {
218  if (pos >= max_pos)
219  return true;
220 
221  if (*base_t::this_to_base() == rhs)
222  {
223  if constexpr (or_throw)
224  throw unexpected_end_of_input{"Reached end of input before designated size."};
225 
226  return true;
227  }
228  else
229  {
230  return false;
231  }
232  }
233 
235  constexpr friend bool operator==(sentinel_type const & lhs, iterator_type const & rhs) noexcept(noexcept(rhs == lhs))
236  {
237  return rhs == lhs;
238  }
239 
241  constexpr bool operator!=(sentinel_type const & rhs) const
242  noexcept(noexcept(std::declval<iterator_type &>() == rhs))
243  {
244  return !(*this == rhs);
245  }
246 
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>
253  {
254  return !(*this == rhs);
255  }
256 
258  constexpr friend bool operator!=(sentinel_type const & lhs, iterator_type const & rhs) noexcept(noexcept(rhs != lhs))
259  {
260  return rhs != lhs;
261  }
263 
273  constexpr reference operator[](std::make_unsigned_t<difference_type> const n) const
274  noexcept(noexcept(std::declval<base_base_t &>()[0]))
276  requires std::random_access_iterator<base_base_t>
278  {
279  return base_base_t::operator[](n);
280  }
282  }; // class iterator_type
283 
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>,
296  void>;
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>;
304 
305 public:
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;
315 
321  constexpr view_take(urng_t _urange, size_t const _size)
322  : urange{std::move(_urange)}, target_size{_size}
323  {
324  if constexpr (std::ranges::sized_range<urng_t>)
325  {
326  if (std::ranges::size(urange) < target_size)
327  {
328  if constexpr (exactly && or_throw)
329  {
331  {
332  "You are trying to construct a views::take_exactly_or_throw from a range that is strictly "
333  "smaller."
334  };
335  }
336  else
337  {
338  target_size = std::ranges::size(urange);
339  }
340  }
341  }
342  }
343 
350  template <std::ranges::viewable_range rng_t>
354  constexpr view_take(rng_t && _urange, size_t const _size)
355  : view_take{std::views::all(std::forward<rng_t>(_urange)), _size}
356  {}
358 
375  constexpr auto begin() noexcept
376  {
377  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
378  return std::ranges::begin(urange);
379  else
380  return iterator{std::ranges::begin(urange), 0, target_size, this};
381  }
382 
384  constexpr auto begin() const noexcept
385  requires const_iterable_range<urng_t>
386  {
387  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
388  return std::ranges::cbegin(urange);
389  else
390  return const_iterator{std::ranges::cbegin(urange), 0, target_size};
391  }
392 
394  constexpr auto cbegin() const noexcept
395  requires const_iterable_range<urng_t>
396  {
397  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
398  return std::ranges::cbegin(urange);
399  else
400  return const_iterator{std::ranges::cbegin(urange), 0, target_size};
401  }
402 
416  constexpr auto end() noexcept
417  {
418  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
419  return std::ranges::begin(urange) + target_size;
420  else
421  return std::ranges::end(urange);
422  }
423 
425  constexpr auto end() const noexcept
426  requires const_iterable_range<urng_t>
427  {
428  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
429  return std::ranges::cbegin(urange) + target_size;
430  else
431  return std::ranges::cend(urange);
432  }
433 
435  constexpr auto cend() const noexcept
436  requires const_iterable_range<urng_t>
437  {
438  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>)
439  return std::ranges::cbegin(urange) + target_size;
440  else
441  return std::ranges::cend(urange);
442  }
444 
459  constexpr size_type size() const noexcept
460  requires exactly || std::ranges::sized_range<urng_t>
461  {
462  return target_size;
463  }
464 };
465 
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>;
472 
473 // ============================================================================
474 // take_fn (adaptor definition)
475 // ============================================================================
476 
480 template <bool exactly, bool or_throw>
481 struct take_fn
482 {
484  constexpr auto operator()(size_t const size) const
485  {
486  return adaptor_from_functor{*this, size};
487  }
488 
492  template <std::ranges::range urng_t>
493  constexpr auto operator()(urng_t && urange, size_t target_size) const
494  {
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.");
497 
498  // safeguard against wrong size
499  if constexpr (std::ranges::sized_range<urng_t>)
500  {
501  if constexpr (or_throw)
502  {
503  if (target_size > std::ranges::size(urange))
504  {
505  throw std::invalid_argument{"You are trying to construct a views::take_exactly_or_throw from a "
506  "range that is strictly smaller."};
507  }
508  }
509  else
510  {
511  target_size = std::min<size_t>(target_size, std::ranges::size(urange));
512  }
513  }
514 
515  // string_view
516  if constexpr (is_type_specialisation_of_v<remove_cvref_t<urng_t>, std::basic_string_view>)
517  {
518  return urange.substr(0, target_size);
519  }
520  // string const &
521  else if constexpr (is_type_specialisation_of_v<remove_cvref_t<urng_t>, std::basic_string> &&
523  {
524  return std::basic_string_view{std::ranges::data(urange), target_size};
525  }
526  // contiguous
527  else if constexpr (forwarding_range<urng_t> &&
528  std::ranges::contiguous_range<urng_t> &&
529  std::ranges::sized_range<urng_t>)
530  {
531  return std::span{std::ranges::data(urange), target_size};
532  }
533  // random_access
534  else if constexpr (forwarding_range<urng_t> &&
535  std::ranges::random_access_range<urng_t> &&
536  std::ranges::sized_range<urng_t>)
537  {
538  return std::ranges::subrange<std::ranges::iterator_t<urng_t>, std::ranges::iterator_t<urng_t>>
539  {
540  std::ranges::begin(urange),
541  std::ranges::begin(urange) + target_size,
542  target_size
543  };
544  }
545  // our type
546  else
547  {
548  return view_take<std::ranges::all_view<urng_t>, exactly, or_throw>
549  {
550  std::forward<urng_t>(urange),
551  target_size
552  };
553  }
554  }
555 };
556 
557 } // namespace seqan3::detail
558 
559 // ============================================================================
560 // views::take (adaptor instance definition)
561 // ============================================================================
562 
563 namespace seqan3::views
564 {
565 
624 inline auto constexpr take = detail::take_fn<false, false>{};
625 
627 
628 } // namespace seqan3::views
shortcuts.hpp
Provides various shortcuts for common std::ranges functions.
seqan3::views
The SeqAn namespace for views.
Definition: view_to_simd.hpp:672
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
constructible_from
The std::constructible_from concept specifies that a variable of type T can be initialized with the g...
std::rel_ops::operator!=
T operator!=(T... args)
iterator
Provides C++20 additions to the <iterator> header.
seqan3::views::move
const auto move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:68
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.
range.hpp
Provides various transformation traits used by the range module.
std::iterator_traits
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::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:624
seqan3::search_cfg::all
constexpr detail::search_mode_all all
Configuration element to receive all hits within the error bounds.
Definition: mode.hpp:43
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::end
T end(T... args)
std::conditional_t
inherited_iterator_base.hpp
Provides the seqan3::detail::inherited_iterator_base template.
forwarding_range
Specifies a range whose iterators may outlive the range and remain valid.
detail.hpp
Auxiliary header for the views submodule .
std::make_unsigned_t