Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / libcxx / include / __ranges / lazy_split_view.h
blob04182a530fc5a6ed8d0330bcddd743d0a2d8b306
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 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___RANGES_LAZY_SPLIT_VIEW_H
11 #define _LIBCPP___RANGES_LAZY_SPLIT_VIEW_H
13 #include <__algorithm/ranges_find.h>
14 #include <__algorithm/ranges_mismatch.h>
15 #include <__assert>
16 #include <__concepts/constructible.h>
17 #include <__concepts/convertible_to.h>
18 #include <__concepts/derived_from.h>
19 #include <__config>
20 #include <__functional/bind_back.h>
21 #include <__functional/ranges_operations.h>
22 #include <__iterator/concepts.h>
23 #include <__iterator/default_sentinel.h>
24 #include <__iterator/incrementable_traits.h>
25 #include <__iterator/indirectly_comparable.h>
26 #include <__iterator/iter_move.h>
27 #include <__iterator/iter_swap.h>
28 #include <__iterator/iterator_traits.h>
29 #include <__memory/addressof.h>
30 #include <__ranges/access.h>
31 #include <__ranges/all.h>
32 #include <__ranges/concepts.h>
33 #include <__ranges/non_propagating_cache.h>
34 #include <__ranges/range_adaptor.h>
35 #include <__ranges/single_view.h>
36 #include <__ranges/subrange.h>
37 #include <__ranges/view_interface.h>
38 #include <__type_traits/conditional.h>
39 #include <__type_traits/decay.h>
40 #include <__type_traits/is_nothrow_constructible.h>
41 #include <__type_traits/maybe_const.h>
42 #include <__type_traits/remove_reference.h>
43 #include <__utility/forward.h>
44 #include <__utility/move.h>
46 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
47 # pragma GCC system_header
48 #endif
50 _LIBCPP_BEGIN_NAMESPACE_STD
52 #if _LIBCPP_STD_VER >= 20
54 namespace ranges {
56 template <auto> struct __require_constant;
58 template <class _Range>
59 concept __tiny_range =
60 sized_range<_Range> &&
61 requires { typename __require_constant<remove_reference_t<_Range>::size()>; } &&
62 (remove_reference_t<_Range>::size() <= 1);
64 template <input_range _View, forward_range _Pattern>
65 requires view<_View> && view<_Pattern> &&
66 indirectly_comparable<iterator_t<_View>, iterator_t<_Pattern>, ranges::equal_to> &&
67 (forward_range<_View> || __tiny_range<_Pattern>)
68 class lazy_split_view : public view_interface<lazy_split_view<_View, _Pattern>> {
70 _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
71 _LIBCPP_NO_UNIQUE_ADDRESS _Pattern __pattern_ = _Pattern();
73 using _MaybeCurrent = _If<!forward_range<_View>, __non_propagating_cache<iterator_t<_View>>, __empty_cache>;
74 _LIBCPP_NO_UNIQUE_ADDRESS _MaybeCurrent __current_ = _MaybeCurrent();
76 template <bool> struct __outer_iterator;
77 template <bool> struct __inner_iterator;
79 public:
80 _LIBCPP_HIDE_FROM_ABI
81 lazy_split_view()
82 requires default_initializable<_View> && default_initializable<_Pattern> = default;
84 _LIBCPP_HIDE_FROM_ABI
85 constexpr _LIBCPP_EXPLICIT_SINCE_CXX23 lazy_split_view(_View __base, _Pattern __pattern)
86 : __base_(std::move(__base)), __pattern_(std::move(__pattern)) {}
88 template <input_range _Range>
89 requires constructible_from<_View, views::all_t<_Range>> &&
90 constructible_from<_Pattern, single_view<range_value_t<_Range>>>
91 _LIBCPP_HIDE_FROM_ABI
92 constexpr _LIBCPP_EXPLICIT_SINCE_CXX23 lazy_split_view(_Range&& __r, range_value_t<_Range> __e)
93 : __base_(views::all(std::forward<_Range>(__r)))
94 , __pattern_(views::single(std::move(__e))) {}
96 _LIBCPP_HIDE_FROM_ABI
97 constexpr _View base() const& requires copy_constructible<_View> { return __base_; }
98 _LIBCPP_HIDE_FROM_ABI
99 constexpr _View base() && { return std::move(__base_); }
101 _LIBCPP_HIDE_FROM_ABI
102 constexpr auto begin() {
103 if constexpr (forward_range<_View>) {
104 return __outer_iterator<__simple_view<_View> && __simple_view<_Pattern>>{*this, ranges::begin(__base_)};
105 } else {
106 __current_.__emplace(ranges::begin(__base_));
107 return __outer_iterator<false>{*this};
111 _LIBCPP_HIDE_FROM_ABI
112 constexpr auto begin() const requires forward_range<_View> && forward_range<const _View> {
113 return __outer_iterator<true>{*this, ranges::begin(__base_)};
116 _LIBCPP_HIDE_FROM_ABI
117 constexpr auto end() requires forward_range<_View> && common_range<_View> {
118 return __outer_iterator<__simple_view<_View> && __simple_view<_Pattern>>{*this, ranges::end(__base_)};
121 _LIBCPP_HIDE_FROM_ABI
122 constexpr auto end() const {
123 if constexpr (forward_range<_View> && forward_range<const _View> && common_range<const _View>) {
124 return __outer_iterator<true>{*this, ranges::end(__base_)};
125 } else {
126 return default_sentinel;
130 private:
132 template <class>
133 struct __outer_iterator_category {};
135 template <forward_range _Tp>
136 struct __outer_iterator_category<_Tp> {
137 using iterator_category = input_iterator_tag;
140 template <bool _Const>
141 struct __outer_iterator : __outer_iterator_category<__maybe_const<_Const, _View>> {
142 private:
143 template <bool>
144 friend struct __inner_iterator;
145 friend __outer_iterator<true>;
147 using _Parent = __maybe_const<_Const, lazy_split_view>;
148 using _Base = __maybe_const<_Const, _View>;
150 _Parent* __parent_ = nullptr;
151 using _MaybeCurrent = _If<forward_range<_View>, iterator_t<_Base>, __empty_cache>;
152 _LIBCPP_NO_UNIQUE_ADDRESS _MaybeCurrent __current_ = _MaybeCurrent();
153 bool __trailing_empty_ = false;
155 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
156 constexpr auto& __current() noexcept {
157 if constexpr (forward_range<_View>) {
158 return __current_;
159 } else {
160 return *__parent_->__current_;
164 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
165 constexpr const auto& __current() const noexcept {
166 if constexpr (forward_range<_View>) {
167 return __current_;
168 } else {
169 return *__parent_->__current_;
173 // Workaround for the GCC issue that doesn't allow calling `__parent_->__base_` from friend functions (because
174 // `__base_` is private).
175 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
176 constexpr auto& __parent_base() const noexcept {
177 return __parent_->__base_;
180 public:
181 // using iterator_category = inherited;
182 using iterator_concept = conditional_t<forward_range<_Base>, forward_iterator_tag, input_iterator_tag>;
183 using difference_type = range_difference_t<_Base>;
185 struct value_type : view_interface<value_type> {
186 private:
187 __outer_iterator __i_ = __outer_iterator();
189 public:
190 _LIBCPP_HIDE_FROM_ABI
191 value_type() = default;
192 _LIBCPP_HIDE_FROM_ABI
193 constexpr explicit value_type(__outer_iterator __i)
194 : __i_(std::move(__i)) {}
196 _LIBCPP_HIDE_FROM_ABI
197 constexpr __inner_iterator<_Const> begin() const { return __inner_iterator<_Const>{__i_}; }
198 _LIBCPP_HIDE_FROM_ABI
199 constexpr default_sentinel_t end() const noexcept { return default_sentinel; }
202 _LIBCPP_HIDE_FROM_ABI
203 __outer_iterator() = default;
205 _LIBCPP_HIDE_FROM_ABI
206 constexpr explicit __outer_iterator(_Parent& __parent)
207 requires (!forward_range<_Base>)
208 : __parent_(std::addressof(__parent)) {}
210 _LIBCPP_HIDE_FROM_ABI
211 constexpr __outer_iterator(_Parent& __parent, iterator_t<_Base> __current)
212 requires forward_range<_Base>
213 : __parent_(std::addressof(__parent)), __current_(std::move(__current)) {}
215 _LIBCPP_HIDE_FROM_ABI
216 constexpr __outer_iterator(__outer_iterator<!_Const> __i)
217 requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
218 : __parent_(__i.__parent_), __current_(std::move(__i.__current_)) {}
220 _LIBCPP_HIDE_FROM_ABI
221 constexpr value_type operator*() const { return value_type{*this}; }
223 _LIBCPP_HIDE_FROM_ABI
224 constexpr __outer_iterator& operator++() {
225 const auto __end = ranges::end(__parent_->__base_);
226 if (__current() == __end) {
227 __trailing_empty_ = false;
228 return *this;
231 const auto [__pbegin, __pend] = ranges::subrange{__parent_->__pattern_};
232 if (__pbegin == __pend) {
233 // Empty pattern: split on every element in the input range
234 ++__current();
236 } else if constexpr (__tiny_range<_Pattern>) {
237 // One-element pattern: we can use `ranges::find`.
238 __current() = ranges::find(std::move(__current()), __end, *__pbegin);
239 if (__current() != __end) {
240 // Make sure we point to after the separator we just found.
241 ++__current();
242 if (__current() == __end)
243 __trailing_empty_ = true;
246 } else {
247 // General case for n-element pattern.
248 do {
249 const auto [__b, __p] = ranges::mismatch(__current(), __end, __pbegin, __pend);
250 if (__p == __pend) {
251 __current() = __b;
252 if (__current() == __end) {
253 __trailing_empty_ = true;
255 break; // The pattern matched; skip it.
257 } while (++__current() != __end);
260 return *this;
263 _LIBCPP_HIDE_FROM_ABI
264 constexpr decltype(auto) operator++(int) {
265 if constexpr (forward_range<_Base>) {
266 auto __tmp = *this;
267 ++*this;
268 return __tmp;
270 } else {
271 ++*this;
275 _LIBCPP_HIDE_FROM_ABI
276 friend constexpr bool operator==(const __outer_iterator& __x, const __outer_iterator& __y)
277 requires forward_range<_Base> {
278 return __x.__current_ == __y.__current_ && __x.__trailing_empty_ == __y.__trailing_empty_;
281 _LIBCPP_HIDE_FROM_ABI
282 friend constexpr bool operator==(const __outer_iterator& __x, default_sentinel_t) {
283 _LIBCPP_ASSERT_UNCATEGORIZED(__x.__parent_, "Cannot call comparison on a default-constructed iterator.");
284 return __x.__current() == ranges::end(__x.__parent_base()) && !__x.__trailing_empty_;
288 template <class>
289 struct __inner_iterator_category {};
291 template <forward_range _Tp>
292 struct __inner_iterator_category<_Tp> {
293 using iterator_category = _If<
294 derived_from<typename iterator_traits<iterator_t<_Tp>>::iterator_category, forward_iterator_tag>,
295 forward_iterator_tag,
296 typename iterator_traits<iterator_t<_Tp>>::iterator_category
300 template <bool _Const>
301 struct __inner_iterator : __inner_iterator_category<__maybe_const<_Const, _View>> {
302 private:
303 using _Base = __maybe_const<_Const, _View>;
304 // Workaround for a GCC issue.
305 static constexpr bool _OuterConst = _Const;
306 __outer_iterator<_Const> __i_ = __outer_iterator<_OuterConst>();
307 bool __incremented_ = false;
309 // Note: these private functions are necessary because GCC doesn't allow calls to private members of `__i_` from
310 // free functions that are friends of `inner-iterator`.
312 _LIBCPP_HIDE_FROM_ABI
313 constexpr bool __is_done() const {
314 _LIBCPP_ASSERT_UNCATEGORIZED(__i_.__parent_, "Cannot call comparison on a default-constructed iterator.");
316 auto [__pcur, __pend] = ranges::subrange{__i_.__parent_->__pattern_};
317 auto __end = ranges::end(__i_.__parent_->__base_);
319 if constexpr (__tiny_range<_Pattern>) {
320 const auto& __cur = __i_.__current();
321 if (__cur == __end)
322 return true;
323 if (__pcur == __pend)
324 return __incremented_;
326 return *__cur == *__pcur;
328 } else {
329 auto __cur = __i_.__current();
330 if (__cur == __end)
331 return true;
332 if (__pcur == __pend)
333 return __incremented_;
335 do {
336 if (*__cur != *__pcur)
337 return false;
338 if (++__pcur == __pend)
339 return true;
340 } while (++__cur != __end);
342 return false;
346 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
347 constexpr auto& __outer_current() noexcept {
348 return __i_.__current();
351 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
352 constexpr const auto& __outer_current() const noexcept {
353 return __i_.__current();
356 public:
357 // using iterator_category = inherited;
358 using iterator_concept = typename __outer_iterator<_Const>::iterator_concept;
359 using value_type = range_value_t<_Base>;
360 using difference_type = range_difference_t<_Base>;
362 _LIBCPP_HIDE_FROM_ABI
363 __inner_iterator() = default;
365 _LIBCPP_HIDE_FROM_ABI
366 constexpr explicit __inner_iterator(__outer_iterator<_Const> __i)
367 : __i_(std::move(__i)) {}
369 _LIBCPP_HIDE_FROM_ABI
370 constexpr const iterator_t<_Base>& base() const& noexcept { return __i_.__current(); }
371 _LIBCPP_HIDE_FROM_ABI
372 constexpr iterator_t<_Base> base() &&
373 requires forward_range<_View> { return std::move(__i_.__current()); }
375 _LIBCPP_HIDE_FROM_ABI
376 constexpr decltype(auto) operator*() const { return *__i_.__current(); }
378 _LIBCPP_HIDE_FROM_ABI
379 constexpr __inner_iterator& operator++() {
380 __incremented_ = true;
382 if constexpr (!forward_range<_Base>) {
383 if constexpr (_Pattern::size() == 0) {
384 return *this;
388 ++__i_.__current();
389 return *this;
392 _LIBCPP_HIDE_FROM_ABI
393 constexpr decltype(auto) operator++(int) {
394 if constexpr (forward_range<_Base>) {
395 auto __tmp = *this;
396 ++*this;
397 return __tmp;
399 } else {
400 ++*this;
404 _LIBCPP_HIDE_FROM_ABI
405 friend constexpr bool operator==(const __inner_iterator& __x, const __inner_iterator& __y)
406 requires forward_range<_Base> {
407 return __x.__outer_current() == __y.__outer_current();
410 _LIBCPP_HIDE_FROM_ABI
411 friend constexpr bool operator==(const __inner_iterator& __x, default_sentinel_t) {
412 return __x.__is_done();
415 _LIBCPP_HIDE_FROM_ABI
416 friend constexpr decltype(auto) iter_move(const __inner_iterator& __i)
417 noexcept(noexcept(ranges::iter_move(__i.__outer_current()))) {
418 return ranges::iter_move(__i.__outer_current());
421 _LIBCPP_HIDE_FROM_ABI
422 friend constexpr void iter_swap(const __inner_iterator& __x, const __inner_iterator& __y)
423 noexcept(noexcept(ranges::iter_swap(__x.__outer_current(), __y.__outer_current())))
424 requires indirectly_swappable<iterator_t<_Base>> {
425 ranges::iter_swap(__x.__outer_current(), __y.__outer_current());
431 template <class _Range, class _Pattern>
432 lazy_split_view(_Range&&, _Pattern&&) -> lazy_split_view<views::all_t<_Range>, views::all_t<_Pattern>>;
434 template <input_range _Range>
435 lazy_split_view(_Range&&, range_value_t<_Range>)
436 -> lazy_split_view<views::all_t<_Range>, single_view<range_value_t<_Range>>>;
438 namespace views {
439 namespace __lazy_split_view {
440 struct __fn : __range_adaptor_closure<__fn> {
441 template <class _Range, class _Pattern>
442 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
443 constexpr auto operator()(_Range&& __range, _Pattern&& __pattern) const
444 noexcept(noexcept(lazy_split_view(std::forward<_Range>(__range), std::forward<_Pattern>(__pattern))))
445 -> decltype( lazy_split_view(std::forward<_Range>(__range), std::forward<_Pattern>(__pattern)))
446 { return lazy_split_view(std::forward<_Range>(__range), std::forward<_Pattern>(__pattern)); }
448 template <class _Pattern>
449 requires constructible_from<decay_t<_Pattern>, _Pattern>
450 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
451 constexpr auto operator()(_Pattern&& __pattern) const
452 noexcept(is_nothrow_constructible_v<decay_t<_Pattern>, _Pattern>) {
453 return __range_adaptor_closure_t(std::__bind_back(*this, std::forward<_Pattern>(__pattern)));
456 } // namespace __lazy_split_view
458 inline namespace __cpo {
459 inline constexpr auto lazy_split = __lazy_split_view::__fn{};
460 } // namespace __cpo
461 } // namespace views
463 } // namespace ranges
465 #endif // _LIBCPP_STD_VER >= 20
467 _LIBCPP_END_NAMESPACE_STD
469 #endif // _LIBCPP___RANGES_LAZY_SPLIT_VIEW_H