SeqAn3  3.0.0
The Modern C++ library for sequence analysis.
take.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2019, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2019, 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 ranges::view_interface<view_take<urng_t, exactly, or_throw>>
56 {
57 private:
59  urng_t urange;
60 
62  size_t target_size;
63 
65  using sentinel_type = std::ranges::sentinel_t<urng_t>;
66 
69  template <typename rng_t>
70  class iterator_type : public inherited_iterator_base<iterator_type<rng_t>, std::ranges::iterator_t<rng_t>>
71  {
72  private:
74  using base_base_t = std::ranges::iterator_t<rng_t>;
76  using base_t = inherited_iterator_base<iterator_type, std::ranges::iterator_t<rng_t>>;
77 
79  size_t pos{};
80 
82  size_t max_pos{};
83 
85  std::conditional_t<exactly && !std::ForwardIterator<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::ForwardIterator<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::BidirectionalIterator<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>)
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))
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))
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::ForwardIterator<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 &>() == std::declval<sentinel_type &>()))
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))
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::RandomAccessIterator<base_base_t>
278  {
279  return base_base_t::operator[](n);
280  }
282  }; // class iterator_type
283 
284 public:
288  using reference = reference_t<urng_t>;
291  using const_reference = detail::transformation_trait_or_t<seqan3::reference<urng_t const>, void>;
293  using value_type = value_type_t<urng_t>;
295  using size_type = std::conditional_t<exactly,
296  transformation_trait_or_t<seqan3::size_type<urng_t>, size_t>,
297  void>;
299  using difference_type = difference_type_t<urng_t>;
301  using iterator = iterator_type<urng_t>;
303  using const_iterator = detail::transformation_trait_or_t<std::type_identity<iterator_type<urng_t const>>, void>;
305 
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 (exactly && or_throw && std::ranges::SizedRange<urng_t>)
325  {
326  if (seqan3::size(_urange) < _size)
327  {
328  throw std::invalid_argument{
329  "You are trying to construct a view::take_exactly_or_throw from a range that is strictly smaller."};
330  }
331  }
332  }
333 
340  template<std::ranges::ViewableRange rng_t>
344  constexpr view_take(rng_t && _urange, size_t const _size)
345  : view_take{std::view::all(std::forward<rng_t>(_urange)), _size}
346  {}
348 
365  constexpr iterator begin() noexcept
366  {
367  return {seqan3::begin(urange), 0, target_size, &(*this)};
368  }
369 
371  constexpr const_iterator begin() const noexcept
372  requires ConstIterableRange<urng_t>
373  {
374  return {seqan3::cbegin(urange), 0, target_size};
375  }
376 
378  constexpr const_iterator cbegin() const noexcept
379  requires ConstIterableRange<urng_t>
380  {
381  return {seqan3::cbegin(urange), 0, target_size};
382  }
383 
397  constexpr sentinel_type end() noexcept
398  {
399  return {seqan3::end(urange)};
400  }
401 
403  constexpr sentinel_type end() const noexcept
404  requires ConstIterableRange<urng_t>
405  {
406  return {seqan3::cend(urange)};
407  }
408 
410  constexpr sentinel_type cend() const noexcept
411  requires ConstIterableRange<urng_t>
412  {
413  return {seqan3::cend(urange)};
414  }
416 
428  constexpr size_type size() const noexcept
429  requires exactly
430  {
431  return target_size;
432  }
433 };
434 
437 template <typename urng_t,
438  bool exactly = false,
439  bool or_throw = false>
440 view_take(urng_t && , size_t) -> view_take<std::ranges::all_view<urng_t>, exactly, or_throw>;
441 
442 // ============================================================================
443 // take_fn (adaptor definition)
444 // ============================================================================
445 
449 template <bool exactly, bool or_throw>
450 struct take_fn
451 {
453  constexpr auto operator()(size_t const size) const
454  {
455  return adaptor_from_functor{*this, size};
456  }
457 
461  template <std::ranges::Range urng_t>
462  constexpr auto operator()(urng_t && urange, size_t target_size) const
463  {
465  "The view::take adaptor can only be passed ViewableRanges, i.e. Views or &-to-non-View.");
466 
467  // safeguard against wrong size
468  if constexpr (std::ranges::SizedRange<urng_t>)
469  {
470  if constexpr (or_throw)
471  {
472  if (target_size > std::ranges::size(urange))
473  {
474  throw std::invalid_argument{"You are trying to construct a view::take_exactly_or_throw from a "
475  "range that is strictly smaller."};
476  }
477  }
478  else
479  {
480  target_size = std::min(target_size, std::ranges::size(urange));
481  }
482  }
483 
484  // string_view
485  if constexpr (is_type_specialisation_of_v<remove_cvref_t<urng_t>, std::basic_string_view>)
486  {
487  return urange.substr(0, target_size);
488  }
489  // string const &
490  else if constexpr (is_type_specialisation_of_v<remove_cvref_t<urng_t>, std::basic_string> &&
492  {
493  return std::basic_string_view{std::ranges::data(urange), target_size};
494  }
495  // contiguous
496  else if constexpr (ForwardingRange<urng_t> &&
499  {
500  return std::span{std::ranges::data(urange), target_size};
501  }
502  // random_access
503  else if constexpr (ForwardingRange<urng_t> &&
506  {
508  {
509  std::ranges::begin(urange),
510  std::ranges::begin(urange) + target_size,
511  target_size
512  };
513  }
514  // our type
515  else
516  {
517  return view_take<std::ranges::all_view<urng_t>, exactly, or_throw>
518  {
519  std::forward<urng_t>(urange),
520  target_size
521  };
522  }
523  }
524 };
525 
526 } // namespace seqan3::detail
527 
528 // ============================================================================
529 // view::take (adaptor instance definition)
530 // ============================================================================
531 
532 namespace seqan3::view
533 {
534 
596 inline auto constexpr take = detail::take_fn<false, false>{};
597 
599 
600 } // namespace seqan3::view
::ranges::cbegin cbegin
Alias for ranges::cbegin. Returns an iterator to the beginning of a range.
Definition: ranges:209
Specifies the requirements of a Range type that is either a std::ranges::View or an lvalue-reference...
::ranges::subrange< it_t, sen_t, k > subrange
Create a view from a pair of iterator and sentinel.
Definition: ranges:339
Provides exceptions used in the I/O module.
Specifies requirements of a Range type whose elements occupy adjacent locations in memory...
T operator!=(T... args)
Provides C++20 additions to the <iterator> header.
Provides various shortcuts for common std::ranges functions.
Provides seqan3::detail::transformation_trait_or.
Provides seqan3::type_list and auxiliary type traits.
Specifies requirements of a Range type for which begin returns a type that models std::RandomAccessIt...
Provides the seqan3::detail::inherited_iterator_base template.
The InputIterator concept is a refinement of std::Iterator, adding the requirement that the reference...
SeqAn specific customisations in the standard namespace.
constexpr auto all
A view adaptor that behaves like std::view:all, but type erases contiguous ranges.
Definition: view_all.hpp:160
::ranges::size size
Alias for ranges::size. Obtains the size of a range whose size can be calculated in constant time...
Definition: ranges:189
::ranges::data data
Alias for ranges::data. Returns a pointer the block of data of a ContiguousRange. ...
Definition: ranges:184
::ranges::view_interface< urng_t > view_interface
Alias for ranges::view_interface.
Definition: ranges:220
T min(T... args)
Specifies the requirements of a Range type that knows its size in constant time with the size functio...
Provides various transformation traits for use on iterators.
t & operator=(t1 const &rhs)
Assignment operator.
Additional non-standard concepts for ranges.
The Concepts library.
Auxiliary header for the view submodule .
::ranges::iterator_t iterator_t
Alias for ranges::iterator_t. Obtains the iterator type of a range.
Definition: ranges:204
Adaptations of concepts from the Ranges TS.
::ranges::sentinel_t sentinel_t
Alias for ranges::sentinel_t. Obtains the sentinel type of a range.
Definition: ranges:199
::ranges::begin begin
Alias for ranges::begin. Returns an iterator to the beginning of a range.
Definition: ranges:174
The SeqAn3 namespace for views.
Provides std::span from the C++20 standard library.
T is_const_v
Definition: aligned_sequence_concept.hpp:35
The concept RandomAccessIterator refines std::BidirectionalIterator by adding support for constant ti...
The std::Constructible concept specifies that a variable of type T can be initialized with the given ...
Provides C++20 additions to the type_traits header.
The concept BidirectionalIterator refines std::ForwardIterator by adding the ability to move an itera...
Adaptations of algorithms from the Ranges TS.
Provides various transformation traits used by the range module.
auto constexpr take
A view adaptor that returns the first size elements from the underlying range (or less if the underly...
Definition: take.hpp:596
::ranges::cend cend
Alias for ranges::cend. Returns an iterator to the end of a range.
Definition: ranges:214
Adaptations of concepts from the standard library.
::ranges::end end
Alias for ranges::end. Returns an iterator to the end of a range.
Definition: ranges:179