Skip to content

Commit 6efbe3a

Browse files
committed
[libc++][ranges] implement std::ranges::zip_transform_view
1 parent c358979 commit 6efbe3a

File tree

15 files changed

+1521
-0
lines changed

15 files changed

+1521
-0
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -738,6 +738,7 @@ set(files
738738
__ranges/view_interface.h
739739
__ranges/views.h
740740
__ranges/zip_view.h
741+
__ranges/zip_transform_view.h
741742
__split_buffer
742743
__std_mbstate_t.h
743744
__stop_token/atomic_unique_lock.h
Lines changed: 357 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,357 @@
1+
// -*- C++ -*-
2+
//===----------------------------------------------------------------------===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#ifndef _LIBCPP___RANGES_ZIP_TRANSFORM_VIEW_H
11+
#define _LIBCPP___RANGES_ZIP_TRANSFORM_VIEW_H
12+
13+
#include <__config>
14+
15+
#include <__concepts/constructible.h>
16+
#include <__concepts/convertible_to.h>
17+
#include <__concepts/derived_from.h>
18+
#include <__concepts/equality_comparable.h>
19+
#include <__concepts/invocable.h>
20+
#include <__functional/invoke.h>
21+
#include <__iterator/concepts.h>
22+
#include <__iterator/incrementable_traits.h>
23+
#include <__iterator/iterator_traits.h>
24+
#include <__memory/addressof.h>
25+
#include <__ranges/access.h>
26+
#include <__ranges/all.h>
27+
#include <__ranges/concepts.h>
28+
#include <__ranges/empty_view.h>
29+
#include <__ranges/movable_box.h>
30+
#include <__ranges/view_interface.h>
31+
#include <__ranges/zip_view.h>
32+
#include <__type_traits/decay.h>
33+
#include <__type_traits/invoke.h>
34+
#include <__type_traits/is_object.h>
35+
#include <__type_traits/is_reference.h>
36+
#include <__type_traits/maybe_const.h>
37+
#include <__type_traits/remove_cvref.h>
38+
#include <__utility/forward.h>
39+
#include <__utility/in_place.h>
40+
#include <__utility/move.h>
41+
#include <tuple>
42+
43+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
44+
# pragma GCC system_header
45+
#endif
46+
47+
_LIBCPP_BEGIN_NAMESPACE_STD
48+
49+
#if _LIBCPP_STD_VER >= 23
50+
51+
namespace ranges {
52+
53+
template <move_constructible _Fn, input_range... _Views>
54+
requires(view<_Views> && ...) &&
55+
(sizeof...(_Views) > 0) && is_object_v<_Fn> && regular_invocable<_Fn&, range_reference_t<_Views>...> &&
56+
__can_reference<invoke_result_t<_Fn&, range_reference_t<_Views>...>>
57+
class zip_transform_view : public view_interface<zip_transform_view<_Fn, _Views...>> {
58+
_LIBCPP_NO_UNIQUE_ADDRESS zip_view<_Views...> __zip_;
59+
_LIBCPP_NO_UNIQUE_ADDRESS __movable_box<_Fn> __fun_;
60+
61+
using _InnerView = zip_view<_Views...>;
62+
template <bool _Const>
63+
using __ziperator = iterator_t<__maybe_const<_Const, _InnerView>>;
64+
template <bool Const>
65+
using __zentinel = sentinel_t<__maybe_const<Const, _InnerView>>;
66+
67+
template <bool>
68+
class __iterator;
69+
70+
template <bool>
71+
class __sentinel;
72+
73+
public:
74+
_LIBCPP_HIDE_FROM_ABI zip_transform_view() = default;
75+
76+
_LIBCPP_HIDE_FROM_ABI constexpr explicit zip_transform_view(_Fn __fun, _Views... __views)
77+
: __zip_(std::move(__views)...), __fun_(in_place, std::move(__fun)) {}
78+
79+
_LIBCPP_HIDE_FROM_ABI constexpr auto begin() { return __iterator<false>(*this, __zip_.begin()); }
80+
81+
_LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
82+
requires range<const _InnerView> && regular_invocable<const _Fn&, range_reference_t<const _Views>...>
83+
{
84+
return __iterator<true>(*this, __zip_.begin());
85+
}
86+
87+
_LIBCPP_HIDE_FROM_ABI constexpr auto end() {
88+
if constexpr (common_range<_InnerView>) {
89+
return __iterator<false>(*this, __zip_.end());
90+
} else {
91+
return __sentinel<false>(__zip_.end());
92+
}
93+
}
94+
95+
_LIBCPP_HIDE_FROM_ABI constexpr auto end() const
96+
requires range<const _InnerView> && regular_invocable<const _Fn&, range_reference_t<const _Views>...>
97+
{
98+
if constexpr (common_range<const _InnerView>) {
99+
return __iterator<true>(*this, __zip_.end());
100+
} else {
101+
return __sentinel<true>(__zip_.end());
102+
}
103+
}
104+
105+
_LIBCPP_HIDE_FROM_ABI constexpr auto size()
106+
requires sized_range<_InnerView>
107+
{
108+
return __zip_.size();
109+
}
110+
111+
_LIBCPP_HIDE_FROM_ABI constexpr auto size() const
112+
requires sized_range<const _InnerView>
113+
{
114+
return __zip_.size();
115+
}
116+
};
117+
118+
template <class _Fn, class... _Ranges>
119+
zip_transform_view(_Fn, _Ranges&&...) -> zip_transform_view<_Fn, views::all_t<_Ranges>...>;
120+
121+
template <bool _Const, class... _Views>
122+
concept __base_forward = forward_range<__maybe_const<_Const, zip_view<_Views...>>>;
123+
124+
template <bool _Const, class _Fn, class... _Views>
125+
struct __zip_transform_iterator_category_base {};
126+
127+
template <bool _Const, class _Fn, class... _Views>
128+
requires __base_forward<_Const, _Views...>
129+
struct __zip_transform_iterator_category_base<_Const, _Fn, _Views...> {
130+
private:
131+
template <class _View>
132+
using __tag = typename iterator_traits<iterator_t<__maybe_const<_Const, _View>>>::iterator_category;
133+
134+
static consteval auto __get_iterator_category() {
135+
if constexpr (!is_reference_v<invoke_result_t<__maybe_const<_Const, _Fn>&,
136+
range_reference_t<__maybe_const<_Const, _Views>>...>>) {
137+
return input_iterator_tag();
138+
} else if constexpr ((derived_from<__tag<_Views>, random_access_iterator_tag> && ...)) {
139+
return random_access_iterator_tag();
140+
} else if constexpr ((derived_from<__tag<_Views>, bidirectional_iterator_tag> && ...)) {
141+
return bidirectional_iterator_tag();
142+
} else if constexpr ((derived_from<__tag<_Views>, forward_iterator_tag> && ...)) {
143+
return forward_iterator_tag();
144+
} else {
145+
return input_iterator_tag();
146+
}
147+
}
148+
149+
public:
150+
using iterator_category = decltype(__get_iterator_category());
151+
};
152+
153+
template <move_constructible _Fn, input_range... _Views>
154+
requires(view<_Views> && ...) &&
155+
(sizeof...(_Views) > 0) && is_object_v<_Fn> && regular_invocable<_Fn&, range_reference_t<_Views>...> &&
156+
__can_reference<invoke_result_t<_Fn&, range_reference_t<_Views>...>>
157+
template <bool _Const>
158+
class zip_transform_view<_Fn, _Views...>::__iterator
159+
: public __zip_transform_iterator_category_base<_Const, _Fn, _Views...> {
160+
using _Parent = __maybe_const<_Const, zip_transform_view>;
161+
using _Base = __maybe_const<_Const, _InnerView>;
162+
163+
friend zip_transform_view<_Fn, _Views...>;
164+
165+
_Parent* __parent_ = nullptr;
166+
__ziperator<_Const> __inner_;
167+
168+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(_Parent& __parent, __ziperator<_Const> __inner)
169+
: __parent_(std::addressof(__parent)), __inner_(std::move(__inner)) {}
170+
171+
_LIBCPP_HIDE_FROM_ABI constexpr auto __get_deref_and_invoke() const noexcept {
172+
return [this](const auto&... __iters) noexcept(
173+
noexcept(std::invoke(*__parent_->__fun_, *__iters...))) -> decltype(auto) {
174+
return std::invoke(*__parent_->__fun_, *__iters...);
175+
};
176+
}
177+
178+
public:
179+
using iterator_concept = typename __ziperator<_Const>::iterator_concept;
180+
using value_type =
181+
remove_cvref_t<invoke_result_t<__maybe_const<_Const, _Fn>&, range_reference_t<__maybe_const<_Const, _Views>>...>>;
182+
using difference_type = range_difference_t<_Base>;
183+
184+
_LIBCPP_HIDE_FROM_ABI __iterator() = default;
185+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(__iterator<!_Const> __i)
186+
requires _Const && convertible_to<__ziperator<false>, __ziperator<_Const>>
187+
: __parent_(__i.__parent_), __inner_(std::move(__i.__inner_)) {}
188+
189+
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator*() const
190+
noexcept(noexcept(std::apply(__get_deref_and_invoke(), __zip_view_iterator_access::__get_underlying(__inner_)))) {
191+
return std::apply(__get_deref_and_invoke(), __zip_view_iterator_access::__get_underlying(__inner_));
192+
}
193+
194+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
195+
++__inner_;
196+
return *this;
197+
}
198+
199+
_LIBCPP_HIDE_FROM_ABI constexpr void operator++(int) { ++*this; }
200+
201+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int)
202+
requires forward_range<_Base>
203+
{
204+
auto __tmp = *this;
205+
++*this;
206+
return __tmp;
207+
}
208+
209+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
210+
requires bidirectional_range<_Base>
211+
{
212+
--__inner_;
213+
return *this;
214+
}
215+
216+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
217+
requires bidirectional_range<_Base>
218+
{
219+
auto __tmp = *this;
220+
--*this;
221+
return __tmp;
222+
}
223+
224+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator+=(difference_type __x)
225+
requires random_access_range<_Base>
226+
{
227+
__inner_ += __x;
228+
return *this;
229+
}
230+
231+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator-=(difference_type __x)
232+
requires random_access_range<_Base>
233+
{
234+
__inner_ -= __x;
235+
return *this;
236+
}
237+
238+
_LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator[](difference_type __n) const
239+
requires random_access_range<_Base>
240+
{
241+
return std::apply(
242+
[&]<class... _Is>(const _Is&... __iters) -> decltype(auto) {
243+
return std::invoke(*__parent_->__fun_, __iters[iter_difference_t<_Is>(__n)]...);
244+
},
245+
__zip_view_iterator_access::__get_underlying(__inner_));
246+
}
247+
248+
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y)
249+
requires equality_comparable<__ziperator<_Const>>
250+
{
251+
return __x.__inner_ == __y.__inner_;
252+
}
253+
254+
_LIBCPP_HIDE_FROM_ABI friend constexpr auto operator<=>(const __iterator& __x, const __iterator& __y)
255+
requires random_access_range<_Base>
256+
{
257+
return __x.__inner_ <=> __y.__inner_;
258+
}
259+
260+
_LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(const __iterator& __i, difference_type __n)
261+
requires random_access_range<_Base>
262+
{
263+
return __iterator(*__i.__parent_, __i.__inner_ + __n);
264+
}
265+
266+
_LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator+(difference_type __n, const __iterator& __i)
267+
requires random_access_range<_Base>
268+
{
269+
return __iterator(*__i.__parent_, __i.__inner_ + __n);
270+
}
271+
272+
_LIBCPP_HIDE_FROM_ABI friend constexpr __iterator operator-(const __iterator& __i, difference_type __n)
273+
requires random_access_range<_Base>
274+
{
275+
return __iterator(*__i.__parent_, __i.__inner_ - __n);
276+
}
277+
278+
_LIBCPP_HIDE_FROM_ABI friend constexpr difference_type operator-(const __iterator& __x, const __iterator& __y)
279+
requires sized_sentinel_for<__ziperator<_Const>, __ziperator<_Const>>
280+
{
281+
return __x.__inner_ - __y.__inner_;
282+
}
283+
};
284+
285+
template <move_constructible _Fn, input_range... _Views>
286+
requires(view<_Views> && ...) &&
287+
(sizeof...(_Views) > 0) && is_object_v<_Fn> && regular_invocable<_Fn&, range_reference_t<_Views>...> &&
288+
__can_reference<invoke_result_t<_Fn&, range_reference_t<_Views>...>>
289+
template <bool _Const>
290+
class zip_transform_view<_Fn, _Views...>::__sentinel {
291+
__zentinel<_Const> __inner_;
292+
293+
friend zip_transform_view<_Fn, _Views...>;
294+
295+
_LIBCPP_HIDE_FROM_ABI constexpr explicit __sentinel(__zentinel<_Const> __inner) : __inner_(__inner) {}
296+
297+
public:
298+
_LIBCPP_HIDE_FROM_ABI __sentinel() = default;
299+
300+
_LIBCPP_HIDE_FROM_ABI constexpr __sentinel(__sentinel<!_Const> __i)
301+
requires _Const && convertible_to<__zentinel<false>, __zentinel<_Const>>
302+
: __inner_(__i.__inner_) {}
303+
304+
template <bool _OtherConst>
305+
requires sentinel_for<__zentinel<_Const>, __ziperator<_OtherConst>>
306+
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
307+
return __x.__inner_ == __y.__inner_;
308+
}
309+
310+
template <bool _OtherConst>
311+
requires sized_sentinel_for<__zentinel<_Const>, __ziperator<_OtherConst>>
312+
_LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _InnerView>>
313+
operator-(const __iterator<_OtherConst>& __x, const __sentinel& __y) {
314+
return __x.__inner_ - __y.__inner_;
315+
}
316+
317+
template <bool _OtherConst>
318+
requires sized_sentinel_for<__zentinel<_Const>, __ziperator<_OtherConst>>
319+
_LIBCPP_HIDE_FROM_ABI friend constexpr range_difference_t<__maybe_const<_OtherConst, _InnerView>>
320+
operator-(const __sentinel& __x, const __iterator<_OtherConst>& __y) {
321+
return __x.__inner_ - __y.__inner_;
322+
}
323+
};
324+
325+
namespace views {
326+
namespace __zip_transform {
327+
328+
struct __fn {
329+
template <class _Fn>
330+
requires(move_constructible<decay_t<_Fn>> && regular_invocable<decay_t<_Fn>&> &&
331+
is_object_v<invoke_result_t<decay_t<_Fn>&>>)
332+
_LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Fn&&) const
333+
noexcept(noexcept(auto(views::empty<decay_t<invoke_result_t<decay_t<_Fn>&>>>))) {
334+
return views::empty<decay_t<invoke_result_t<decay_t<_Fn>&>>>;
335+
}
336+
337+
template <class _Fn, class... _Ranges>
338+
requires(sizeof...(_Ranges) > 0)
339+
_LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Fn&& __fun, _Ranges&&... __rs) const
340+
noexcept(noexcept(zip_transform_view(std::forward<_Fn>(__fun), std::forward<_Ranges>(__rs)...)))
341+
-> decltype(zip_transform_view(std::forward<_Fn>(__fun), std::forward<_Ranges>(__rs)...)) {
342+
return zip_transform_view(std::forward<_Fn>(__fun), std::forward<_Ranges>(__rs)...);
343+
}
344+
};
345+
346+
} // namespace __zip_transform
347+
inline namespace __cpo {
348+
inline constexpr auto zip_transform = __zip_transform::__fn{};
349+
} // namespace __cpo
350+
} // namespace views
351+
} // namespace ranges
352+
353+
#endif // _LIBCPP_STD_VER >= 23
354+
355+
_LIBCPP_END_NAMESPACE_STD
356+
357+
#endif // _LIBCPP___RANGES_ZIP_TRANSFORM_VIEW_H

libcxx/include/__ranges/zip_view.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,13 @@ struct __zip_view_iterator_category_base<_Const, _Views...> {
235235
using iterator_category = input_iterator_tag;
236236
};
237237

238+
struct __zip_view_iterator_access {
239+
template <class _Iter>
240+
_LIBCPP_HIDE_FROM_ABI static constexpr decltype(auto) __get_underlying(_Iter& __iter) noexcept {
241+
return (__iter.__current_);
242+
}
243+
};
244+
238245
template <input_range... _Views>
239246
requires(view<_Views> && ...) && (sizeof...(_Views) > 0)
240247
template <bool _Const>
@@ -255,6 +262,7 @@ class zip_view<_Views...>::__iterator : public __zip_view_iterator_category_base
255262
static constexpr bool __is_zip_view_iterator = true;
256263

257264
friend struct __product_iterator_traits<__iterator>;
265+
friend __zip_view_iterator_access;
258266

259267
public:
260268
using iterator_concept = decltype(ranges::__get_zip_view_iterator_tag<_Const, _Views...>());

0 commit comments

Comments
 (0)