Skip to content

Commit 065dc48

Browse files
JMazurkiewiczvar-const
authored andcommitted
[libc++][ranges] Implement P2443R1: views::chunk_by
This patch implements https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p2443r1.html (`views::chunk_by`). Reviewed By: #libc, var-const Differential Revision: https://reviews.llvm.org/D144767
1 parent 3e19b10 commit 065dc48

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2381
-59
lines changed

libcxx/docs/FeatureTestMacroTable.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -346,7 +346,7 @@ Status
346346
--------------------------------------------------- -----------------
347347
``__cpp_lib_ranges_chunk`` *unimplemented*
348348
--------------------------------------------------- -----------------
349-
``__cpp_lib_ranges_chunk_by`` *unimplemented*
349+
``__cpp_lib_ranges_chunk_by`` ``202202L``
350350
--------------------------------------------------- -----------------
351351
``__cpp_lib_ranges_iota`` *unimplemented*
352352
--------------------------------------------------- -----------------

libcxx/docs/ReleaseNotes/18.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ Implemented Papers
4141

4242
- P2497R0 - Testing for success or failure of ``<charconv>`` functions
4343
- P2697R1 - Interfacing ``bitset`` with ``string_view``
44-
44+
- P2443R1 - ``views::chunk_by``
4545

4646
Improvements and New Features
4747
-----------------------------

libcxx/docs/Status/Cxx23Papers.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@
4949
"`P2440R1 <https://wg21.link/P2440R1>`__","LWG","``ranges::iota``, ``ranges::shift_left`` and ``ranges::shift_right``","February 2022","","","|ranges|"
5050
"`P2441R2 <https://wg21.link/P2441R2>`__","LWG","``views::join_with``","February 2022","","","|ranges|"
5151
"`P2442R1 <https://wg21.link/P2442R1>`__","LWG","Windowing range adaptors: ``views::chunk`` and ``views::slide``","February 2022","","","|ranges|"
52-
"`P2443R1 <https://wg21.link/P2443R1>`__","LWG","``views::chunk_by``","February 2022","","","|ranges|"
52+
"`P2443R1 <https://wg21.link/P2443R1>`__","LWG","``views::chunk_by``","February 2022","|Complete|","18.0","|ranges|"
5353
"","","","","","",""
5454
"`P0009R18 <https://wg21.link/P0009R18>`__","LWG","mdspan: A Non-Owning Multidimensional Array Reference","July 2022","|In progress| [#note-P0009R18]_|",""
5555
"`P0429R9 <https://wg21.link/P0429R9>`__","LWG","A Standard ``flat_map``","July 2022","",""

libcxx/docs/Status/RangesViews.csv

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ C++23,`adjacent_transform <https://wg21.link/P2321R2>`_,Hui Xie,No patch yet,Not
3131
C++23,`join_with <https://wg21.link/P2441R2>`_,Unassigned,No patch yet,Not started
3232
C++23,`slide <https://wg21.link/P2442R1>`_,Unassigned,No patch yet,Not started
3333
C++23,`chunk <https://wg21.link/P2442R1>`_,Unassigned,No patch yet,Not started
34-
C++23,`chunk_by <https://wg21.link/P2443R1>`_,Unassigned,No patch yet,Not started
34+
C++23,`chunk_by <https://wg21.link/P2443R1>`_,Jakub Mazurkiewicz,`D144767 <https://llvm.org/D144767>`,✅
3535
C++23,`as_const <https://wg21.link/P2278R4>`_,Unassigned,No patch yet,Not started
3636
C++23,`as_rvalue <https://wg21.link/P2446R2>`_,Nikolas Klauser,`D137637 <https://llvm.org/D137637>`_,✅
3737
C++23,`stride <https://wg21.link/P1899R3>`_,Hristo Hristov and Will Hawkins,`D156924 <https://llvm.org/D156924>`_,In Progress

