SeqAn3
take.hpp
Go to the documentation of this file.
1 // ============================================================================
2 // SeqAn - The Library for Sequence Analysis
3 // ============================================================================
4 //
5 // Copyright (c) 2006-2018, Knut Reinert & Freie Universitaet Berlin
6 // Copyright (c) 2016-2018, Knut Reinert & MPI Molekulare Genetik
7 // All rights reserved.
8 //
9 // Redistribution and use in source and binary forms, with or without
10 // modification, are permitted provided that the following conditions are met:
11 //
12 // * Redistributions of source code must retain the above copyright
13 // notice, this list of conditions and the following disclaimer.
14 // * Redistributions in binary form must reproduce the above copyright
15 // notice, this list of conditions and the following disclaimer in the
16 // documentation and/or other materials provided with the distribution.
17 // * Neither the name of Knut Reinert or the FU Berlin nor the names of
18 // its contributors may be used to endorse or promote products derived
19 // from this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 // ARE DISCLAIMED. IN NO EVENT SHALL KNUT REINERT OR THE FU BERLIN BE LIABLE
25 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
28 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 // OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 // DAMAGE.
32 //
33 // ============================================================================
34 
40 #pragma once
41 
42 #include <range/v3/algorithm/copy.hpp>
43 
47 #include <seqan3/io/exception.hpp>
48 #include <seqan3/range/concept.hpp>
53 #include <seqan3/std/concepts>
54 #include <seqan3/std/iterator>
55 #include <seqan3/std/type_traits>
56 #include <seqan3/std/ranges>
58 
59 namespace seqan3::detail
60 {
61 
62 // ============================================================================
63 // view_take
64 // ============================================================================
65 
79 template <std::ranges::View urng_t, bool exactly, bool or_throw>
80 class view_take : public ranges::view_interface<view_take<urng_t, exactly, or_throw>>
81 {
82 private:
84  urng_t urange;
85 
87  size_t target_size;
88 
90  using sentinel_type = std::ranges::sentinel_t<urng_t>;
91 
94  template <typename rng_t>
95  class iterator_type : public inherited_iterator_base<iterator_type<rng_t>, std::ranges::iterator_t<rng_t>>
96  {
97  private:
99  using base_base_t = std::ranges::iterator_t<rng_t>;
101  using base_t = inherited_iterator_base<iterator_type, std::ranges::iterator_t<rng_t>>;
102 
104  size_t pos;
105 
107  size_t max_pos;
108 
109  public:
113  iterator_type() = default;
114  constexpr iterator_type(iterator_type const & rhs) = default;
115  constexpr iterator_type(iterator_type && rhs) = default;
116  constexpr iterator_type & operator=(iterator_type const & rhs) = default;
117  constexpr iterator_type & operator=(iterator_type && rhs) = default;
118  ~iterator_type() = default;
119 
121  iterator_type(base_base_t const & it) :
122  base_t{it}
123  {}
124 
126  iterator_type(base_base_t it, size_t const _pos, size_t const _max_pos) :
127  base_t{it}, pos{_pos}, max_pos(_max_pos)
128  {}
130 
135  using difference_type = typename std::iterator_traits<base_base_t>::difference_type;
136  using value_type = typename std::iterator_traits<base_base_t>::value_type;
137  using reference = typename std::iterator_traits<base_base_t>::reference;
138  using pointer = typename std::iterator_traits<base_base_t>::pointer;
139  using iterator_category = typename std::iterator_traits<base_base_t>::iterator_category;
141 
146  iterator_type & operator++() noexcept(noexcept(++base_base_t{}))
147  {
148  base_base_t::operator++();
149  ++pos;
150  return *this;
151  }
152 
153  iterator_type operator++(int) noexcept(noexcept(++base_base_t{}))
154  {
155  iterator_type cpy{*this};
156  ++(*this);
157  return cpy;
158  }
159 
160  iterator_type & operator--() noexcept(noexcept(--base_base_t{}))
162  requires std::BidirectionalIterator<base_base_t>
164  {
165  base_base_t::operator--();
166  --pos;
167  return *this;
168  }
169 
170  iterator_type operator--(int) noexcept(noexcept(--base_base_t{}))
174  {
175  iterator_type cpy{*this};
176  --(*this);
177  return cpy;
178  }
179 
180  iterator_type & operator+=(difference_type const skip) noexcept(noexcept(base_base_t{} += skip))
182  requires std::RandomAccessIterator<base_base_t>
184  {
185  base_base_t::operator+=(skip);
186  pos += skip;
187  return *this;
188  }
189 
190  iterator_type & operator-=(difference_type const skip) noexcept(noexcept(base_base_t{} -= skip))
192  requires std::RandomAccessIterator<base_base_t>
194  {
195  base_base_t::operator-=(skip);
196  pos -= skip;
197  return *this;
198  }
200 
205  bool operator==(iterator_type const & rhs) const noexcept(!or_throw)
206  {
207  return static_cast<base_base_t>(*this) == static_cast<base_base_t>(rhs);
208  }
209 
210  bool operator==(sentinel_type const & rhs) const noexcept(!or_throw)
211  {
212  if (pos >= max_pos)
213  return true;
214 
215  if (static_cast<base_base_t>(*this) == rhs)
216  {
217  if constexpr (or_throw)
218  throw unexpected_end_of_input{"Reached end of input before designated size."};
219 
220  return true;
221  }
222  else
223  {
224  return false;
225  }
226  }
227 
228  friend bool operator==(sentinel_type const & lhs, iterator_type const & rhs) noexcept(!or_throw)
229  {
230  return rhs == lhs;
231  }
232 
233  bool operator!=(sentinel_type const & rhs) const noexcept(!or_throw)
234  {
235  return !(*this == rhs);
236  }
237 
238  bool operator!=(iterator_type const & rhs) const noexcept(!or_throw)
239  {
240  return static_cast<base_base_t>(*this) != static_cast<base_base_t>(rhs);
241  }
242 
243  friend bool operator!=(sentinel_type const & lhs, iterator_type const & rhs) noexcept(!or_throw)
244  {
245  return rhs != lhs;
246  }
248 
253  reference operator[](std::make_unsigned_t<difference_type> const n) const noexcept(noexcept(base_base_t{}[0]))
255  requires std::RandomAccessIterator<base_base_t>
257  {
258  pos = n;
259  return base_base_t::operator[](n);
260  }
262  }; // class iterator_type
263 
264 public:
268  using reference = reference_t<urng_t>;
271  using const_reference = detail::transformation_trait_or_t<seqan3::reference<urng_t const>, void>;
273  using value_type = value_type_t<urng_t>;
275  using size_type = std::conditional_t<exactly, size_t, void>;
277  using difference_type = difference_type_t<urng_t>;
279  using iterator = iterator_type<urng_t>;
281  using const_iterator = detail::transformation_trait_or_t<std::type_identity<iterator_type<urng_t const>>, void>;
283 
287  view_take() = default;
288  constexpr view_take(view_take const & rhs) = default;
289  constexpr view_take(view_take && rhs) = default;
290  constexpr view_take & operator=(view_take const & rhs) = default;
291  constexpr view_take & operator=(view_take && rhs) = default;
292  ~view_take() = default;
293 
299  view_take(urng_t _urange, size_t const _size)
300  : urange{std::move(_urange)}, target_size{_size}
301  {
302  if constexpr (exactly && or_throw && std::ranges::SizedRange<urng_t>)
303  {
304  if (seqan3::size(_urange) < _size)
305  {
306  throw std::invalid_argument{
307  "You are trying to construct a view::take_exactly_or_throw from a range that is strictly smaller."};
308  }
309  }
310  }
312 
329  iterator begin() noexcept
330  {
331  return {seqan3::begin(urange), 0, target_size};
332  }
333 
335  const_iterator begin() const noexcept
336  requires const_iterable_concept<urng_t>
337  {
338  return {seqan3::cbegin(urange), 0, target_size};
339  }
340 
342  const_iterator cbegin() const noexcept
343  requires const_iterable_concept<urng_t>
344  {
345  return {seqan3::cbegin(urange), 0, target_size};
346  }
347 
361  sentinel_type end() noexcept
362  {
363  return {seqan3::end(urange)};
364  }
365 
367  sentinel_type end() const noexcept
368  requires const_iterable_concept<urng_t>
369  {
370  return {seqan3::cend(urange)};
371  }
372 
374  sentinel_type cend() const noexcept
375  requires const_iterable_concept<urng_t>
376  {
377  return {seqan3::cend(urange)};
378  }
380 
392  size_type size() const noexcept
393  requires exactly
394  {
395  return target_size;
396  }
397 
403  template <sequence_container_concept container_t>
404  operator container_t()
406  requires std::CommonReference<reference_t<container_t>, reference>
408  {
409  container_t ret;
411  return ret;
412  }
413 
415  template <sequence_container_concept container_t>
416  operator container_t() const
418  requires std::CommonReference<reference_t<container_t>, reference> && const_iterable_concept<urng_t>
420  {
421  container_t ret;
423  return ret;
424  }
425 };
426 
429 template <typename urng_t,
430  bool exactly = false,
431  bool or_throw = false>
432 view_take(urng_t, size_t) -> view_take<std::remove_reference_t<urng_t>, exactly, or_throw>;
433 
434 // ============================================================================
435 // take_fn (adaptor definition)
436 // ============================================================================
437 
441 template <bool exactly, bool or_throw>
442 class take_fn : public pipable_adaptor_base<take_fn<exactly, or_throw>>
443 {
444 private:
446  using base_t = pipable_adaptor_base<take_fn<exactly, or_throw>>;
447 
448 public:
450  using base_t::base_t;
451 
452 private:
454  friend base_t;
455 
459  template <std::ranges::View urng_t>
460  static auto impl(urng_t urange, size_t const target_size)
461  {
462  return view_take<urng_t, exactly, or_throw>{std::move(urange), target_size};
463  }
464 
468  template <std::ranges::ViewableRange urng_t>
469  static auto impl(urng_t && urange, size_t const target_size)
470  {
471  return impl(view::all(std::forward<urng_t>(urange)), target_size);
472  }
473 };
474 
475 } // namespace seqan3::detail
476 
477 // ============================================================================
478 // view::take (adaptor instance definition)
479 // ============================================================================
480 
481 namespace seqan3::view
482 {
483 
526 inline auto constexpr take = detail::take_fn<false, false>{};
527 
529 
530 } // namespace seqan3::view
::ranges::cbegin cbegin
Alias for ranges::cbegin. Returns an iterator to the beginning of a range.
Definition: ranges:245
Provides exceptions used in the I/O module.
Provides C++20 additions to the <iterator> header.
Contains various shortcuts for common std::ranges functions.
Provides seqan3::detail::transformation_trait_or.
Provides the seqan3::detail::inherited_iterator_base template.
SeqAn specific customisations in the standard namespace.
Definition: align_result.hpp:221
::ranges::copy copy
Alias for ranges::copy. Copies a range of elements to a new location.
Definition: ranges:200
::ranges::size size
Alias for ranges::size. Obtains the size of a range whose size can be calculated in constant time...
Definition: ranges:195
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:225
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:220
::ranges::begin begin
Alias for ranges::begin. Returns an iterator to the beginning of a range.
Definition: ranges:185
Provides seqan3::view::all.
The SeqAn3 namespace for views.
Definition: aligned_sequence_concept.hpp:288
Provides C++20 additions to the type_traits header.
typename reference< t >::type reference_t
Type metafunction shortcut for seqan3::reference.
Definition: pre.hpp:98
The concept BidirectionalIterator refines std::ForwardIterator by adding the ability to move an itera...
constexpr auto all
A view that safely wraps a container (you will likely not need to use this unless defining a new view...
Definition: view_all.hpp:95
Provides various metafunctions used by the range module.
Provides various metafunctions for use on iterators.
auto constexpr take
A view adaptor that returns the first size elements from the underlying range (or less if the underly...
Definition: take.hpp:526
::ranges::cend cend
Alias for ranges::cend. Returns an iterator to the end of a range.
Definition: ranges:250
Adaptations of concepts from the standard library.
constexpr auto back_inserter(container_t &container)
Create a std::back_insert_iterator for the argument.
Definition: iterator:79
Specifies the requirements of a Range type that knows its size in constant time with the size functio...
::ranges::end end
Alias for ranges::end. Returns an iterator to the end of a range.
Definition: ranges:190