SeqAn3 3.2.0
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
28namespace seqan3::detail
29{
30
31// ============================================================================
32// view_interleave
33// ============================================================================
34
46template <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>>
51class view_interleave : public std::ranges::view_interface<view_interleave<urng_t, inserted_rng_t>>
52{
53private:
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
89public:
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
246template <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
261struct 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
306namespace seqan3::views
307{
379inline 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.
T end(T... args)
T floor(T... args)
T forward(T... args)
constexpr size_t size
The size of a type pack.
Definition: 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.
Provides seqan3::detail::transformation_trait_or.
Provides seqan3::views::type_reduce.