libcxx/include/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -602,6 +602,7 @@ set(files
602602
__ranges/access.h
603603
__ranges/all.h
604604
__ranges/as_rvalue_view.h
605+
__ranges/chunk_by_view.h
605606
__ranges/common_view.h
606607
__ranges/concepts.h
607608
__ranges/container_compatible_range.h

libcxx/include/__algorithm/ranges_adjacent_find.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@
2424
# pragma GCC system_header
2525
#endif
2626

27+
_LIBCPP_PUSH_MACROS
28+
#include <__undef_macros>
29+
2730
#if _LIBCPP_STD_VER >= 20
2831

2932
_LIBCPP_BEGIN_NAMESPACE_STD
@@ -75,4 +78,6 @@ _LIBCPP_END_NAMESPACE_STD
7578

7679
#endif // _LIBCPP_STD_VER >= 20
7780

81+
_LIBCPP_POP_MACROS
82+
7883
#endif // _LIBCPP___ALGORITHM_RANGES_ADJACENT_FIND_H
Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
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_CHUNK_BY_VIEW_H
11+
#define _LIBCPP___RANGES_CHUNK_BY_VIEW_H
12+
13+
#include <__algorithm/ranges_adjacent_find.h>
14+
#include <__assert>
15+
#include <__concepts/constructible.h>
16+
#include <__config>
17+
#include <__functional/bind_back.h>
18+
#include <__functional/invoke.h>
19+
#include <__functional/not_fn.h>
20+
#include <__functional/reference_wrapper.h>
21+
#include <__iterator/concepts.h>
22+
#include <__iterator/default_sentinel.h>
23+
#include <__iterator/iterator_traits.h>
24+
#include <__iterator/next.h>
25+
#include <__iterator/prev.h>
26+
#include <__memory/addressof.h>
27+
#include <__ranges/access.h>
28+
#include <__ranges/all.h>
29+
#include <__ranges/concepts.h>
30+
#include <__ranges/movable_box.h>
31+
#include <__ranges/non_propagating_cache.h>
32+
#include <__ranges/range_adaptor.h>
33+
#include <__ranges/reverse_view.h>
34+
#include <__ranges/subrange.h>
35+
#include <__ranges/view_interface.h>
36+
#include <__type_traits/conditional.h>
37+
#include <__type_traits/decay.h>
38+
#include <__type_traits/is_nothrow_constructible.h>
39+
#include <__type_traits/is_object.h>
40+
#include <__utility/forward.h>
41+
#include <__utility/in_place.h>
42+
#include <__utility/move.h>
43+
44+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
45+
# pragma GCC system_header
46+
#endif
47+
48+
_LIBCPP_PUSH_MACROS
49+
#include <__undef_macros>
50+
51+
_LIBCPP_BEGIN_NAMESPACE_STD
52+
53+
#if _LIBCPP_STD_VER >= 23
54+
55+
namespace ranges {
56+
57+
template <forward_range _View, indirect_binary_predicate<iterator_t<_View>, iterator_t<_View>> _Pred>
58+
requires view<_View> && is_object_v<_Pred>
59+
class chunk_by_view : public view_interface<chunk_by_view<_View, _Pred>> {
60+
_LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
61+
_LIBCPP_NO_UNIQUE_ADDRESS __movable_box<_Pred> __pred_;
62+
63+
// We cache the result of begin() to allow providing an amortized O(1).
64+
using _Cache = __non_propagating_cache<iterator_t<_View>>;
65+
_Cache __cached_begin_;
66+
67+
class __iterator;
68+
69+
_LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> __find_next(iterator_t<_View> __current) {
70+
_LIBCPP_ASSERT_UNCATEGORIZED(
71+
__pred_.__has_value(), "Trying to call __find_next() on a chunk_by_view that does not have a valid predicate.");
72+
73+
return ranges::next(ranges::adjacent_find(__current, ranges::end(__base_), std::not_fn(std::ref(*__pred_))),
74+
1,
75+
ranges::end(__base_));
76+
}
77+
78+
_LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> __find_prev(iterator_t<_View> __current)
79+
requires bidirectional_range<_View>
80+
{
81+
_LIBCPP_ASSERT_UNCATEGORIZED(
82+
__current != ranges::begin(__base_), "Trying to call __find_prev() on a begin iterator.");
83+
_LIBCPP_ASSERT_UNCATEGORIZED(
84+
__pred_.__has_value(), "Trying to call __find_prev() on a chunk_by_view that does not have a valid predicate.");
85+
86+
auto __first = ranges::begin(__base_);
87+
reverse_view __reversed{subrange{__first, __current}};
88+
auto __reversed_pred = [this]<class _Tp, class _Up>(_Tp&& __x, _Up&& __y) {
89+
return !std::invoke(*__pred_, std::forward<_Up>(__y), std::forward<_Tp>(__x));
90+
};
91+
return ranges::prev(ranges::adjacent_find(__reversed, __reversed_pred).base(), 1, std::move(__first));
92+
}
93+
94+
public:
95+
_LIBCPP_HIDE_FROM_ABI chunk_by_view()
96+
requires default_initializable<_View> && default_initializable<_Pred>
97+
= default;
98+
99+
_LIBCPP_HIDE_FROM_ABI constexpr explicit chunk_by_view(_View __base, _Pred __pred)
100+
: __base_(std::move(__base)), __pred_(in_place, std::move(__pred)) {}
101+
102+
_LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
103+
requires copy_constructible<_View>
104+
{
105+
return __base_;
106+
}
107+
108+
_LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
109+
110+
_LIBCPP_HIDE_FROM_ABI constexpr const _Pred& pred() const { return *__pred_; }
111+
112+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() {
113+
_LIBCPP_ASSERT_UNCATEGORIZED(
114+
__pred_.__has_value(), "Trying to call begin() on a chunk_by_view that does not have a valid predicate.");
115+
116+
auto __first = ranges::begin(__base_);
117+
if (!__cached_begin_.__has_value()) {
118+
__cached_begin_.__emplace(__find_next(__first));
119+
}
120+
return {*this, std::move(__first), *__cached_begin_};
121+
}
122+
123+
_LIBCPP_HIDE_FROM_ABI constexpr auto end() {
124+
if constexpr (common_range<_View>) {
125+
return __iterator{*this, ranges::end(__base_), ranges::end(__base_)};
126+
} else {
127+
return default_sentinel;
128+
}
129+
}
130+
};
131+
132+
template <class _Range, class _Pred>
133+
chunk_by_view(_Range&&, _Pred) -> chunk_by_view<views::all_t<_Range>, _Pred>;
134+
135+
template <forward_range _View, indirect_binary_predicate<iterator_t<_View>, iterator_t<_View>> _Pred>
136+
requires view<_View> && is_object_v<_Pred>
137+
class chunk_by_view<_View, _Pred>::__iterator {
138+
friend chunk_by_view;
139+
140+
chunk_by_view* __parent_ = nullptr;
141+
_LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_View> __current_ = iterator_t<_View>();
142+
_LIBCPP_NO_UNIQUE_ADDRESS iterator_t<_View> __next_ = iterator_t<_View>();
143+
144+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator(
145+
chunk_by_view& __parent, iterator_t<_View> __current, iterator_t<_View> __next)
146+
: __parent_(std::addressof(__parent)), __current_(__current), __next_(__next) {}
147+
148+
public:
149+
using value_type = subrange<iterator_t<_View>>;
150+
using difference_type = range_difference_t<_View>;
151+
using iterator_category = input_iterator_tag;
152+
using iterator_concept = conditional_t<bidirectional_range<_View>, bidirectional_iterator_tag, forward_iterator_tag>;
153+
154+
_LIBCPP_HIDE_FROM_ABI __iterator() = default;
155+
156+
_LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const {
157+
_LIBCPP_ASSERT_UNCATEGORIZED(__current_ != __next_, "Trying to dereference past-the-end chunk_by_view iterator.");
158+
return {__current_, __next_};
159+
}
160+
161+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() {
162+
_LIBCPP_ASSERT_UNCATEGORIZED(__current_ != __next_, "Trying to increment past end chunk_by_view iterator.");
163+
__current_ = __next_;
164+
__next_ = __parent_->__find_next(__current_);
165+
return *this;
166+
}
167+
168+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator++(int) {
169+
auto __tmp = *this;
170+
++*this;
171+
return __tmp;
172+
}
173+
174+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator--()
175+
requires bidirectional_range<_View>
176+
{
177+
__next_ = __current_;
178+
__current_ = __parent_->__find_prev(__next_);
179+
return *this;
180+
}
181+
182+
_LIBCPP_HIDE_FROM_ABI constexpr __iterator operator--(int)
183+
requires bidirectional_range<_View>
184+
{
185+
auto __tmp = *this;
186+
--*this;
187+
return __tmp;
188+
}
189+
190+
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, const __iterator& __y) {
191+
return __x.__current_ == __y.__current_;
192+
}
193+
194+
_LIBCPP_HIDE_FROM_ABI friend constexpr bool operator==(const __iterator& __x, default_sentinel_t) {
195+
return __x.__current_ == __x.__next_;
196+
}
197+
};
198+
199+
namespace views {
200+
namespace __chunk_by {
201+
struct __fn {
202+
template <class _Range, class _Pred>
203+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Range&& __range, _Pred&& __pred) const
204+
noexcept(noexcept(/**/ chunk_by_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred))))
205+
-> decltype(/*--*/ chunk_by_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred))) {
206+
return /*-------------*/ chunk_by_view(std::forward<_Range>(__range), std::forward<_Pred>(__pred));
207+
}
208+
209+
template <class _Pred>
210+
requires constructible_from<decay_t<_Pred>, _Pred>
211+
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Pred&& __pred) const
212+
noexcept(is_nothrow_constructible_v<decay_t<_Pred>, _Pred>) {
213+
return __range_adaptor_closure_t(std::__bind_back(*this, std::forward<_Pred>(__pred)));
214+
}
215+
};
216+
} // namespace __chunk_by
217+
218+
inline namespace __cpo {
219+
inline constexpr auto chunk_by = __chunk_by::__fn{};
220+
} // namespace __cpo
221+
} // namespace views
222+
} // namespace ranges
223+
224+
#endif // _LIBCPP_STD_VER >= 23
225+
226+
_LIBCPP_END_NAMESPACE_STD
227+
228+
_LIBCPP_POP_MACROS
229+
230+
#endif // _LIBCPP___RANGES_CHUNK_BY_VIEW_H

