SeqAn3  3.0.3
The Modern C++ library for sequence analysis.
enforce_random_access.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/iterator>
16 #include <seqan3/std/ranges>
17 
20 #include <seqan3/range/concept.hpp>
21 
22 namespace seqan3::detail
23 {
24 
25 // ============================================================================
26 // view_pseudo_random_access
27 // ============================================================================
28 
40 template <std::ranges::view urng_t>
44 class view_enforce_random_access : public std::ranges::view_interface<view_enforce_random_access<urng_t>>
45 {
46 private:
47 
48  // Iterator declaration.
49  template <typename underlying_iter_t>
50  class basic_iterator;
51 
52 public:
53 
57  constexpr view_enforce_random_access() = default;
58  constexpr view_enforce_random_access(view_enforce_random_access const &) = default;
59  constexpr view_enforce_random_access(view_enforce_random_access &&) = default;
60  constexpr view_enforce_random_access & operator=(view_enforce_random_access const &) = default;
61  constexpr view_enforce_random_access & operator=(view_enforce_random_access &&) = default;
62  ~view_enforce_random_access() = default;
63 
65  explicit constexpr view_enforce_random_access(urng_t range) : urng{std::move(range)}
66  {}
67 
69  template <typename viewable_rng_t>
71  requires (!std::same_as<std::remove_cvref_t<viewable_rng_t>, view_enforce_random_access>) &&
72  std::ranges::viewable_range<viewable_rng_t> &&
73  std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<viewable_rng_t>>>
75  explicit constexpr view_enforce_random_access(viewable_rng_t range) :
76  view_enforce_random_access{std::views::all(range)}
77  {}
79 
84  constexpr auto begin() noexcept
85  {
86  return basic_iterator<decltype(std::ranges::begin(urng))>{std::ranges::begin(urng)};
87  }
88 
90  constexpr auto begin() const noexcept
92  requires const_iterable_range<urng_t>
94  {
95  return basic_iterator<decltype(std::ranges::cbegin(urng))>{std::ranges::cbegin(urng)};
96  }
97 
106  constexpr auto end() noexcept
107  {
108  if constexpr (std::ranges::common_range<urng_t>)
109  return basic_iterator<decltype(std::ranges::end(urng))>{std::ranges::end(urng)};
110  else
111  return urng.end();
112  }
113 
115  constexpr auto end() const noexcept
117  requires const_iterable_range<urng_t>
119  {
120  if constexpr (std::ranges::common_range<urng_t>)
121  return basic_iterator<decltype(std::ranges::cend(urng))>{std::ranges::cend(urng)};
122  else
123  return std::ranges::cend(urng);
124  }
126 
127  urng_t urng;
128 };
129 
138 template <std::ranges::view urng_t>
142 template <typename underlying_iter_t>
143 class view_enforce_random_access<urng_t>::basic_iterator :
144  public inherited_iterator_base<basic_iterator<underlying_iter_t>, underlying_iter_t>
145 {
146 private:
148  using base_t = inherited_iterator_base<basic_iterator<underlying_iter_t>, underlying_iter_t>;
149 
150 public:
151 
153  using iterator_category = std::random_access_iterator_tag;
155  using iterator_concept = iterator_category;
156 
160  // Importing base's constructors.
161  using base_t::base_t;
163  constexpr basic_iterator() = default;
165  constexpr basic_iterator(basic_iterator const &) = default;
167  constexpr basic_iterator(basic_iterator &&) = default;
169  constexpr basic_iterator & operator=(basic_iterator const &) = default;
171  constexpr basic_iterator & operator=(basic_iterator &&) = default;
173  ~basic_iterator() = default;
175 
180  // Importing base's equality operators
181  using base_t::operator==;
182  using base_t::operator!=;
184  friend constexpr bool operator==(basic_iterator const & lhs, std::ranges::sentinel_t<urng_t> const & rhs)
185  noexcept(noexcept(std::declval<underlying_iter_t const &>() ==
186  std::declval<std::ranges::sentinel_t<urng_t> const &>()))
187  {
188  return lhs.base() == rhs;
189  }
190 
192  friend constexpr bool operator==(std::ranges::sentinel_t<urng_t> const & lhs, basic_iterator const & rhs)
193  noexcept(noexcept(std::declval<underlying_iter_t const &>() ==
194  std::declval<std::ranges::sentinel_t<urng_t> const &>()))
195  {
196  return rhs == lhs;
197  }
198 
200  friend constexpr bool operator!=(basic_iterator const & lhs, std::ranges::sentinel_t<urng_t> const & rhs)
201  noexcept(noexcept(std::declval<underlying_iter_t const &>() !=
202  std::declval<std::ranges::sentinel_t<urng_t> const &>()))
203  {
204  return !(lhs == rhs);
205  }
206 
208  friend constexpr bool operator!=(std::ranges::sentinel_t<urng_t> const & lhs, basic_iterator const & rhs)
209  noexcept(noexcept(std::declval<underlying_iter_t const &>() !=
210  std::declval<std::ranges::sentinel_t<urng_t> const &>()))
211  {
212  return rhs != lhs;
213  }
215 
219  // Import operator from base.
220  using base_t::operator-;
221 
223  constexpr typename base_t::difference_type operator-(std::ranges::sentinel_t<urng_t> const & rhs) const
224  noexcept(noexcept(std::declval<underlying_iter_t const &>() -
225  std::declval<std::ranges::sentinel_t<urng_t> const &>()))
226  requires std::sized_sentinel_for<std::ranges::sentinel_t<urng_t>, underlying_iter_t>
227  {
228  return this->base() - rhs;
229  }
230 
232  constexpr friend typename base_t::difference_type operator-(std::ranges::sentinel_t<urng_t> const & lhs,
233  basic_iterator const & rhs)
234  noexcept(noexcept(std::declval<std::ranges::sentinel_t<urng_t> const &>() -
235  std::declval<underlying_iter_t const &>()))
236  requires std::sized_sentinel_for<std::ranges::sentinel_t<urng_t>, underlying_iter_t>
237  {
238  return lhs - rhs.base();
239  }
241 };
242 
248 template <std::ranges::viewable_range rng_t>
249 view_enforce_random_access(rng_t &&) -> view_enforce_random_access<std::views::all_t<rng_t>>;
251 
252 // ============================================================================
253 // pseudo_random_access_fn (adaptor definition)
254 // ============================================================================
255 
257 struct pseudo_random_access_fn : public adaptor_base<pseudo_random_access_fn>
258 {
259 private:
261  using base_t = adaptor_base<pseudo_random_access_fn>;
262 
263 public:
265  using base_t::base_t;
266 
267 private:
269  friend base_t;
270 
274  template <std::ranges::viewable_range urng_t>
275  static constexpr auto impl(urng_t && urange)
276  {
277  static_assert(std::ranges::random_access_range<urng_t> || pseudo_random_access_range<urng_t>,
278  "The adapted range must either model std::ranges::random_access_range or must be "
279  "a specific SeqAn range type that supports pseudo random access.");
280  static_assert(std::ranges::forward_range<urng_t>,
281  "The underlying range must model std::ranges::forward_range.");
282 
283  if constexpr (std::ranges::random_access_range<urng_t>)
284  { // Nothing to do, just return as ref_view or original view.
285  return std::views::all(std::forward<urng_t>(urange));
286  }
287  else
288  { // Get a subrange using the random access iterators of the container.
289  return view_enforce_random_access{std::forward<urng_t>(urange)};
290  }
291  }
292 };
293 
294 } // namespace seqan3::detail
295 
296 namespace seqan3::views
297 {
298 
371 inline constexpr auto enforce_random_access = detail::pseudo_random_access_fn{};
373 } // namespace seqan3::views
T begin(T... args)
T declval(T... args)
T end(T... args)
auto const move
A view that turns lvalue-references into rvalue-references.
Definition: move.hpp:70
constexpr auto enforce_random_access
A view adaptor that converts a pseudo random access range to a std::ranges::random_access_range.
Definition: enforce_random_access.hpp:371
Provides the seqan3::detail::inherited_iterator_base template.
Specifies requirements of an input range type for which the const version of that type satisfies the ...
This concept checks if a type models a pseudo random access range.
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)
Additional non-standard concepts for ranges.
Adaptations of concepts from the Ranges TS.