25namespace bio::ranges::detail::zip
28template <
bool is_const,
typename t>
32template <
typename... range_ts>
33concept zip_is_common =
34 (
sizeof...(range_ts) == 1 && (std::ranges::common_range<range_ts> && ...)) ||
35 (!(std::ranges::bidirectional_range<range_ts> && ...) && (std::ranges::common_range<range_ts> && ...)) ||
36 ((std::ranges::random_access_range<range_ts> && ...) && (std::ranges::sized_range<range_ts> && ...));
40constexpr t abs(t && v)
noexcept
42 if constexpr (std::is_signed_v<t>)
43 return v < 0 ? -v : v;
50template <
typename fun_t,
typename tuple_t>
51constexpr auto tuple_transform(fun_t && f, tuple_t && tuple)
54 [&]<
typename... ts>(ts &&... elements)
56 std::forward<tuple_t>(tuple));
61template <
typename fun_t,
typename tuple_t>
62constexpr void tuple_for_each(fun_t && f, tuple_t && tuple)
64 std::apply([&]<
typename... ts>(ts &&... elements) { (
std::invoke(f, std::forward<ts>(elements)), ...); },
65 std::forward<tuple_t>(tuple));
68template <
bool is_const,
typename... range_ts>
69concept all_random_access = (std::ranges::random_access_range<maybe_const<is_const, range_ts>> && ...);
71template <
bool is_const,
typename... range_ts>
72concept all_bidirectional = (std::ranges::bidirectional_range<maybe_const<is_const, range_ts>> && ...);
74template <
bool is_const,
typename... range_ts>
75concept all_forward = (std::ranges::forward_range<maybe_const<is_const, range_ts>> && ...);
78#if defined(__GNUC__) && (__GNUC__ == 10)
79template <
bool is_const,
typename... range_ts>
80concept all_contiguous = (std::ranges::contiguous_range<maybe_const<is_const, range_ts>> && ...);
82template <
bool Const,
typename... Views>
83struct iterator_category_t
86 all_contiguous<Const, Views...>,
87 std::contiguous_iterator_tag,
89 all_random_access<Const, Views...>,
92 all_bidirectional<Const, Views...>,
98struct iterator_category_t;
100struct iterator_category_t<true>
105struct iterator_category_t<false>
111namespace bio::ranges::detail
114template <std::ranges::input_range... Views>
115 requires(std::ranges::view<Views> && ...) && (
sizeof...(Views) > 0)
116class zip_view :
public std::ranges::view_interface<zip_view<Views...>>
128 requires(std::is_default_constructible_v<Views> && ...)
130 constexpr explicit zip_view(Views... views) : views_(
std::
move(views)...) {}
132 constexpr auto begin()
133 requires(!(simple_view<Views> && ...))
138 constexpr auto begin() const
139 requires(
std::ranges::range<Views const> && ...)
145 requires(!(simple_view<Views> && ...))
147 if constexpr (!zip::zip_is_common<Views...>)
148 return sentinel<false>(zip::tuple_transform(std::ranges::end, views_));
149 else if constexpr ((std::ranges::random_access_range<Views> && ...))
152 return iterator<false>(zip::tuple_transform(std::ranges::end, views_));
155 constexpr auto end() const
156 requires(
std::ranges::range<Views const> && ...)
158 if constexpr (!zip::zip_is_common<Views
const...>)
159 return sentinel<true>(zip::tuple_transform(std::ranges::end, views_));
160 else if constexpr ((std::ranges::random_access_range<Views const> && ...))
163 return iterator<true>(zip::tuple_transform(std::ranges::end, views_));
166 constexpr auto size()
167 requires(std::ranges::sized_range<Views> && ...)
175 zip::tuple_transform(std::ranges::size, views_));
178 constexpr auto size() const
179 requires(
std::ranges::sized_range<Views const> && ...)
187 zip::tuple_transform(std::ranges::size, views_));
191template <
typename... range_ts>
192zip_view(range_ts &&...) -> zip_view<std::ranges::views::all_t<range_ts>...>;
194template <std::ranges::input_range... Views>
195 requires(std::ranges::view<Views> && ...) && (
sizeof...(Views) > 0)
197#if defined(__GNUC__) && (__GNUC__ == 10)
198class zip_view<Views...>::iterator :
public zip::iterator_category_t<Const, Views...>
200class zip_view<Views...>::iterator :
public zip::iterator_category_t<zip::all_forward<Const, Views...>>
204 constexpr explicit iterator(
std::tuple<std::ranges::iterator_t<zip::maybe_const<Const, Views>>...> current) :
208 friend class zip_view<Views...>;
215 zip::all_random_access<Const, Views...>,
218 zip::all_bidirectional<Const, Views...>,
224 iterator() =
default;
225 constexpr iterator(iterator<!Const> i)
226 requires Const && (std::convertible_to<std::ranges::iterator_t<Views>,
227 std::ranges::iterator_t<zip::maybe_const<Const, Views>>> &&
229 : current_(
std::
move(i.current))
232 constexpr auto operator*()
const
234 return zip::tuple_transform([](
auto & i) ->
decltype(
auto) {
return *i; }, current_);
237 constexpr iterator & operator++()
239 zip::tuple_for_each([](
auto & i) { ++i; }, current_);
243 constexpr void operator++(
int) { ++*
this; }
245 constexpr iterator operator++(
int)
246 requires zip::all_forward<Const, Views...>
253 constexpr iterator & operator--()
254 requires zip::all_bidirectional<Const, Views...>
256 zip::tuple_for_each([](
auto & i) { --i; }, current_);
260 constexpr iterator operator--(
int)
261 requires zip::all_bidirectional<Const, Views...>
268 constexpr iterator & operator+=(difference_type x)
269 requires zip::all_random_access<Const, Views...>
275 constexpr iterator & operator-=(difference_type x)
276 requires zip::all_random_access<Const, Views...>
282 constexpr auto operator[](difference_type n)
const
283 requires zip::all_random_access<Const, Views...>
285 return zip::tuple_transform([&]<
typename I>(I & i) ->
decltype(
auto)
290 friend constexpr bool operator==(iterator
const & x, iterator
const & y)
291 requires(std::equality_comparable<std::ranges::iterator_t<zip::maybe_const<Const, Views>>> && ...)
293 if constexpr (zip::all_bidirectional<Const, Views...>)
295 return x.current_ == y.current_;
300 return ((std::get<N>(x.current_) == std::get<N>(y.current_)) || ...);
305 friend constexpr auto operator<=>(iterator
const & x, iterator
const & y)
306 requires zip::all_random_access<Const, Views...> &&
307 (std::three_way_comparable<std::ranges::iterator_t<zip::maybe_const<Const, Views>>> && ...)
309 return x.current_ <=> y.current_;
312 friend constexpr iterator operator+(iterator
const & i, difference_type n)
313 requires zip::all_random_access<Const, Views...>
320 friend constexpr iterator operator+(difference_type n, iterator
const & i)
321 requires zip::all_random_access<Const, Views...>
326 friend constexpr iterator operator-(iterator
const & i, difference_type n)
327 requires zip::all_random_access<Const, Views...>
334 friend constexpr difference_type operator-(iterator
const & x, iterator
const & y)
335 requires(std::sized_sentinel_for<std::ranges::iterator_t<zip::maybe_const<Const, Views>>,
336 std::ranges::iterator_t<zip::maybe_const<Const, Views>>> &&
342 {
static_cast<difference_type
>(std::get<N>(x.current_) - std::get<N>(y.current_))...},
343 [](difference_type a, difference_type b) {
return zip::abs(b) < zip::abs(a); });
347 friend constexpr auto iter_move(iterator
const & i)
noexcept(
349 std::ranges::iter_move(
std::declval<std::ranges::iterator_t<zip::maybe_const<Const, Views>>
const &>())) &&
351 (std::is_nothrow_move_constructible_v<std::ranges::range_rvalue_reference_t<zip::maybe_const<Const, Views>>> &&
354 return zip::tuple_transform(std::ranges::iter_move, i.current_);
357 friend constexpr void iter_swap(iterator
const & l, iterator
const & r)
noexcept(
359 std::ranges::iter_swap(
std::declval<std::ranges::iterator_t<zip::maybe_const<Const, Views>>
const &>(),
360 std::declval<std::ranges::iterator_t<zip::maybe_const<Const, Views>>
const &>())) &&
362 requires(std::indirectly_swappable<std::ranges::iterator_t<zip::maybe_const<Const, Views>>> && ...)
365 (std::ranges::iter_swap(std::get<N>(l.current_), std::get<N>(r.current)), ...);
370template <std::ranges::input_range... Views>
371 requires(std::ranges::view<Views> && ...) && (
sizeof...(Views) > 0)
373class zip_view<Views...>::sentinel
376 constexpr explicit sentinel(
std::tuple<std::ranges::sentinel_t<zip::maybe_const<Const, Views>>...> end) :
380 friend class zip_view<Views...>;
386 sentinel() =
default;
387 constexpr sentinel(sentinel<!Const> i)
388 requires Const && (std::convertible_to<std::ranges::sentinel_t<Views>,
389 std::ranges::sentinel_t<zip::maybe_const<Const, Views>>> &&
394 template <
bool OtherConst>
395 requires(std::sentinel_for<std::ranges::sentinel_t<zip::maybe_const<Const, Views>>,
396 std::ranges::iterator_t<zip::maybe_const<OtherConst, Views>>> &&
398 friend constexpr
bool operator==(iterator<OtherConst> const & x, sentinel const & y)
404 template <
bool OtherConst>
405 requires(std::sized_sentinel_for<std::ranges::sentinel_t<zip::maybe_const<Const, Views>>,
406 std::ranges::iterator_t<zip::maybe_const<OtherConst, Views>>> &&
408 friend constexpr
std::common_type_t<
std::ranges::range_difference_t<zip::maybe_const<OtherConst, Views>>...>
409 operator-(iterator<OtherConst> const & x, sentinel const & y)
414 return std::ranges::min({
static_cast<return_t
>(std::get<N>(x.current_) - std::get<N>(y.end_))...},
415 [](return_t a, return_t b) {
return zip::abs(b) < zip::abs(a); });
419 template <
bool OtherConst>
420 requires(std::sized_sentinel_for<std::ranges::sentinel_t<zip::maybe_const<Const, Views>>,
421 std::ranges::iterator_t<zip::maybe_const<OtherConst, Views>>> &&
423 friend constexpr
std::common_type_t<
std::ranges::range_difference_t<zip::maybe_const<OtherConst, Views>>...>
424 operator-(sentinel const & y, iterator<OtherConst> const & x)
432 constexpr auto operator()()
const {
return std::views::empty<std::tuple<>>; }
434 template <
typename... urng_ts>
435 requires(
sizeof...(urng_ts) >= 1)
436 constexpr auto operator()(urng_ts &&... ranges)
const
438 return zip_view{std::views::all(std::forward<urng_ts>(ranges))...};
455inline constexpr auto zip = detail::zip_fn{};
constexpr auto size
A type trait that holds the size of a (semi-)alphabet.
Definition: concept.hpp:517
The BioC++ namespace for views.
constexpr auto zip
A view adaptor that produces a tuple-like value of all passed views.
Definition: zip.hpp:455
Additional non-standard concepts for ranges.
Auxiliary header for the views submodule .