libcxx/include/__ranges/movable_box.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@
2626
# pragma GCC system_header
2727
#endif
2828

29+
_LIBCPP_PUSH_MACROS
30+
#include <__undef_macros>
31+
2932
_LIBCPP_BEGIN_NAMESPACE_STD
3033

3134
#if _LIBCPP_STD_VER >= 20
@@ -203,4 +206,6 @@ class __movable_box<_Tp> {
203206

204207
_LIBCPP_END_NAMESPACE_STD
205208

209+
_LIBCPP_POP_MACROS
210+
206211
#endif // _LIBCPP___RANGES_MOVABLE_BOX_H

libcxx/include/module.modulemap.in

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1659,6 +1659,7 @@ module std_private_ranges_all [system] {
16591659
export std_private_ranges_owning_view
16601660
}
16611661
module std_private_ranges_as_rvalue_view [system] { header "__ranges/as_rvalue_view.h" }
1662+
module std_private_ranges_chunk_by_view [system] { header "__ranages/chunk_by_view.h" }
16621663
module std_private_ranges_common_view [system] { header "__ranges/common_view.h" }
16631664
module std_private_ranges_concepts [system] {
16641665
header "__ranges/concepts.h"

libcxx/include/ranges

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -320,17 +320,24 @@ namespace std::ranges {
320320
class zip_view; // C++23
321321
322322
template<class... Views>
323-
inline constexpr bool enable_borrowed_range<zip_view<Views...>> = // C++23
323+
inline constexpr bool enable_borrowed_range<zip_view<Views...>> = // C++23
324324
(enable_borrowed_range<Views> && ...);
325325
326-
namespace views { inline constexpr unspecified zip = unspecified; } // C++23
326+
namespace views { inline constexpr unspecified zip = unspecified; } // C++23
327327
328328
// [range.as.rvalue]
329329
template <view V>
330330
requires input_range<V>
331-
class as_rvalue_view; // since C++23
331+
class as_rvalue_view; // C++23
332332
333-
namespace views { inline constexpr unspecified as_rvalue ) unspecified; } // since C++23
333+
namespace views { inline constexpr unspecified as_rvalue ) unspecified; } // C++23
334+
335+
[range.chunk.by]
336+
template<forward_range V, indirect_binary_predicate<iterator_t<V>, iterator_t<V>> Pred>
337+
requires view<V> && is_object_v<Pred>
338+
class chunk_by_view; // C++23
339+
340+
namespace views { inline constexpr unspecified chunk_by = unspecified; } // C++23
334341
}
335342
336343
namespace std {
@@ -373,6 +380,7 @@ namespace std {
373380
#include <__ranges/access.h>
374381
#include <__ranges/all.h>
375382
#include <__ranges/as_rvalue_view.h>
383+
#include <__ranges/chunk_by_view.h>
376384
#include <__ranges/common_view.h>
377385
#include <__ranges/concepts.h>
378386
#include <__ranges/counted.h>

libcxx/include/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ __cpp_lib_within_lifetime 202306L <type_traits>
435435
// # define __cpp_lib_print 202207L
436436
# define __cpp_lib_ranges_as_rvalue 202207L
437437
// # define __cpp_lib_ranges_chunk 202202L
438-
// # define __cpp_lib_ranges_chunk_by 202202L
438+
# define __cpp_lib_ranges_chunk_by 202202L
439439
// # define __cpp_lib_ranges_iota 202202L
440440
// # define __cpp_lib_ranges_join_with 202202L
441441
# define __cpp_lib_ranges_repeat 202207L

libcxx/modules/std/ranges.inc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,7 @@ export namespace std {
309309
namespace views {
310310
using std::ranges::views::slide;
311311
}
312+
#endif
312313

313314
// [range.chunk.by], chunk by view
314315
using std::ranges::chunk_by_view;
@@ -317,6 +318,7 @@ export namespace std {
317318
using std::ranges::views::chunk_by;
318319
}
319320

321+
#if 0
320322
// [range.stride], stride view
321323
using std::ranges::stride_view;
322324

0 commit comments

Comments
 (0)