29template <
typename... range_ts>
30concept zip_is_common = (
sizeof...(range_ts) == 1 && (std::ranges::common_range<range_ts> && ...))
31 || (!(std::ranges::bidirectional_range<range_ts> && ...)
32 && (std::ranges::common_range<range_ts> && ...))
33 || ((std::ranges::random_access_range<range_ts> && ...)
34 && (std::ranges::sized_range<range_ts> && ...));
37template <
typename... ts>
38struct tuple_or_pair_impl;
41template <
typename... ts>
42 requires (
sizeof...(ts) != 2)
43struct tuple_or_pair_impl<ts...>
49template <
typename... ts>
50 requires (
sizeof...(ts) == 2)
51struct tuple_or_pair_impl<ts...>
57template <
typename... ts>
58using tuple_or_pair = tuple_or_pair_impl<ts...>::type;
62constexpr t abs(t && v)
noexcept
64 if constexpr (std::is_signed_v<t>)
65 return v < 0 ? -v : v;
72template <
typename fun_t,
typename tuple_t>
73constexpr auto tuple_transform(fun_t && f, tuple_t && tuple)
76 [&]<
typename... ts>(ts &&...
elements)
78 return tuple_or_pair<std::invoke_result_t<fun_t &, ts>...>{
std::invoke(f, std::forward<ts>(
elements))...};
80 std::forward<tuple_t>(tuple));
85template <
typename fun_t,
typename tuple_t>
86constexpr void tuple_for_each(fun_t && f, tuple_t && tuple)
89 [&]<
typename... ts>(ts &&...
elements)
93 std::forward<tuple_t>(tuple));
96template <
bool is_const,
typename... range_ts>
97concept all_random_access = (std::ranges::random_access_range<view_helper::maybe_const<is_const, range_ts>> && ...);
99template <
bool is_const,
typename... range_ts>
100concept all_bidirectional = (std::ranges::bidirectional_range<view_helper::maybe_const<is_const, range_ts>> && ...);
102template <
bool is_const,
typename... range_ts>
103concept all_forward = (std::ranges::forward_range<view_helper::maybe_const<is_const, range_ts>> && ...);
106#if defined(__GNUC__) && (__GNUC__ == 10)
107template <
bool is_const,
typename... range_ts>
108concept all_contiguous = (std::ranges::contiguous_range<view_helper::maybe_const<is_const, range_ts>> && ...);
110template <
bool Const,
typename... Views>
111struct iterator_category_t
114 all_contiguous<Const, Views...>,
115 std::contiguous_iterator_tag,
117 all_random_access<Const, Views...>,
120 all_bidirectional<Const, Views...>,
126struct iterator_category_t;
128struct iterator_category_t<true>
133struct iterator_category_t<false>
142template <std::ranges::input_range... Views>
143 requires (std::ranges::view<Views> && ...) && (
sizeof...(Views) > 0)
144class zip_view :
public std::ranges::view_interface<zip_view<Views...>>
156 requires (std::is_default_constructible_v<Views> && ...)
158 constexpr explicit zip_view(Views... views) : views_(
std::move(views)...)
161 constexpr auto begin()
162 requires (!(view_helper::simple_view<Views> && ...))
164 return iterator<false>(zip::tuple_transform(std::ranges::begin, views_));
167 constexpr auto begin() const
168 requires (
std::ranges::range<Views const> && ...)
170 return iterator<true>(zip::tuple_transform(std::ranges::begin, views_));
174 requires (!(view_helper::simple_view<Views> && ...))
176 if constexpr (!zip::zip_is_common<Views...>)
177 return sentinel<false>(zip::tuple_transform(std::ranges::end, views_));
178 else if constexpr ((std::ranges::random_access_range<Views> && ...))
181 return iterator<false>(zip::tuple_transform(std::ranges::end, views_));
184 constexpr auto end() const
185 requires (
std::ranges::range<Views const> && ...)
187 if constexpr (!zip::zip_is_common<Views
const...>)
188 return sentinel<true>(zip::tuple_transform(std::ranges::end, views_));
189 else if constexpr ((std::ranges::random_access_range<Views const> && ...))
192 return iterator<true>(zip::tuple_transform(std::ranges::end, views_));
195 constexpr auto size()
196 requires (std::ranges::sized_range<Views> && ...)
202 return std::ranges::min({
static_cast<common_size_t
>(sizes)...});
207 constexpr auto size() const
208 requires (
std::ranges::sized_range<Views const> && ...)
214 return std::ranges::min({
static_cast<common_size_t
>(sizes)...});
220template <
typename... range_ts>
221zip_view(range_ts &&...) -> zip_view<seqan3::detail::all_t<range_ts>...>;
223template <std::ranges::input_range... Views>
224 requires (std::ranges::view<Views> && ...) && (
sizeof...(Views) > 0)
226#if defined(__GNUC__) && (__GNUC__ == 10)
227class zip_view<Views...>::iterator :
public zip::iterator_category_t<Const, Views...>
229class zip_view<Views...>::iterator :
public zip::iterator_category_t<zip::all_forward<Const, Views...>>
233 constexpr explicit iterator(
234 zip::tuple_or_pair<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>...> current) :
235 current_(
std::move(current))
238 friend class zip_view<Views...>;
242 zip::tuple_or_pair<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>...> current_;
245 zip::all_random_access<Const, Views...>,
248 zip::all_bidirectional<Const, Views...>,
251 using value_type = zip::tuple_or_pair<std::ranges::range_value_t<view_helper::maybe_const<Const, Views>>...>;
252 using difference_type =
255 iterator() =
default;
256 constexpr iterator(iterator<!Const> i)
258 && (std::convertible_to<std::ranges::iterator_t<Views>,
259 std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>>
261 : current_(
std::move(i.current))
264 constexpr auto operator*()
const
266 return zip::tuple_transform(
267 [](
auto & i) ->
decltype(
auto)
274 constexpr iterator & operator++()
285 constexpr void operator++(
int)
290 constexpr iterator operator++(
int)
291 requires zip::all_forward<Const, Views...>
298 constexpr iterator & operator--()
299 requires zip::all_bidirectional<Const, Views...>
310 constexpr iterator operator--(
int)
311 requires zip::all_bidirectional<Const, Views...>
318 constexpr iterator & operator+=(difference_type x)
319 requires zip::all_random_access<Const, Views...>
322 [&]<
typename I>(I & i)
330 constexpr iterator & operator-=(difference_type x)
331 requires zip::all_random_access<Const, Views...>
334 [&]<
typename I>(I & i)
342 constexpr auto operator[](difference_type n)
const
343 requires zip::all_random_access<Const, Views...>
345 return zip::tuple_transform(
346 [&]<
typename I>(I & i) ->
decltype(
auto)
353 friend constexpr bool operator==(iterator
const & x, iterator
const & y)
354 requires (std::equality_comparable<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>> && ...)
356 if constexpr (zip::all_bidirectional<Const, Views...>)
358 return x.current_ == y.current_;
364 return ((std::get<N>(x.current_) == std::get<N>(y.current_)) || ...);
370 friend constexpr bool operator<(iterator
const & x, iterator
const & y)
371 requires zip::all_random_access<Const, Views...>
373 return x.current_ < y.current_;
376 friend constexpr bool operator>(iterator
const & x, iterator
const & y)
377 requires zip::all_random_access<Const, Views...>
382 friend constexpr bool operator<=(iterator
const & x, iterator
const & y)
383 requires zip::all_random_access<Const, Views...>
388 friend constexpr bool operator>=(iterator
const & x, iterator
const & y)
389 requires zip::all_random_access<Const, Views...>
394#ifdef __cpp_lib_three_way_comparison
395 friend constexpr auto operator<=>(iterator
const & x, iterator
const & y)
396 requires zip::all_random_access<Const, Views...>
397 && (std::three_way_comparable<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>> && ...)
399 return x.current_ <=> y.current_;
403 friend constexpr iterator operator+(iterator
const & i, difference_type n)
404 requires zip::all_random_access<Const, Views...>
411 friend constexpr iterator operator+(difference_type n, iterator
const & i)
412 requires zip::all_random_access<Const, Views...>
417 friend constexpr iterator operator-(iterator
const & i, difference_type n)
418 requires zip::all_random_access<Const, Views...>
425 friend constexpr difference_type operator-(iterator
const & x, iterator
const & y)
426 requires (std::sized_sentinel_for<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>,
427 std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>>
432 return std::ranges::min(
433 {
static_cast<difference_type
>(std::get<N>(x.current_) - std::get<N>(y.current_))...},
434 [](difference_type a, difference_type b)
436 return zip::abs(b) < zip::abs(a);
442 friend constexpr auto iter_move(iterator
const & i)
noexcept(
443 (
noexcept(std::ranges::iter_move(
444 std::declval<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>
const &>()))
447 std::ranges::range_rvalue_reference_t<view_helper::maybe_const<Const, Views>>>
450 return zip::tuple_transform(std::ranges::iter_move, i.current_);
453 friend constexpr void iter_swap(iterator
const & l, iterator
const & r)
noexcept(
454 (
noexcept(std::ranges::iter_swap(
455 std::declval<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>
const &>(),
456 std::declval<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>
const &>()))
458 requires (std::indirectly_swappable<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>> && ...)
462 (std::ranges::iter_swap(std::get<N>(l.current_), std::get<N>(r.current)), ...);
468template <std::ranges::input_range... Views>
469 requires (std::ranges::view<Views> && ...) && (
sizeof...(Views) > 0)
471class zip_view<Views...>::sentinel
474 constexpr explicit sentinel(
475 zip::tuple_or_pair<std::ranges::sentinel_t<view_helper::maybe_const<Const, Views>>...> end) :
479 friend class zip_view<Views...>;
483 zip::tuple_or_pair<std::ranges::sentinel_t<view_helper::maybe_const<Const, Views>>...> end_;
485 sentinel() =
default;
486 constexpr sentinel(sentinel<!Const> i)
488 && (std::convertible_to<std::ranges::sentinel_t<Views>,
489 std::ranges::sentinel_t<view_helper::maybe_const<Const, Views>>>
491 : end_(
std::move(i.end_))
494 template <
bool OtherConst>
495 requires (std::sentinel_for<std::ranges::sentinel_t<view_helper::maybe_const<Const, Views>>,
496 std::ranges::iterator_t<view_helper::maybe_const<OtherConst, Views>>>
498 friend constexpr bool operator==(iterator<OtherConst>
const & x, sentinel
const & y)
502 return ((std::get<N>(x.current_) == std::get<N>(y.end_)) || ...);
507 template <
bool OtherConst>
508 requires (std::sized_sentinel_for<std::ranges::sentinel_t<view_helper::maybe_const<Const, Views>>,
509 std::ranges::iterator_t<view_helper::maybe_const<OtherConst, Views>>>
512 operator-(iterator<OtherConst>
const & x, sentinel
const & y)
518 return std::ranges::min({
static_cast<return_t
>(std::get<N>(x.current_) - std::get<N>(y.end_))...},
519 [](return_t a, return_t b)
521 return zip::abs(b) < zip::abs(a);
527 template <
bool OtherConst>
528 requires (std::sized_sentinel_for<std::ranges::sentinel_t<view_helper::maybe_const<Const, Views>>,
529 std::ranges::iterator_t<view_helper::maybe_const<OtherConst, Views>>>
532 operator-(sentinel
const & y, iterator<OtherConst>
const & x)
540 template <
typename urng_t>
541 constexpr auto operator()(urng_t && rng)
const
543 return adaptor_from_functor{*
this, std::forward<urng_t>(rng)};
546 template <
typename... urng_ts>
547 requires (
sizeof...(urng_ts) == 0)
548 constexpr auto operator()(urng_ts &&... ranges)
const
550 return std::views::empty<seqan3::common_tuple<>>;
553 template <
typename... urng_ts>
554 requires (
sizeof...(urng_ts) > 1)
555 constexpr auto operator()(urng_ts &&... ranges)
const
557 return zip_view{std::forward<urng_ts>(ranges)...};
572inline constexpr auto zip = seqan3::detail::zip_fn{};
Provides seqan3::detail::adaptor_from_functor.
Provides seqan3::detail::all.
A std::tuple implementation that incorporates most changes from C++23's standard library.
Definition: common_tuple.hpp:31
Provides seqan3::common_tuple.
constexpr size_t size
The size of a type pack.
Definition: traits.hpp:146
constexpr auto zip
A view adaptor that takes several views and returns tuple-like values from every i-th element of each...
Definition: zip.hpp:572
constexpr auto elements
A view calling get on each element in a range.
Definition: elements.hpp:80
Provides implementation helper for seqan3::views::zip and seqan3::views::join_with.
T is_nothrow_move_constructible_v
The internal SeqAn3 namespace.
Definition: aligned_sequence_concept.hpp:29
The SeqAn namespace for views.
Definition: char_strictly_to.hpp:22
SeqAn specific customisations in the standard namespace.
The <ranges> header from C++20's standard library.
A std::pair implementation that incorporates most changes from C++23's standard library.
Definition: common_pair.hpp:28