SeqAn3  3.2.0-rc.1
The Modern C++ library for sequence analysis.
enforce_random_access.hpp
Go to the documentation of this file.
1 // -----------------------------------------------------------------------------------------------------
2 // Copyright (c) 2006-2022, Knut Reinert & Freie Universität Berlin
3 // Copyright (c) 2016-2022, 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 <iterator>
16 #include <ranges>
17 #include <type_traits>
18 
22 
23 namespace seqan3::detail
24 {
25 
26 // ============================================================================
27 // view_pseudo_random_access
28 // ============================================================================
29 
41 template <std::ranges::view urng_t>
43 class view_enforce_random_access : public std::ranges::view_interface<view_enforce_random_access<urng_t>>
44 {
45 private:
46  // Iterator declaration.
47  template <typename underlying_iter_t>
48  class basic_iterator;
49 
50 public:
54  constexpr view_enforce_random_access() = default;
55  constexpr view_enforce_random_access(view_enforce_random_access const &) = default;
56  constexpr view_enforce_random_access(view_enforce_random_access &&) = default;
57  constexpr view_enforce_random_access & operator=(view_enforce_random_access const &) = default;
58  constexpr view_enforce_random_access & operator=(view_enforce_random_access &&) = default;
59  ~view_enforce_random_access() = default;
60 
62  explicit constexpr view_enforce_random_access(urng_t && range) : urng{std::move(range)}
63  {}
64 
66  template <typename viewable_rng_t>
67  requires (!std::same_as<std::remove_cvref_t<viewable_rng_t>, view_enforce_random_access>)
68  && std::ranges::viewable_range<viewable_rng_t>
69  && std::constructible_from<urng_t, std::ranges::ref_view<std::remove_reference_t<viewable_rng_t>>>
70  explicit constexpr view_enforce_random_access(viewable_rng_t && range) :
71  view_enforce_random_access{std::views::all(std::forward<viewable_rng_t>(range))}
72  {}
74 
79  constexpr auto begin() noexcept
80  {
81  return basic_iterator<decltype(std::ranges::begin(urng))>{std::ranges::begin(urng)};
82  }
83 
85  constexpr auto begin() const noexcept
87  {
88  return basic_iterator<decltype(std::ranges::cbegin(urng))>{std::ranges::cbegin(urng)};
89  }
90 
99  constexpr auto end() noexcept
100  {
101  if constexpr (std::ranges::common_range<urng_t>)
102  return basic_iterator<decltype(std::ranges::end(urng))>{std::ranges::end(urng)};
103  else
104  return urng.end();
105  }
106 
108  constexpr auto end() const noexcept
110  {
111  if constexpr (std::ranges::common_range<urng_t>)
112  return basic_iterator<decltype(std::ranges::cend(urng))>{std::ranges::cend(urng)};
113  else
114  return std::ranges::cend(urng);
115  }
117 
118  urng_t urng;
119 };
120 
129 template <std::ranges::view urng_t>
131 template <typename underlying_iter_t>
132 class view_enforce_random_access<urng_t>::basic_iterator :
133  public inherited_iterator_base<basic_iterator<underlying_iter_t>, underlying_iter_t>
134 {
135 private:
137  using base_t = inherited_iterator_base<basic_iterator<underlying_iter_t>, underlying_iter_t>;
138 
139 public:
141  using iterator_category = std::random_access_iterator_tag;
143  using iterator_concept = iterator_category;
144 
148  // Importing base's constructors.
149  using base_t::base_t;
151  constexpr basic_iterator() = default;
153  constexpr basic_iterator(basic_iterator const &) = default;
155  constexpr basic_iterator(basic_iterator &&) = default;
157  constexpr basic_iterator & operator=(basic_iterator const &) = default;
159  constexpr basic_iterator & operator=(basic_iterator &&) = default;
161  ~basic_iterator() = default;
163 
168  // Importing base's equality operators
169  using base_t::operator==;
170  using base_t::operator!=;
172  friend constexpr bool operator==(basic_iterator const & lhs, std::ranges::sentinel_t<urng_t> const & rhs) noexcept(
173  noexcept(std::declval<underlying_iter_t const &>() == std::declval<std::ranges::sentinel_t<urng_t> const &>()))
174  {
175  return lhs.base() == rhs;
176  }
177 
179  friend constexpr bool operator==(std::ranges::sentinel_t<urng_t> const & lhs, basic_iterator const & rhs) noexcept(
180  noexcept(std::declval<underlying_iter_t const &>() == std::declval<std::ranges::sentinel_t<urng_t> const &>()))
181  {
182  return rhs == lhs;
183  }
184 
186  friend constexpr bool operator!=(basic_iterator const & lhs, std::ranges::sentinel_t<urng_t> const & rhs) noexcept(
187  noexcept(std::declval<underlying_iter_t const &>() != std::declval<std::ranges::sentinel_t<urng_t> const &>()))
188  {
189  return !(lhs == rhs);
190  }
191 
193  friend constexpr bool operator!=(std::ranges::sentinel_t<urng_t> const & lhs, basic_iterator const & rhs) noexcept(
194  noexcept(std::declval<underlying_iter_t const &>() != std::declval<std::ranges::sentinel_t<urng_t> const &>()))
195  {
196  return rhs != lhs;
197  }
199 
203  // Import operator from base.
204  using base_t::operator-;
205 
207  constexpr typename base_t::difference_type operator-(std::ranges::sentinel_t<urng_t> const & rhs) const
208  noexcept(noexcept(std::declval<underlying_iter_t const &>()
209  - std::declval<std::ranges::sentinel_t<urng_t> const &>()))
210  requires std::sized_sentinel_for<std::ranges::sentinel_t<urng_t>, underlying_iter_t>
211  {
212  return this->base() - rhs;
213  }
214 
216  constexpr friend typename base_t::difference_type
217  operator-(std::ranges::sentinel_t<urng_t> const & lhs,
218  basic_iterator const & rhs) noexcept(noexcept(std::declval<std::ranges::sentinel_t<urng_t> const &>()
219  - std::declval<underlying_iter_t const &>()))
220  requires std::sized_sentinel_for<std::ranges::sentinel_t<urng_t>, underlying_iter_t>
221  {
222  return lhs - rhs.base();
223  }
225 };
226 
232 template <std::ranges::viewable_range rng_t>
233 view_enforce_random_access(rng_t &&) -> view_enforce_random_access<std::views::all_t<rng_t>>;
235 
236 // ============================================================================
237 // pseudo_random_access_fn (adaptor definition)
238 // ============================================================================
239 
241 struct pseudo_random_access_fn : public adaptor_base<pseudo_random_access_fn>
242 {
243 private:
245  using base_t = adaptor_base<pseudo_random_access_fn>;
246 
247 public:
249  using base_t::base_t;
250 
251 private:
253  friend base_t;
254 
258  template <std::ranges::viewable_range urng_t>
259  static constexpr auto impl(urng_t && urange)
260  {
261  static_assert(std::ranges::random_access_range<urng_t> || pseudo_random_access_range<urng_t>,
262  "The adapted range must either model std::ranges::random_access_range or must be "
263  "a specific SeqAn range type that supports pseudo random access.");
264  static_assert(std::ranges::forward_range<urng_t>,
265  "The underlying range must model std::ranges::forward_range.");
266 
267  if constexpr (std::ranges::random_access_range<urng_t>)
268  { // Nothing to do, just return as ref_view or original view.
269  return std::views::all(std::forward<urng_t>(urange));
270  }
271  else
272  { // Get a subrange using the random access iterators of the container.
273  return view_enforce_random_access{std::forward<urng_t>(urange)};
274  }
275  }
276 };
277 
278 } // namespace seqan3::detail
279 
280 namespace seqan3::views
281 {
350 inline constexpr auto enforce_random_access = detail::pseudo_random_access_fn{};
351 
352 } // namespace seqan3::views
Provides seqan3::detail::adaptor_base and seqan3::detail::combined_adaptor.
T begin(T... args)
T declval(T... args)
T end(T... args)
T forward(T... args)
requires requires
The rank_type of the semi-alphabet; defined as the return type of seqan3::to_rank....
Definition: alphabet/concept.hpp:164
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:350
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.
The SeqAn namespace for views.
Definition: char_strictly_to.hpp:22
SeqAn specific customisations in the standard namespace.
T operator!=(T... args)
The <ranges> header from C++20's standard library.
Additional non-standard concepts for ranges.