30template <
typename... range_ts>
31concept zip_is_common = (
sizeof...(range_ts) == 1 && (std::ranges::common_range<range_ts> && ...))
32 || (!(std::ranges::bidirectional_range<range_ts> && ...)
33 && (std::ranges::common_range<range_ts> && ...))
34 || ((std::ranges::random_access_range<range_ts> && ...)
35 && (std::ranges::sized_range<range_ts> && ...));
38template <
typename... ts>
39struct tuple_or_pair_impl;
42template <
typename... ts>
43 requires (
sizeof...(ts) != 2)
44struct tuple_or_pair_impl<ts...>
50template <
typename... ts>
51 requires (
sizeof...(ts) == 2)
52struct tuple_or_pair_impl<ts...>
58template <
typename... ts>
59using tuple_or_pair = tuple_or_pair_impl<ts...>::type;
63constexpr t abs(t && v)
noexcept
65 if constexpr (std::is_signed_v<t>)
66 return v < 0 ? -v : v;
73template <
typename fun_t,
typename tuple_t>
74constexpr auto tuple_transform(fun_t && f, tuple_t && tuple)
77 [&]<
typename... ts>(ts &&...
elements)
79 return tuple_or_pair<std::invoke_result_t<fun_t &, ts>...>{
std::invoke(f, std::forward<ts>(
elements))...};
81 std::forward<tuple_t>(tuple));
86template <
typename fun_t,
typename tuple_t>
87constexpr void tuple_for_each(fun_t && f, tuple_t && tuple)
90 [&]<
typename... ts>(ts &&...
elements)
94 std::forward<tuple_t>(tuple));
97template <
bool is_const,
typename... range_ts>
98concept all_random_access = (std::ranges::random_access_range<view_helper::maybe_const<is_const, range_ts>> && ...);
100template <
bool is_const,
typename... range_ts>
101concept all_bidirectional = (std::ranges::bidirectional_range<view_helper::maybe_const<is_const, range_ts>> && ...);
103template <
bool is_const,
typename... range_ts>
104concept all_forward = (std::ranges::forward_range<view_helper::maybe_const<is_const, range_ts>> && ...);
107#if defined(__GNUC__) && (__GNUC__ == 10)
108template <
bool is_const,
typename... range_ts>
109concept all_contiguous = (std::ranges::contiguous_range<view_helper::maybe_const<is_const, range_ts>> && ...);
111template <
bool Const,
typename... Views>
112struct iterator_category_t
115 all_contiguous<Const, Views...>,
116 std::contiguous_iterator_tag,
118 all_random_access<Const, Views...>,
121 all_bidirectional<Const, Views...>,
127struct iterator_category_t;
129struct iterator_category_t<true>
134struct iterator_category_t<false>
140namespace seqan3::detail
143template <std::ranges::input_range... Views>
144 requires (std::ranges::view<Views> && ...) && (
sizeof...(Views) > 0)
145class zip_view :
public std::ranges::view_interface<zip_view<Views...>>
157 requires (std::is_default_constructible_v<Views> && ...)
159 constexpr explicit zip_view(Views... views) : views_(
std::
move(views)...)
162 constexpr auto begin()
163 requires (!(view_helper::simple_view<Views> && ...))
168 constexpr auto begin() const
169 requires (
std::ranges::range<Views const> && ...)
175 requires (!(view_helper::simple_view<Views> && ...))
177 if constexpr (!zip::zip_is_common<Views...>)
178 return sentinel<false>(zip::tuple_transform(std::ranges::end, views_));
179 else if constexpr ((std::ranges::random_access_range<Views> && ...))
182 return iterator<false>(zip::tuple_transform(std::ranges::end, views_));
185 constexpr auto end() const
186 requires (
std::ranges::range<Views const> && ...)
188 if constexpr (!zip::zip_is_common<Views
const...>)
189 return sentinel<true>(zip::tuple_transform(std::ranges::end, views_));
190 else if constexpr ((std::ranges::random_access_range<Views const> && ...))
193 return iterator<true>(zip::tuple_transform(std::ranges::end, views_));
196 constexpr auto size()
197 requires (std::ranges::sized_range<Views> && ...)
208 constexpr auto size() const
209 requires (
std::ranges::sized_range<Views const> && ...)
221template <
typename... range_ts>
222zip_view(range_ts &&...) -> zip_view<seqan3::detail::all_t<range_ts>...>;
224template <std::ranges::input_range... Views>
225 requires (std::ranges::view<Views> && ...) && (
sizeof...(Views) > 0)
227#if defined(__GNUC__) && (__GNUC__ == 10)
228class zip_view<Views...>::iterator :
public zip::iterator_category_t<Const, Views...>
230class zip_view<Views...>::iterator :
public zip::iterator_category_t<zip::all_forward<Const, Views...>>
234 constexpr explicit iterator(
235 zip::tuple_or_pair<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>...> current) :
239 friend class zip_view<Views...>;
243 zip::tuple_or_pair<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>...> current_;
246 zip::all_random_access<Const, Views...>,
249 zip::all_bidirectional<Const, Views...>,
252 using value_type = zip::tuple_or_pair<std::ranges::range_value_t<view_helper::maybe_const<Const, Views>>...>;
253 using difference_type =
256 iterator() =
default;
257 constexpr iterator(iterator<!Const> i)
259 && (std::convertible_to<std::ranges::iterator_t<Views>,
260 std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>>
262 : current_(
std::
move(i.current))
265 constexpr auto operator*()
const
267 return zip::tuple_transform(
268 [](
auto & i) ->
decltype(
auto)
275 constexpr iterator & operator++()
286 constexpr void operator++(
int)
291 constexpr iterator operator++(
int)
292 requires zip::all_forward<Const, Views...>
299 constexpr iterator & operator--()
300 requires zip::all_bidirectional<Const, Views...>
311 constexpr iterator operator--(
int)
312 requires zip::all_bidirectional<Const, Views...>
319 constexpr iterator & operator+=(difference_type x)
320 requires zip::all_random_access<Const, Views...>
323 [&]<
typename I>(I & i)
331 constexpr iterator & operator-=(difference_type x)
332 requires zip::all_random_access<Const, Views...>
335 [&]<
typename I>(I & i)
343 constexpr auto operator[](difference_type n)
const
344 requires zip::all_random_access<Const, Views...>
346 return zip::tuple_transform(
347 [&]<
typename I>(I & i) ->
decltype(
auto)
354 friend constexpr bool operator==(iterator
const & x, iterator
const & y)
355 requires (std::equality_comparable<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>> && ...)
357 if constexpr (zip::all_bidirectional<Const, Views...>)
359 return x.current_ == y.current_;
365 return ((std::get<N>(x.current_) == std::get<N>(y.current_)) || ...);
371 friend constexpr bool operator<(iterator
const & x, iterator
const & y)
372 requires zip::all_random_access<Const, Views...>
374 return x.current_ < y.current_;
377 friend constexpr bool operator>(iterator
const & x, iterator
const & y)
378 requires zip::all_random_access<Const, Views...>
383 friend constexpr bool operator<=(iterator
const & x, iterator
const & y)
384 requires zip::all_random_access<Const, Views...>
389 friend constexpr bool operator>=(iterator
const & x, iterator
const & y)
390 requires zip::all_random_access<Const, Views...>
395#ifdef __cpp_lib_three_way_comparison
396 friend constexpr auto operator<=>(iterator
const & x, iterator
const & y)
397 requires zip::all_random_access<Const, Views...>
398 && (std::three_way_comparable<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>> && ...)
400 return x.current_ <=> y.current_;
404 friend constexpr iterator operator+(iterator
const & i, difference_type n)
405 requires zip::all_random_access<Const, Views...>
412 friend constexpr iterator operator+(difference_type n, iterator
const & i)
413 requires zip::all_random_access<Const, Views...>
418 friend constexpr iterator operator-(iterator
const & i, difference_type n)
419 requires zip::all_random_access<Const, Views...>
426 friend constexpr difference_type operator-(iterator
const & x, iterator
const & y)
427 requires (std::sized_sentinel_for<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>,
428 std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>>
434 {
static_cast<difference_type
>(std::get<N>(x.current_) - std::get<N>(y.current_))...},
435 [](difference_type a, difference_type b)
437 return zip::abs(b) < zip::abs(a);
443 friend constexpr auto iter_move(iterator
const & i)
noexcept(
444 (
noexcept(std::ranges::iter_move(
445 std::declval<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>
const &>()))
448 std::ranges::range_rvalue_reference_t<view_helper::maybe_const<Const, Views>>>
451 return zip::tuple_transform(std::ranges::iter_move, i.current_);
454 friend constexpr void iter_swap(iterator
const & l, iterator
const & r)
noexcept(
455 (
noexcept(std::ranges::iter_swap(
456 std::declval<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>
const &>(),
457 std::declval<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>
const &>()))
459 requires (std::indirectly_swappable<std::ranges::iterator_t<view_helper::maybe_const<Const, Views>>> && ...)
463 (std::ranges::iter_swap(std::get<N>(l.current_), std::get<N>(r.current)), ...);
469template <std::ranges::input_range... Views>
470 requires (std::ranges::view<Views> && ...) && (
sizeof...(Views) > 0)
472class zip_view<Views...>::sentinel
475 constexpr explicit sentinel(
476 zip::tuple_or_pair<std::ranges::sentinel_t<view_helper::maybe_const<Const, Views>>...> end) :
480 friend class zip_view<Views...>;
484 zip::tuple_or_pair<std::ranges::sentinel_t<view_helper::maybe_const<Const, Views>>...> end_;
486 sentinel() =
default;
487 constexpr sentinel(sentinel<!Const> i)
489 && (std::convertible_to<std::ranges::sentinel_t<Views>,
490 std::ranges::sentinel_t<view_helper::maybe_const<Const, Views>>>
495 template <
bool OtherConst>
496 requires (std::sentinel_for<std::ranges::sentinel_t<view_helper::maybe_const<Const, Views>>,
497 std::ranges::iterator_t<view_helper::maybe_const<OtherConst, Views>>>
499 friend constexpr bool operator==(iterator<OtherConst>
const & x, sentinel
const & y)
503 return ((std::get<N>(x.current_) == std::get<N>(y.end_)) || ...);
508 template <
bool OtherConst>
509 requires (std::sized_sentinel_for<std::ranges::sentinel_t<view_helper::maybe_const<Const, Views>>,
510 std::ranges::iterator_t<view_helper::maybe_const<OtherConst, Views>>>
513 operator-(iterator<OtherConst>
const & x, sentinel
const & y)
519 return std::ranges::min({
static_cast<return_t
>(std::get<N>(x.current_) - std::get<N>(y.end_))...},
520 [](return_t a, return_t b)
522 return zip::abs(b) < zip::abs(a);
528 template <
bool OtherConst>
529 requires (std::sized_sentinel_for<std::ranges::sentinel_t<view_helper::maybe_const<Const, Views>>,
530 std::ranges::iterator_t<view_helper::maybe_const<OtherConst, Views>>>
533 operator-(sentinel
const & y, iterator<OtherConst>
const & x)
541 template <
typename urng_t>
542 constexpr auto operator()(urng_t && rng)
const
544 return adaptor_from_functor{*
this, std::forward<urng_t>(rng)};
547 template <
typename... urng_ts>
548 requires (
sizeof...(urng_ts) == 0)
549 constexpr auto operator()(urng_ts &&... ranges)
const
551 return std::views::empty<seqan3::common_tuple<>>;
554 template <
typename... urng_ts>
555 requires (
sizeof...(urng_ts) > 1)
556 constexpr auto operator()(urng_ts &&... ranges)
const
558 return zip_view{std::forward<urng_ts>(ranges)...};
573inline 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:29
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:573
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 SeqAn namespace for views.
Definition: char_strictly_to.hpp:22
SeqAn specific customisations in the standard namespace.
A std::pair implementation that incorporates most changes from C++23's standard library.
Definition: common_pair.hpp:28