SeqAn3  3.2.0-rc.1
The Modern C++ library for sequence analysis.
interleave.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 <cmath>
16 #include <concepts>
17 #include <ranges>
18 #include <type_traits>
19 
27 
28 namespace seqan3::detail
29 {
30 
31 // ============================================================================
32 // view_interleave
33 // ============================================================================
34 
46 template <std::ranges::random_access_range urng_t, std::ranges::random_access_range inserted_rng_t>
47  requires std::ranges::view<urng_t> && std::ranges::sized_range<urng_t> && std::ranges::view<inserted_rng_t>
48  && std::ranges::sized_range<inserted_rng_t>
49  && std::common_reference_with<std::ranges::range_reference_t<urng_t>,
50  std::ranges::range_reference_t<inserted_rng_t>>
51 class view_interleave : public std::ranges::view_interface<view_interleave<urng_t, inserted_rng_t>>
52 {
53 private:
55  urng_t urange;
57  size_t step_size{};
59  inserted_rng_t inserted_range;
60 
66  using size_type = std::ranges::range_size_t<urng_t>;
68  using reference =
69  std::common_reference_t<std::ranges::range_reference_t<urng_t>, std::ranges::range_reference_t<inserted_rng_t>>;
71  using const_reference =
72  detail::transformation_trait_or_t<std::common_reference<std::ranges::range_reference_t<urng_t const>,
73  std::ranges::range_reference_t<inserted_rng_t const>>,
74  void>;
76  using value_type = std::ranges::range_value_t<urng_t>;
78  using difference_type = std::ranges::range_difference_t<urng_t>;
80  using iterator = detail::random_access_iterator<view_interleave>;
82  using const_iterator = detail::random_access_iterator<view_interleave const>;
84 
86  template <typename range_type, template <typename...> typename derived_t_template>
87  friend class detail::random_access_iterator_base;
88 
89 public:
93  constexpr view_interleave() noexcept = default;
94  constexpr view_interleave(view_interleave const & rhs) noexcept = default;
95  constexpr view_interleave(view_interleave && rhs) noexcept = default;
96  constexpr view_interleave & operator=(view_interleave const & rhs) noexcept = default;
97  constexpr view_interleave & operator=(view_interleave && rhs) noexcept = default;
98  ~view_interleave() noexcept = default;
99 
105  view_interleave(urng_t && _urange, size_t const _step_size, inserted_rng_t && _inserted_range) :
106  urange{_urange},
107  step_size{_step_size},
108  inserted_range{std::forward<inserted_rng_t>(_inserted_range)}
109  {}
110 
120  template <typename orng_t, typename oirng_t>
121  requires std::constructible_from<urng_t, decltype(views::type_reduce(std::declval<orng_t>()))>
122  && std::constructible_from<inserted_rng_t, decltype(detail::persist(std::declval<oirng_t>()))>
123  view_interleave(orng_t && _urange, size_t const _step_size, oirng_t && _inserted_range) :
124  view_interleave{views::type_reduce(std::forward<orng_t>(_urange)),
125  _step_size,
126  detail::persist(std::forward<oirng_t>(_inserted_range))}
127  {}
129 
146  iterator begin() noexcept
147  {
148  return {*this, 0};
149  }
150 
152  const_iterator begin() const noexcept
153  {
154  return {*this, 0};
155  }
156 
170  iterator end() noexcept
171  {
172  return {*this, size()};
173  }
174 
176  const_iterator end() const noexcept
177  {
178  return {*this, size()};
179  }
181 
190  size_type size()
191  {
192  return std::ranges::size(urange)
193  + ((std::floor(std::ranges::size(urange) / step_size)
194  - (std::ranges::size(urange) % step_size == 0 ? 1 : 0))
195  * std::ranges::size(inserted_range));
196  }
197 
199  size_type size() const
200  {
201  return std::ranges::size(urange)
202  + ((std::floor(std::ranges::size(urange) / step_size)
203  - (std::ranges::size(urange) % step_size == 0 ? 1 : 0))
204  * std::ranges::size(inserted_range));
205  }
206 
222  reference operator[](size_type const i)
223  {
224  size_t combined_size = step_size + std::ranges::size(inserted_range);
225  assert(i < size());
226  if (i % (combined_size) < step_size)
227  return urange[i - (std::floor(i / (combined_size)) * std::ranges::size(inserted_range))];
228  else
229  return inserted_range[(i % (combined_size)) - step_size];
230  }
231 
233  const_reference operator[](size_type const i) const
234  {
235  size_t combined_size = step_size + std::ranges::size(inserted_range);
236  assert(i < size());
237  if (i % (combined_size) < step_size)
238  return urange[i - (std::floor(i / (combined_size)) * std::ranges::size(inserted_range))];
239  else
240  return inserted_range[(i % (combined_size)) - step_size];
241  }
242 };
243 
246 template <std::ranges::random_access_range urng_t, std::ranges::random_access_range inserted_rng_t>
247  requires std::ranges::viewable_range<urng_t> && std::ranges::sized_range<urng_t>
248  && std::ranges::sized_range<inserted_rng_t>
249  && std::common_reference_with<std::ranges::range_reference_t<urng_t>,
250  std::ranges::range_reference_t<inserted_rng_t>>
251  view_interleave(urng_t &&, size_t, inserted_rng_t &&)
252  -> view_interleave<decltype(views::type_reduce(std::declval<urng_t>())),
253  decltype(detail::persist(std::declval<inserted_rng_t>()))>;
254 
255 // ============================================================================
256 // interleave_fn (adaptor definition)
257 // ============================================================================
258 
261 struct interleave_fn
262 {
264  template <std::ranges::forward_range inserted_rng_t, std::integral size_type>
265  constexpr auto operator()(size_type const size, inserted_rng_t && i) const noexcept
266  {
267  return detail::adaptor_from_functor{*this, size, std::forward<inserted_rng_t>(i)};
268  }
269 
276  template <std::ranges::range urng_t, std::ranges::range inserted_rng_t, std::integral size_type>
277  constexpr auto operator()(urng_t && urange, size_type const size, inserted_rng_t && i) const noexcept
278  {
279  static_assert(std::ranges::forward_range<urng_t>,
280  "The underlying range parameter in views::interleave must model std::ranges::forward_range.");
281  static_assert(std::ranges::viewable_range<urng_t>,
282  "The underlying range parameter in views::interleave must model std::ranges::viewable_range.");
283  static_assert(std::ranges::forward_range<inserted_rng_t>,
284  "The range to be inserted by views::interleave must model std::ranges::forward_range.");
285  if constexpr (std::ranges::random_access_range<urng_t> && std::ranges::sized_range<urng_t>
286  && std::ranges::random_access_range<inserted_rng_t> && std::ranges::sized_range<inserted_rng_t>)
287  {
288  return detail::view_interleave{std::forward<urng_t>(urange),
289  static_cast<size_t>(size),
290  std::forward<inserted_rng_t>(i)};
291  }
292  else
293  {
294  return std::forward<urng_t>(urange) | seqan3::views::chunk(static_cast<size_t>(size))
295  | views::join_with(std::forward<inserted_rng_t>(i));
296  }
297  }
298 };
299 
300 } // namespace seqan3::detail
301 
302 // ============================================================================
303 // views::interleave (adaptor instance definition)
304 // ============================================================================
305 
306 namespace seqan3::views
307 {
379 inline constexpr auto interleave = detail::interleave_fn{};
380 
381 } // namespace seqan3::views
Provides seqan3::detail::adaptor_from_functor.
T begin(T... args)
Provides seqan3::views::chunk.
The <concepts> header from C++20's standard library.
T end(T... args)
T floor(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 size_t size
The size of a type pack.
Definition: type_pack/traits.hpp:146
constexpr auto join_with
A view adaptor that represents view consisting of the sequence obtained from flattening a view of ran...
Definition: join_with.hpp:531
constexpr auto chunk
Divide a range in chunks.
Definition: chunk.hpp:835
constexpr auto type_reduce
A view adaptor that behaves like std::views::all, but type erases certain ranges.
Definition: type_reduce.hpp:150
constexpr auto interleave
A view that interleaves a given range into another range at regular intervals.
Definition: interleave.hpp:379
Provides seqan3::views::join_with.
The SeqAn namespace for views.
Definition: char_strictly_to.hpp:22
SeqAn specific customisations in the standard namespace.
Provides seqan3::detail::persist.
Provides the seqan3::detail::random_access_iterator class.
The <ranges> header from C++20's standard library.
Provides seqan3::detail::transformation_trait_or.
Provides seqan3::views::type_reduce.