1*4bdff4beSrobert // -*- C++ -*-
2*4bdff4beSrobert //===----------------------------------------------------------------------===//
3*4bdff4beSrobert //
4*4bdff4beSrobert // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5*4bdff4beSrobert // See https://llvm.org/LICENSE.txt for license information.
6*4bdff4beSrobert // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7*4bdff4beSrobert //
8*4bdff4beSrobert //===----------------------------------------------------------------------===//
9*4bdff4beSrobert 
10*4bdff4beSrobert #ifndef _LIBCPP___RANGES_ZIP_VIEW_H
11*4bdff4beSrobert #define _LIBCPP___RANGES_ZIP_VIEW_H
12*4bdff4beSrobert 
13*4bdff4beSrobert #include <__config>
14*4bdff4beSrobert 
15*4bdff4beSrobert #include <__algorithm/ranges_min.h>
16*4bdff4beSrobert #include <__compare/three_way_comparable.h>
17*4bdff4beSrobert #include <__concepts/convertible_to.h>
18*4bdff4beSrobert #include <__concepts/equality_comparable.h>
19*4bdff4beSrobert #include <__functional/invoke.h>
20*4bdff4beSrobert #include <__functional/operations.h>
21*4bdff4beSrobert #include <__iterator/concepts.h>
22*4bdff4beSrobert #include <__iterator/incrementable_traits.h>
23*4bdff4beSrobert #include <__iterator/iter_move.h>
24*4bdff4beSrobert #include <__iterator/iter_swap.h>
25*4bdff4beSrobert #include <__iterator/iterator_traits.h>
26*4bdff4beSrobert #include <__ranges/access.h>
27*4bdff4beSrobert #include <__ranges/all.h>
28*4bdff4beSrobert #include <__ranges/concepts.h>
29*4bdff4beSrobert #include <__ranges/empty_view.h>
30*4bdff4beSrobert #include <__ranges/enable_borrowed_range.h>
31*4bdff4beSrobert #include <__ranges/size.h>
32*4bdff4beSrobert #include <__ranges/view_interface.h>
33*4bdff4beSrobert #include <__utility/forward.h>
34*4bdff4beSrobert #include <__utility/integer_sequence.h>
35*4bdff4beSrobert #include <__utility/move.h>
36*4bdff4beSrobert #include <tuple>
37*4bdff4beSrobert #include <type_traits>
38*4bdff4beSrobert 
39*4bdff4beSrobert #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
40*4bdff4beSrobert #  pragma GCC system_header
41*4bdff4beSrobert #endif
42*4bdff4beSrobert 
43*4bdff4beSrobert _LIBCPP_PUSH_MACROS
44*4bdff4beSrobert #include <__undef_macros>
45*4bdff4beSrobert 
46*4bdff4beSrobert _LIBCPP_BEGIN_NAMESPACE_STD
47*4bdff4beSrobert 
48*4bdff4beSrobert #if _LIBCPP_STD_VER > 20
49*4bdff4beSrobert 
50*4bdff4beSrobert namespace ranges {
51*4bdff4beSrobert 
52*4bdff4beSrobert template <class... _Ranges>
53*4bdff4beSrobert concept __zip_is_common = (sizeof...(_Ranges) == 1 && (common_range<_Ranges> && ...)) ||
54*4bdff4beSrobert                           (!(bidirectional_range<_Ranges> && ...) && (common_range<_Ranges> && ...)) ||
55*4bdff4beSrobert                           ((random_access_range<_Ranges> && ...) && (sized_range<_Ranges> && ...));
56*4bdff4beSrobert 
57*4bdff4beSrobert template <typename _Tp, typename _Up>
58*4bdff4beSrobert auto __tuple_or_pair_test() -> pair<_Tp, _Up>;
59*4bdff4beSrobert 
60*4bdff4beSrobert template <typename... _Types>
61*4bdff4beSrobert   requires(sizeof...(_Types) != 2)
62*4bdff4beSrobert auto __tuple_or_pair_test() -> tuple<_Types...>;
63*4bdff4beSrobert 
64*4bdff4beSrobert template <class... _Types>
65*4bdff4beSrobert using __tuple_or_pair = decltype(__tuple_or_pair_test<_Types...>());
66*4bdff4beSrobert 
67*4bdff4beSrobert template <class _Fun, class _Tuple>
__tuple_transform(_Fun && __f,_Tuple && __tuple)68*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_transform(_Fun&& __f, _Tuple&& __tuple) {
69*4bdff4beSrobert   return std::apply(
70*4bdff4beSrobert       [&]<class... _Types>(_Types&&... __elements) {
71*4bdff4beSrobert         return __tuple_or_pair<invoke_result_t<_Fun&, _Types>...>(
72*4bdff4beSrobert             std::invoke(__f, std::forward<_Types>(__elements))...);
73*4bdff4beSrobert       },
74*4bdff4beSrobert       std::forward<_Tuple>(__tuple));
75*4bdff4beSrobert }
76*4bdff4beSrobert 
77*4bdff4beSrobert template <class _Fun, class _Tuple>
__tuple_for_each(_Fun && __f,_Tuple && __tuple)78*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr void __tuple_for_each(_Fun&& __f, _Tuple&& __tuple) {
79*4bdff4beSrobert   std::apply(
80*4bdff4beSrobert       [&]<class... _Types>(_Types&&... __elements) { (std::invoke(__f, std::forward<_Types>(__elements)), ...); },
81*4bdff4beSrobert       std::forward<_Tuple>(__tuple));
82*4bdff4beSrobert }
83*4bdff4beSrobert 
84*4bdff4beSrobert template <class _Fun, class _Tuple1, class _Tuple2, size_t... _Indices>
85*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr __tuple_or_pair<
86*4bdff4beSrobert     invoke_result_t<_Fun&, typename tuple_element<_Indices, remove_cvref_t<_Tuple1>>::type,
87*4bdff4beSrobert                     typename tuple_element<_Indices, remove_cvref_t<_Tuple2>>::type>...>
__tuple_zip_transform(_Fun && __f,_Tuple1 && __tuple1,_Tuple2 && __tuple2,index_sequence<_Indices...>)88*4bdff4beSrobert __tuple_zip_transform(_Fun&& __f, _Tuple1&& __tuple1, _Tuple2&& __tuple2, index_sequence<_Indices...>) {
89*4bdff4beSrobert   return {std::invoke(__f, std::get<_Indices>(std::forward<_Tuple1>(__tuple1)),
90*4bdff4beSrobert                       std::get<_Indices>(std::forward<_Tuple2>(__tuple2)))...};
91*4bdff4beSrobert }
92*4bdff4beSrobert 
93*4bdff4beSrobert template <class _Fun, class _Tuple1, class _Tuple2>
__tuple_zip_transform(_Fun && __f,_Tuple1 && __tuple1,_Tuple2 && __tuple2)94*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_zip_transform(_Fun&& __f, _Tuple1&& __tuple1, _Tuple2&& __tuple2) {
95*4bdff4beSrobert   return ranges::__tuple_zip_transform(__f, std::forward<_Tuple1>(__tuple1), std::forward<_Tuple2>(__tuple2),
96*4bdff4beSrobert                                        std::make_index_sequence<tuple_size<remove_cvref_t<_Tuple1>>::value>());
97*4bdff4beSrobert }
98*4bdff4beSrobert 
99*4bdff4beSrobert template <class _Fun, class _Tuple1, class _Tuple2, size_t... _Indices>
__tuple_zip_for_each(_Fun && __f,_Tuple1 && __tuple1,_Tuple2 && __tuple2,index_sequence<_Indices...>)100*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr void __tuple_zip_for_each(_Fun&& __f, _Tuple1&& __tuple1, _Tuple2&& __tuple2,
101*4bdff4beSrobert                                                           index_sequence<_Indices...>) {
102*4bdff4beSrobert   (std::invoke(__f, std::get<_Indices>(std::forward<_Tuple1>(__tuple1)),
103*4bdff4beSrobert                std::get<_Indices>(std::forward<_Tuple2>(__tuple2))),
104*4bdff4beSrobert    ...);
105*4bdff4beSrobert }
106*4bdff4beSrobert 
107*4bdff4beSrobert template <class _Fun, class _Tuple1, class _Tuple2>
__tuple_zip_for_each(_Fun && __f,_Tuple1 && __tuple1,_Tuple2 && __tuple2)108*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_zip_for_each(_Fun&& __f, _Tuple1&& __tuple1, _Tuple2&& __tuple2) {
109*4bdff4beSrobert   return ranges::__tuple_zip_for_each(__f, std::forward<_Tuple1>(__tuple1), std::forward<_Tuple2>(__tuple2),
110*4bdff4beSrobert                                       std::make_index_sequence<tuple_size<remove_cvref_t<_Tuple1>>::value>());
111*4bdff4beSrobert }
112*4bdff4beSrobert 
113*4bdff4beSrobert template <class _Tuple1, class _Tuple2>
__tuple_any_equals(const _Tuple1 & __tuple1,const _Tuple2 & __tuple2)114*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr bool __tuple_any_equals(const _Tuple1& __tuple1, const _Tuple2& __tuple2) {
115*4bdff4beSrobert   const auto __equals = ranges::__tuple_zip_transform(std::equal_to<>(), __tuple1, __tuple2);
116*4bdff4beSrobert   return std::apply([](auto... __bools) { return (__bools || ...); }, __equals);
117*4bdff4beSrobert }
118*4bdff4beSrobert 
119*4bdff4beSrobert // abs in cstdlib is not constexpr
120*4bdff4beSrobert // TODO : remove __abs once P0533R9 is implemented.
121*4bdff4beSrobert template <class _Tp>
__abs(_Tp __t)122*4bdff4beSrobert _LIBCPP_HIDE_FROM_ABI constexpr _Tp __abs(_Tp __t) {
123*4bdff4beSrobert   return __t < 0 ? -__t : __t;
124*4bdff4beSrobert }
125*4bdff4beSrobert 
126*4bdff4beSrobert template <input_range... _Views>
requires(view<_Views> &&...)127*4bdff4beSrobert   requires(view<_Views> && ...) && (sizeof...(_Views) > 0)
128*4bdff4beSrobert class zip_view : public view_interface<zip_view<_Views...>> {
129*4bdff4beSrobert 
130*4bdff4beSrobert   _LIBCPP_NO_UNIQUE_ADDRESS tuple<_Views...> __views_;
131*4bdff4beSrobert 
132*4bdff4beSrobert   template <bool>
133*4bdff4beSrobert   class __iterator;
134*4bdff4beSrobert 
135*4bdff4beSrobert   template <bool>
136*4bdff4beSrobert   class __sentinel;
137*4bdff4beSrobert 
138*4bdff4beSrobert public:
139*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
140*4bdff4beSrobert   zip_view() = default;
141*4bdff4beSrobert 
142*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
143*4bdff4beSrobert   constexpr explicit zip_view(_Views... __views) : __views_(std::move(__views)...) {}
144*4bdff4beSrobert 
145*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
146*4bdff4beSrobert   constexpr auto begin()
147*4bdff4beSrobert     requires(!(__simple_view<_Views> && ...)) {
148*4bdff4beSrobert     return __iterator<false>(ranges::__tuple_transform(ranges::begin, __views_));
149*4bdff4beSrobert   }
150*4bdff4beSrobert 
151*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
152*4bdff4beSrobert   constexpr auto begin() const
153*4bdff4beSrobert     requires(range<const _Views> && ...) {
154*4bdff4beSrobert     return __iterator<true>(ranges::__tuple_transform(ranges::begin, __views_));
155*4bdff4beSrobert   }
156*4bdff4beSrobert 
157*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
158*4bdff4beSrobert   constexpr auto end()
159*4bdff4beSrobert     requires(!(__simple_view<_Views> && ...)) {
160*4bdff4beSrobert     if constexpr (!__zip_is_common<_Views...>) {
161*4bdff4beSrobert       return __sentinel<false>(ranges::__tuple_transform(ranges::end, __views_));
162*4bdff4beSrobert     } else if constexpr ((random_access_range<_Views> && ...)) {
163*4bdff4beSrobert       return begin() + iter_difference_t<__iterator<false>>(size());
164*4bdff4beSrobert     } else {
165*4bdff4beSrobert       return __iterator<false>(ranges::__tuple_transform(ranges::end, __views_));
166*4bdff4beSrobert     }
167*4bdff4beSrobert   }
168*4bdff4beSrobert 
169*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
170*4bdff4beSrobert   constexpr auto end() const
171*4bdff4beSrobert     requires(range<const _Views> && ...) {
172*4bdff4beSrobert     if constexpr (!__zip_is_common<const _Views...>) {
173*4bdff4beSrobert       return __sentinel<true>(ranges::__tuple_transform(ranges::end, __views_));
174*4bdff4beSrobert     } else if constexpr ((random_access_range<const _Views> && ...)) {
175*4bdff4beSrobert       return begin() + iter_difference_t<__iterator<true>>(size());
176*4bdff4beSrobert     } else {
177*4bdff4beSrobert       return __iterator<true>(ranges::__tuple_transform(ranges::end, __views_));
178*4bdff4beSrobert     }
179*4bdff4beSrobert   }
180*4bdff4beSrobert 
181*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
182*4bdff4beSrobert   constexpr auto size()
183*4bdff4beSrobert     requires(sized_range<_Views> && ...) {
184*4bdff4beSrobert     return std::apply(
185*4bdff4beSrobert         [](auto... __sizes) {
186*4bdff4beSrobert           using _CT = make_unsigned_t<common_type_t<decltype(__sizes)...>>;
187*4bdff4beSrobert           return ranges::min({_CT(__sizes)...});
188*4bdff4beSrobert         },
189*4bdff4beSrobert         ranges::__tuple_transform(ranges::size, __views_));
190*4bdff4beSrobert   }
191*4bdff4beSrobert 
192*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
193*4bdff4beSrobert   constexpr auto size() const
194*4bdff4beSrobert     requires(sized_range<const _Views> && ...) {
195*4bdff4beSrobert     return std::apply(
196*4bdff4beSrobert         [](auto... __sizes) {
197*4bdff4beSrobert           using _CT = make_unsigned_t<common_type_t<decltype(__sizes)...>>;
198*4bdff4beSrobert           return ranges::min({_CT(__sizes)...});
199*4bdff4beSrobert         },
200*4bdff4beSrobert         ranges::__tuple_transform(ranges::size, __views_));
201*4bdff4beSrobert   }
202*4bdff4beSrobert };
203*4bdff4beSrobert 
204*4bdff4beSrobert template <class... _Ranges>
205*4bdff4beSrobert zip_view(_Ranges&&...) -> zip_view<views::all_t<_Ranges>...>;
206*4bdff4beSrobert 
207*4bdff4beSrobert template <bool _Const, class... _Views>
208*4bdff4beSrobert concept __zip_all_random_access = (random_access_range<__maybe_const<_Const, _Views>> && ...);
209*4bdff4beSrobert 
210*4bdff4beSrobert template <bool _Const, class... _Views>
211*4bdff4beSrobert concept __zip_all_bidirectional = (bidirectional_range<__maybe_const<_Const, _Views>> && ...);
212*4bdff4beSrobert 
213*4bdff4beSrobert template <bool _Const, class... _Views>
214*4bdff4beSrobert concept __zip_all_forward = (forward_range<__maybe_const<_Const, _Views>> && ...);
215*4bdff4beSrobert 
216*4bdff4beSrobert template <bool _Const, class... _Views>
__get_zip_view_iterator_tag()217*4bdff4beSrobert consteval auto __get_zip_view_iterator_tag() {
218*4bdff4beSrobert   if constexpr (__zip_all_random_access<_Const, _Views...>) {
219*4bdff4beSrobert     return random_access_iterator_tag();
220*4bdff4beSrobert   } else if constexpr (__zip_all_bidirectional<_Const, _Views...>) {
221*4bdff4beSrobert     return bidirectional_iterator_tag();
222*4bdff4beSrobert   } else if constexpr (__zip_all_forward<_Const, _Views...>) {
223*4bdff4beSrobert     return forward_iterator_tag();
224*4bdff4beSrobert   } else {
225*4bdff4beSrobert     return input_iterator_tag();
226*4bdff4beSrobert   }
227*4bdff4beSrobert }
228*4bdff4beSrobert 
229*4bdff4beSrobert template <bool _Const, class... _Views>
230*4bdff4beSrobert struct __zip_view_iterator_category_base {};
231*4bdff4beSrobert 
232*4bdff4beSrobert template <bool _Const, class... _Views>
233*4bdff4beSrobert   requires __zip_all_forward<_Const, _Views...>
234*4bdff4beSrobert struct __zip_view_iterator_category_base<_Const, _Views...> {
235*4bdff4beSrobert   using iterator_category = input_iterator_tag;
236*4bdff4beSrobert };
237*4bdff4beSrobert 
238*4bdff4beSrobert template <input_range... _Views>
239*4bdff4beSrobert   requires(view<_Views> && ...) && (sizeof...(_Views) > 0)
240*4bdff4beSrobert template <bool _Const>
241*4bdff4beSrobert class zip_view<_Views...>::__iterator : public __zip_view_iterator_category_base<_Const, _Views...> {
242*4bdff4beSrobert 
243*4bdff4beSrobert   __tuple_or_pair<iterator_t<__maybe_const<_Const, _Views>>...> __current_;
244*4bdff4beSrobert 
245*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
246*4bdff4beSrobert   constexpr explicit __iterator(__tuple_or_pair<iterator_t<__maybe_const<_Const, _Views>>...> __current)
247*4bdff4beSrobert       : __current_(std::move(__current)) {}
248*4bdff4beSrobert 
249*4bdff4beSrobert   template <bool>
250*4bdff4beSrobert   friend class zip_view<_Views...>::__iterator;
251*4bdff4beSrobert 
252*4bdff4beSrobert   template <bool>
253*4bdff4beSrobert   friend class zip_view<_Views...>::__sentinel;
254*4bdff4beSrobert 
255*4bdff4beSrobert   friend class zip_view<_Views...>;
256*4bdff4beSrobert 
257*4bdff4beSrobert public:
258*4bdff4beSrobert   using iterator_concept = decltype(__get_zip_view_iterator_tag<_Const, _Views...>());
259*4bdff4beSrobert   using value_type = __tuple_or_pair<range_value_t<__maybe_const<_Const, _Views>>...>;
260*4bdff4beSrobert   using difference_type = common_type_t<range_difference_t<__maybe_const<_Const, _Views>>...>;
261*4bdff4beSrobert 
262*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
263*4bdff4beSrobert   __iterator() = default;
264*4bdff4beSrobert 
265*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
266*4bdff4beSrobert   constexpr __iterator(__iterator<!_Const> __i)
267*4bdff4beSrobert     requires _Const && (convertible_to<iterator_t<_Views>, iterator_t<__maybe_const<_Const, _Views>>> && ...)
268*4bdff4beSrobert   : __current_(std::move(__i.__current_)) {}
269*4bdff4beSrobert 
270*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
271*4bdff4beSrobert   constexpr auto operator*() const {
272*4bdff4beSrobert     return ranges::__tuple_transform([](auto& __i) -> decltype(auto) { return *__i; }, __current_);
273*4bdff4beSrobert   }
274*4bdff4beSrobert 
275*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
276*4bdff4beSrobert   constexpr __iterator& operator++() {
277*4bdff4beSrobert     ranges::__tuple_for_each([](auto& __i) { ++__i; }, __current_);
278*4bdff4beSrobert     return *this;
279*4bdff4beSrobert   }
280*4bdff4beSrobert 
281*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
282*4bdff4beSrobert   constexpr void operator++(int) { ++*this; }
283*4bdff4beSrobert 
284*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
285*4bdff4beSrobert   constexpr __iterator operator++(int)
286*4bdff4beSrobert     requires __zip_all_forward<_Const, _Views...> {
287*4bdff4beSrobert     auto __tmp = *this;
288*4bdff4beSrobert     ++*this;
289*4bdff4beSrobert     return __tmp;
290*4bdff4beSrobert   }
291*4bdff4beSrobert 
292*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
293*4bdff4beSrobert   constexpr __iterator& operator--()
294*4bdff4beSrobert     requires __zip_all_bidirectional<_Const, _Views...> {
295*4bdff4beSrobert     ranges::__tuple_for_each([](auto& __i) { --__i; }, __current_);
296*4bdff4beSrobert     return *this;
297*4bdff4beSrobert   }
298*4bdff4beSrobert 
299*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
300*4bdff4beSrobert   constexpr __iterator operator--(int)
301*4bdff4beSrobert     requires __zip_all_bidirectional<_Const, _Views...> {
302*4bdff4beSrobert     auto __tmp = *this;
303*4bdff4beSrobert     --*this;
304*4bdff4beSrobert     return __tmp;
305*4bdff4beSrobert   }
306*4bdff4beSrobert 
307*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
308*4bdff4beSrobert   constexpr __iterator& operator+=(difference_type __x)
309*4bdff4beSrobert     requires __zip_all_random_access<_Const, _Views...> {
310*4bdff4beSrobert     ranges::__tuple_for_each([&]<class _Iter>(_Iter& __i) { __i += iter_difference_t<_Iter>(__x); }, __current_);
311*4bdff4beSrobert     return *this;
312*4bdff4beSrobert   }
313*4bdff4beSrobert 
314*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
315*4bdff4beSrobert   constexpr __iterator& operator-=(difference_type __x)
316*4bdff4beSrobert     requires __zip_all_random_access<_Const, _Views...> {
317*4bdff4beSrobert     ranges::__tuple_for_each([&]<class _Iter>(_Iter& __i) { __i -= iter_difference_t<_Iter>(__x); }, __current_);
318*4bdff4beSrobert     return *this;
319*4bdff4beSrobert   }
320*4bdff4beSrobert 
321*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
322*4bdff4beSrobert   constexpr auto operator[](difference_type __n) const
323*4bdff4beSrobert     requires __zip_all_random_access<_Const, _Views...> {
324*4bdff4beSrobert     return ranges::__tuple_transform(
325*4bdff4beSrobert         [&]<class _Iter>(_Iter& __i) -> decltype(auto) { return __i[iter_difference_t<_Iter>(__n)]; }, __current_);
326*4bdff4beSrobert   }
327*4bdff4beSrobert 
328*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
329*4bdff4beSrobert   friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
330*4bdff4beSrobert     requires(equality_comparable<iterator_t<__maybe_const<_Const, _Views>>> && ...) {
331*4bdff4beSrobert     if constexpr (__zip_all_bidirectional<_Const, _Views...>) {
332*4bdff4beSrobert       return __x.__current_ == __y.__current_;
333*4bdff4beSrobert     } else {
334*4bdff4beSrobert       return ranges::__tuple_any_equals(__x.__current_, __y.__current_);
335*4bdff4beSrobert     }
336*4bdff4beSrobert   }
337*4bdff4beSrobert 
338*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
339*4bdff4beSrobert   friend constexpr bool operator<(const __iterator& __x, const __iterator& __y)
340*4bdff4beSrobert     requires __zip_all_random_access<_Const, _Views...> {
341*4bdff4beSrobert     return __x.__current_ < __y.__current_;
342*4bdff4beSrobert   }
343*4bdff4beSrobert 
344*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
345*4bdff4beSrobert   friend constexpr bool operator>(const __iterator& __x, const __iterator& __y)
346*4bdff4beSrobert     requires __zip_all_random_access<_Const, _Views...> {
347*4bdff4beSrobert     return __y < __x;
348*4bdff4beSrobert   }
349*4bdff4beSrobert 
350*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
351*4bdff4beSrobert   friend constexpr bool operator<=(const __iterator& __x, const __iterator& __y)
352*4bdff4beSrobert     requires __zip_all_random_access<_Const, _Views...> {
353*4bdff4beSrobert     return !(__y < __x);
354*4bdff4beSrobert   }
355*4bdff4beSrobert 
356*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
357*4bdff4beSrobert   friend constexpr bool operator>=(const __iterator& __x, const __iterator& __y)
358*4bdff4beSrobert     requires __zip_all_random_access<_Const, _Views...> {
359*4bdff4beSrobert     return !(__x < __y);
360*4bdff4beSrobert   }
361*4bdff4beSrobert 
362*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
363*4bdff4beSrobert   friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y)
364*4bdff4beSrobert     requires __zip_all_random_access<_Const, _Views...> &&
365*4bdff4beSrobert              (three_way_comparable<iterator_t<__maybe_const<_Const, _Views>>> && ...) {
366*4bdff4beSrobert     return __x.__current_ <=> __y.__current_;
367*4bdff4beSrobert   }
368*4bdff4beSrobert 
369*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
370*4bdff4beSrobert   friend constexpr __iterator operator+(const __iterator& __i, difference_type __n)
371*4bdff4beSrobert     requires __zip_all_random_access<_Const, _Views...> {
372*4bdff4beSrobert     auto __r = __i;
373*4bdff4beSrobert     __r += __n;
374*4bdff4beSrobert     return __r;
375*4bdff4beSrobert   }
376*4bdff4beSrobert 
377*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
378*4bdff4beSrobert   friend constexpr __iterator operator+(difference_type __n, const __iterator& __i)
379*4bdff4beSrobert     requires __zip_all_random_access<_Const, _Views...> {
380*4bdff4beSrobert     return __i + __n;
381*4bdff4beSrobert   }
382*4bdff4beSrobert 
383*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
384*4bdff4beSrobert   friend constexpr __iterator operator-(const __iterator& __i, difference_type __n)
385*4bdff4beSrobert     requires __zip_all_random_access<_Const, _Views...> {
386*4bdff4beSrobert     auto __r = __i;
387*4bdff4beSrobert     __r -= __n;
388*4bdff4beSrobert     return __r;
389*4bdff4beSrobert   }
390*4bdff4beSrobert 
391*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
392*4bdff4beSrobert   friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y)
393*4bdff4beSrobert     requires(sized_sentinel_for<iterator_t<__maybe_const<_Const, _Views>>, iterator_t<__maybe_const<_Const, _Views>>> &&
394*4bdff4beSrobert              ...) {
395*4bdff4beSrobert     const auto __diffs = ranges::__tuple_zip_transform(minus<>(), __x.__current_, __y.__current_);
396*4bdff4beSrobert     return std::apply(
397*4bdff4beSrobert         [](auto... __ds) {
398*4bdff4beSrobert           return ranges::min({difference_type(__ds)...},
399*4bdff4beSrobert                              [](auto __a, auto __b) { return ranges::__abs(__a) < ranges::__abs(__b); });
400*4bdff4beSrobert         },
401*4bdff4beSrobert         __diffs);
402*4bdff4beSrobert   }
403*4bdff4beSrobert 
404*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
405*4bdff4beSrobert   friend constexpr auto iter_move(const __iterator& __i) noexcept(
406*4bdff4beSrobert       (noexcept(ranges::iter_move(std::declval<const iterator_t<__maybe_const<_Const, _Views>>&>())) && ...) &&
407*4bdff4beSrobert       (is_nothrow_move_constructible_v<range_rvalue_reference_t<__maybe_const<_Const, _Views>>> && ...)) {
408*4bdff4beSrobert     return ranges::__tuple_transform(ranges::iter_move, __i.__current_);
409*4bdff4beSrobert   }
410*4bdff4beSrobert 
411*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
412*4bdff4beSrobert   friend constexpr void iter_swap(const __iterator& __l, const __iterator& __r) noexcept(
413*4bdff4beSrobert       (noexcept(ranges::iter_swap(std::declval<const iterator_t<__maybe_const<_Const, _Views>>&>(),
414*4bdff4beSrobert                                   std::declval<const iterator_t<__maybe_const<_Const, _Views>>&>())) &&
415*4bdff4beSrobert        ...))
416*4bdff4beSrobert     requires(indirectly_swappable<iterator_t<__maybe_const<_Const, _Views>>> && ...) {
417*4bdff4beSrobert     ranges::__tuple_zip_for_each(ranges::iter_swap, __l.__current_, __r.__current_);
418*4bdff4beSrobert   }
419*4bdff4beSrobert };
420*4bdff4beSrobert 
421*4bdff4beSrobert template <input_range... _Views>
422*4bdff4beSrobert   requires(view<_Views> && ...) && (sizeof...(_Views) > 0)
423*4bdff4beSrobert template <bool _Const>
424*4bdff4beSrobert class zip_view<_Views...>::__sentinel {
425*4bdff4beSrobert 
426*4bdff4beSrobert   __tuple_or_pair<sentinel_t<__maybe_const<_Const, _Views>>...> __end_;
427*4bdff4beSrobert 
428*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
429*4bdff4beSrobert   constexpr explicit __sentinel(__tuple_or_pair<sentinel_t<__maybe_const<_Const, _Views>>...> __end) : __end_(__end) {}
430*4bdff4beSrobert 
431*4bdff4beSrobert   friend class zip_view<_Views...>;
432*4bdff4beSrobert 
433*4bdff4beSrobert   // hidden friend cannot access private member of iterator because they are friends of friends
434*4bdff4beSrobert   template <bool _OtherConst>
435*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto)
436*4bdff4beSrobert   __iter_current(zip_view<_Views...>::__iterator<_OtherConst> const& __it) {
437*4bdff4beSrobert     return (__it.__current_);
438*4bdff4beSrobert   }
439*4bdff4beSrobert 
440*4bdff4beSrobert public:
441*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
442*4bdff4beSrobert   __sentinel() = default;
443*4bdff4beSrobert 
444*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI
445*4bdff4beSrobert   constexpr __sentinel(__sentinel<!_Const> __i)
446*4bdff4beSrobert     requires _Const && (convertible_to<sentinel_t<_Views>, sentinel_t<__maybe_const<_Const, _Views>>> && ...)
447*4bdff4beSrobert   : __end_(std::move(__i.__end_)) {}
448*4bdff4beSrobert 
449*4bdff4beSrobert   template <bool _OtherConst>
450*4bdff4beSrobert     requires(sentinel_for<sentinel_t<__maybe_const<_Const, _Views>>, iterator_t<__maybe_const<_OtherConst, _Views>>> &&
451*4bdff4beSrobert              ...)
452*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
453*4bdff4beSrobert     return ranges::__tuple_any_equals(__iter_current(__x), __y.__end_);
454*4bdff4beSrobert   }
455*4bdff4beSrobert 
456*4bdff4beSrobert   template <bool _OtherConst>
457*4bdff4beSrobert     requires(
458*4bdff4beSrobert         sized_sentinel_for<sentinel_t<__maybe_const<_Const, _Views>>, iterator_t<__maybe_const<_OtherConst, _Views>>> &&
459*4bdff4beSrobert         ...)
460*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI friend constexpr common_type_t<range_difference_t<__maybe_const<_OtherConst, _Views>>...>
461*4bdff4beSrobert   operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
462*4bdff4beSrobert     const auto __diffs = ranges::__tuple_zip_transform(minus<>(), __iter_current(__x), __y.__end_);
463*4bdff4beSrobert     return std::apply(
464*4bdff4beSrobert         [](auto... __ds) {
465*4bdff4beSrobert           using _Diff = common_type_t<range_difference_t<__maybe_const<_OtherConst, _Views>>...>;
466*4bdff4beSrobert           return ranges::min({_Diff(__ds)...},
467*4bdff4beSrobert                              [](auto __a, auto __b) { return ranges::__abs(__a) < ranges::__abs(__b); });
468*4bdff4beSrobert         },
469*4bdff4beSrobert         __diffs);
470*4bdff4beSrobert   }
471*4bdff4beSrobert 
472*4bdff4beSrobert   template <bool _OtherConst>
473*4bdff4beSrobert     requires(
474*4bdff4beSrobert         sized_sentinel_for<sentinel_t<__maybe_const<_Const, _Views>>, iterator_t<__maybe_const<_OtherConst, _Views>>> &&
475*4bdff4beSrobert         ...)
476*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI friend constexpr common_type_t<range_difference_t<__maybe_const<_OtherConst, _Views>>...>
477*4bdff4beSrobert   operator-(const __sentinel& __y, const __iterator<_OtherConst>& __x) {
478*4bdff4beSrobert     return -(__x - __y);
479*4bdff4beSrobert   }
480*4bdff4beSrobert };
481*4bdff4beSrobert 
482*4bdff4beSrobert template <class... _Views>
483*4bdff4beSrobert inline constexpr bool enable_borrowed_range<zip_view<_Views...>> = (enable_borrowed_range<_Views> && ...);
484*4bdff4beSrobert 
485*4bdff4beSrobert namespace views {
486*4bdff4beSrobert namespace __zip {
487*4bdff4beSrobert 
488*4bdff4beSrobert struct __fn {
489*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto operator()() const noexcept { return empty_view<tuple<>>{}; }
490*4bdff4beSrobert 
491*4bdff4beSrobert   template <class... _Ranges>
492*4bdff4beSrobert   _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Ranges&&... __rs) const
493*4bdff4beSrobert       noexcept(noexcept(zip_view<all_t<_Ranges&&>...>(std::forward<_Ranges>(__rs)...)))
494*4bdff4beSrobert           -> decltype(zip_view<all_t<_Ranges&&>...>(std::forward<_Ranges>(__rs)...)) {
495*4bdff4beSrobert     return zip_view<all_t<_Ranges>...>(std::forward<_Ranges>(__rs)...);
496*4bdff4beSrobert   }
497*4bdff4beSrobert };
498*4bdff4beSrobert 
499*4bdff4beSrobert } // namespace __zip
500*4bdff4beSrobert inline namespace __cpo {
501*4bdff4beSrobert   inline constexpr auto zip = __zip::__fn{};
502*4bdff4beSrobert } // namespace __cpo
503*4bdff4beSrobert } // namespace views
504*4bdff4beSrobert } // namespace ranges
505*4bdff4beSrobert 
506*4bdff4beSrobert #endif // _LIBCPP_STD_VER > 20
507*4bdff4beSrobert 
508*4bdff4beSrobert _LIBCPP_END_NAMESPACE_STD
509*4bdff4beSrobert 
510*4bdff4beSrobert _LIBCPP_POP_MACROS
511*4bdff4beSrobert 
512*4bdff4beSrobert #endif // _LIBCPP___RANGES_ZIP_VIEW_H
513