xref: /freebsd/contrib/llvm-project/libcxx/include/__ranges/lazy_split_view.h (revision e6bfd18d21b225af6a0ed67ceeaf1293b7b9eba5)
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_LAZY_SPLIT_VIEW_H
11 #define _LIBCPP___RANGES_LAZY_SPLIT_VIEW_H
12 
13 #include <__algorithm/in_in_result.h>
14 #include <__algorithm/ranges_find.h>
15 #include <__algorithm/ranges_mismatch.h>
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 <__utility/forward.h>
39 #include <__utility/move.h>
40 #include <type_traits>
41 
42 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
43 #  pragma GCC system_header
44 #endif
45 
46 _LIBCPP_BEGIN_NAMESPACE_STD
47 
48 #if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
49 
50 namespace ranges {
51 
52 template <auto> struct __require_constant;
53 
54 template <class _Range>
55 concept __tiny_range =
56   sized_range<_Range> &&
57   requires { typename __require_constant<remove_reference_t<_Range>::size()>; } &&
58   (remove_reference_t<_Range>::size() <= 1);
59 
60 template <input_range _View, forward_range _Pattern>
61   requires view<_View> && view<_Pattern> &&
62            indirectly_comparable<iterator_t<_View>, iterator_t<_Pattern>, ranges::equal_to> &&
63            (forward_range<_View> || __tiny_range<_Pattern>)
64 class lazy_split_view : public view_interface<lazy_split_view<_View, _Pattern>> {
65 
66   _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
67   _LIBCPP_NO_UNIQUE_ADDRESS _Pattern __pattern_ = _Pattern();
68 
69   using _MaybeCurrent = _If<!forward_range<_View>, __non_propagating_cache<iterator_t<_View>>, __empty_cache>;
70   _LIBCPP_NO_UNIQUE_ADDRESS _MaybeCurrent __current_ = _MaybeCurrent();
71 
72   template <bool> struct __outer_iterator;
73   template <bool> struct __inner_iterator;
74 
75 public:
76   _LIBCPP_HIDE_FROM_ABI
77   lazy_split_view()
78     requires default_initializable<_View> && default_initializable<_Pattern> = default;
79 
80   _LIBCPP_HIDE_FROM_ABI
81   constexpr lazy_split_view(_View __base, _Pattern __pattern)
82     : __base_(std::move(__base)), __pattern_(std::move(__pattern)) {}
83 
84   template <input_range _Range>
85     requires constructible_from<_View, views::all_t<_Range>> &&
86              constructible_from<_Pattern, single_view<range_value_t<_Range>>>
87   _LIBCPP_HIDE_FROM_ABI
88   constexpr lazy_split_view(_Range&& __r, range_value_t<_Range> __e)
89     : __base_(views::all(std::forward<_Range>(__r)))
90     , __pattern_(views::single(std::move(__e))) {}
91 
92   _LIBCPP_HIDE_FROM_ABI
93   constexpr _View base() const& requires copy_constructible<_View> { return __base_; }
94   _LIBCPP_HIDE_FROM_ABI
95   constexpr _View base() && { return std::move(__base_); }
96 
97   _LIBCPP_HIDE_FROM_ABI
98   constexpr auto begin() {
99     if constexpr (forward_range<_View>) {
100       return __outer_iterator<__simple_view<_View> && __simple_view<_Pattern>>{*this, ranges::begin(__base_)};
101     } else {
102       __current_.__emplace(ranges::begin(__base_));
103       return __outer_iterator<false>{*this};
104     }
105   }
106 
107   _LIBCPP_HIDE_FROM_ABI
108   constexpr auto begin() const requires forward_range<_View> && forward_range<const _View> {
109     return __outer_iterator<true>{*this, ranges::begin(__base_)};
110   }
111 
112   _LIBCPP_HIDE_FROM_ABI
113   constexpr auto end() requires forward_range<_View> && common_range<_View> {
114     return __outer_iterator<__simple_view<_View> && __simple_view<_Pattern>>{*this, ranges::end(__base_)};
115   }
116 
117   _LIBCPP_HIDE_FROM_ABI
118   constexpr auto end() const {
119     if constexpr (forward_range<_View> && forward_range<const _View> && common_range<const _View>) {
120       return __outer_iterator<true>{*this, ranges::end(__base_)};
121     } else {
122       return default_sentinel;
123     }
124   }
125 
126 private:
127 
128   template <class>
129   struct __outer_iterator_category {};
130 
131   template <forward_range _Tp>
132   struct __outer_iterator_category<_Tp> {
133     using iterator_category = input_iterator_tag;
134   };
135 
136   template <bool _Const>
137   struct __outer_iterator : __outer_iterator_category<__maybe_const<_Const, _View>> {
138   private:
139     template <bool>
140     friend struct __inner_iterator;
141     friend __outer_iterator<true>;
142 
143     using _Parent = __maybe_const<_Const, lazy_split_view>;
144     using _Base = __maybe_const<_Const, _View>;
145 
146     _Parent* __parent_ = nullptr;
147     using _MaybeCurrent = _If<forward_range<_View>, iterator_t<_Base>, __empty_cache>;
148     _LIBCPP_NO_UNIQUE_ADDRESS _MaybeCurrent __current_ = _MaybeCurrent();
149     bool __trailing_empty_ = false;
150 
151     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
152     constexpr auto& __current() noexcept {
153       if constexpr (forward_range<_View>) {
154         return __current_;
155       } else {
156         return *__parent_->__current_;
157       }
158     }
159 
160     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
161     constexpr const auto& __current() const noexcept {
162       if constexpr (forward_range<_View>) {
163         return __current_;
164       } else {
165         return *__parent_->__current_;
166       }
167     }
168 
169     // Workaround for the GCC issue that doesn't allow calling `__parent_->__base_` from friend functions (because
170     // `__base_` is private).
171     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
172     constexpr auto& __parent_base() const noexcept {
173       return __parent_->__base_;
174     }
175 
176   public:
177     // using iterator_category = inherited;
178     using iterator_concept = conditional_t<forward_range<_Base>, forward_iterator_tag, input_iterator_tag>;
179     using difference_type = range_difference_t<_Base>;
180 
181     struct value_type : view_interface<value_type> {
182     private:
183       __outer_iterator __i_ = __outer_iterator();
184 
185     public:
186       _LIBCPP_HIDE_FROM_ABI
187       value_type() = default;
188       _LIBCPP_HIDE_FROM_ABI
189       constexpr explicit value_type(__outer_iterator __i)
190         : __i_(std::move(__i)) {}
191 
192       _LIBCPP_HIDE_FROM_ABI
193       constexpr __inner_iterator<_Const> begin() const { return __inner_iterator<_Const>{__i_}; }
194       _LIBCPP_HIDE_FROM_ABI
195       constexpr default_sentinel_t end() const noexcept { return default_sentinel; }
196     };
197 
198     _LIBCPP_HIDE_FROM_ABI
199     __outer_iterator() = default;
200 
201     _LIBCPP_HIDE_FROM_ABI
202     constexpr explicit __outer_iterator(_Parent& __parent)
203       requires (!forward_range<_Base>)
204       : __parent_(std::addressof(__parent)) {}
205 
206     _LIBCPP_HIDE_FROM_ABI
207     constexpr __outer_iterator(_Parent& __parent, iterator_t<_Base> __current)
208       requires forward_range<_Base>
209       : __parent_(std::addressof(__parent)), __current_(std::move(__current)) {}
210 
211     _LIBCPP_HIDE_FROM_ABI
212     constexpr __outer_iterator(__outer_iterator<!_Const> __i)
213       requires _Const && convertible_to<iterator_t<_View>, iterator_t<_Base>>
214       : __parent_(__i.__parent_), __current_(std::move(__i.__current_)) {}
215 
216     _LIBCPP_HIDE_FROM_ABI
217     constexpr value_type operator*() const { return value_type{*this}; }
218 
219     _LIBCPP_HIDE_FROM_ABI
220     constexpr __outer_iterator& operator++() {
221       const auto __end = ranges::end(__parent_->__base_);
222       if (__current() == __end) {
223         __trailing_empty_ = false;
224         return *this;
225       }
226 
227       const auto [__pbegin, __pend] = ranges::subrange{__parent_->__pattern_};
228       if (__pbegin == __pend) {
229         // Empty pattern: split on every element in the input range
230         ++__current();
231 
232       } else if constexpr (__tiny_range<_Pattern>) {
233         // One-element pattern: we can use `ranges::find`.
234         __current() = ranges::find(std::move(__current()), __end, *__pbegin);
235         if (__current() != __end) {
236           // Make sure we point to after the separator we just found.
237           ++__current();
238           if (__current() == __end)
239             __trailing_empty_ = true;
240         }
241 
242       } else {
243         // General case for n-element pattern.
244         do {
245           const auto [__b, __p] = ranges::mismatch(__current(), __end, __pbegin, __pend);
246           if (__p == __pend) {
247             __current() = __b;
248             if (__current() == __end) {
249               __trailing_empty_ = true;
250             }
251             break; // The pattern matched; skip it.
252           }
253         } while (++__current() != __end);
254       }
255 
256       return *this;
257     }
258 
259     _LIBCPP_HIDE_FROM_ABI
260     constexpr decltype(auto) operator++(int) {
261       if constexpr (forward_range<_Base>) {
262         auto __tmp = *this;
263         ++*this;
264         return __tmp;
265 
266       } else {
267         ++*this;
268       }
269     }
270 
271     _LIBCPP_HIDE_FROM_ABI
272     friend constexpr bool operator==(const __outer_iterator& __x, const __outer_iterator& __y)
273       requires forward_range<_Base> {
274       return __x.__current_ == __y.__current_ && __x.__trailing_empty_ == __y.__trailing_empty_;
275     }
276 
277     _LIBCPP_HIDE_FROM_ABI
278     friend constexpr bool operator==(const __outer_iterator& __x, default_sentinel_t) {
279       _LIBCPP_ASSERT(__x.__parent_, "Cannot call comparison on a default-constructed iterator.");
280       return __x.__current() == ranges::end(__x.__parent_base()) && !__x.__trailing_empty_;
281     }
282   };
283 
284   template <class>
285   struct __inner_iterator_category {};
286 
287   template <forward_range _Tp>
288   struct __inner_iterator_category<_Tp> {
289     using iterator_category = _If<
290       derived_from<typename iterator_traits<iterator_t<_Tp>>::iterator_category, forward_iterator_tag>,
291       forward_iterator_tag,
292       typename iterator_traits<iterator_t<_Tp>>::iterator_category
293     >;
294   };
295 
296   template <bool _Const>
297   struct __inner_iterator : __inner_iterator_category<__maybe_const<_Const, _View>> {
298   private:
299     using _Base = __maybe_const<_Const, _View>;
300     // Workaround for a GCC issue.
301     static constexpr bool _OuterConst = _Const;
302     __outer_iterator<_Const> __i_ = __outer_iterator<_OuterConst>();
303     bool __incremented_ = false;
304 
305     // Note: these private functions are necessary because GCC doesn't allow calls to private members of `__i_` from
306     // free functions that are friends of `inner-iterator`.
307 
308     _LIBCPP_HIDE_FROM_ABI
309     constexpr bool __is_done() const {
310       _LIBCPP_ASSERT(__i_.__parent_, "Cannot call comparison on a default-constructed iterator.");
311 
312       auto [__pcur, __pend] = ranges::subrange{__i_.__parent_->__pattern_};
313       auto __end = ranges::end(__i_.__parent_->__base_);
314 
315       if constexpr (__tiny_range<_Pattern>) {
316         const auto& __cur = __i_.__current();
317         if (__cur == __end)
318           return true;
319         if (__pcur == __pend)
320           return __incremented_;
321 
322         return *__cur == *__pcur;
323 
324       } else {
325         auto __cur = __i_.__current();
326         if (__cur == __end)
327           return true;
328         if (__pcur == __pend)
329           return __incremented_;
330 
331         do {
332           if (*__cur != *__pcur)
333             return false;
334           if (++__pcur == __pend)
335             return true;
336         } while (++__cur != __end);
337 
338         return false;
339       }
340     }
341 
342     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
343     constexpr auto& __outer_current() noexcept {
344       return __i_.__current();
345     }
346 
347     [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
348     constexpr const auto& __outer_current() const noexcept {
349       return __i_.__current();
350     }
351 
352   public:
353     // using iterator_category = inherited;
354     using iterator_concept = typename __outer_iterator<_Const>::iterator_concept;
355     using value_type = range_value_t<_Base>;
356     using difference_type = range_difference_t<_Base>;
357 
358     _LIBCPP_HIDE_FROM_ABI
359     __inner_iterator() = default;
360 
361     _LIBCPP_HIDE_FROM_ABI
362     constexpr explicit __inner_iterator(__outer_iterator<_Const> __i)
363       : __i_(std::move(__i)) {}
364 
365     _LIBCPP_HIDE_FROM_ABI
366     constexpr const iterator_t<_Base>& base() const& noexcept { return __i_.__current(); }
367     _LIBCPP_HIDE_FROM_ABI
368     constexpr iterator_t<_Base> base() &&
369       requires forward_range<_View> { return std::move(__i_.__current()); }
370 
371     _LIBCPP_HIDE_FROM_ABI
372     constexpr decltype(auto) operator*() const { return *__i_.__current(); }
373 
374     _LIBCPP_HIDE_FROM_ABI
375     constexpr __inner_iterator& operator++() {
376       __incremented_ = true;
377 
378       if constexpr (!forward_range<_Base>) {
379         if constexpr (_Pattern::size() == 0) {
380           return *this;
381         }
382       }
383 
384       ++__i_.__current();
385       return *this;
386     }
387 
388     _LIBCPP_HIDE_FROM_ABI
389     constexpr decltype(auto) operator++(int) {
390       if constexpr (forward_range<_Base>) {
391         auto __tmp = *this;
392         ++*this;
393         return __tmp;
394 
395       } else {
396         ++*this;
397       }
398     }
399 
400     _LIBCPP_HIDE_FROM_ABI
401     friend constexpr bool operator==(const __inner_iterator& __x, const __inner_iterator& __y)
402       requires forward_range<_Base> {
403       return __x.__outer_current() == __y.__outer_current();
404     }
405 
406     _LIBCPP_HIDE_FROM_ABI
407     friend constexpr bool operator==(const __inner_iterator& __x, default_sentinel_t) {
408       return __x.__is_done();
409     }
410 
411     _LIBCPP_HIDE_FROM_ABI
412     friend constexpr decltype(auto) iter_move(const __inner_iterator& __i)
413         noexcept(noexcept(ranges::iter_move(__i.__outer_current()))) {
414       return ranges::iter_move(__i.__outer_current());
415     }
416 
417     _LIBCPP_HIDE_FROM_ABI
418     friend constexpr void iter_swap(const __inner_iterator& __x, const __inner_iterator& __y)
419         noexcept(noexcept(ranges::iter_swap(__x.__outer_current(), __y.__outer_current())))
420         requires indirectly_swappable<iterator_t<_Base>> {
421       ranges::iter_swap(__x.__outer_current(), __y.__outer_current());
422     }
423   };
424 
425 };
426 
427 template <class _Range, class _Pattern>
428 lazy_split_view(_Range&&, _Pattern&&) -> lazy_split_view<views::all_t<_Range>, views::all_t<_Pattern>>;
429 
430 template <input_range _Range>
431 lazy_split_view(_Range&&, range_value_t<_Range>)
432   -> lazy_split_view<views::all_t<_Range>, single_view<range_value_t<_Range>>>;
433 
434 namespace views {
435 namespace __lazy_split_view {
436 struct __fn : __range_adaptor_closure<__fn> {
437   template <class _Range, class _Pattern>
438   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
439   constexpr auto operator()(_Range&& __range, _Pattern&& __pattern) const
440     noexcept(noexcept(lazy_split_view(std::forward<_Range>(__range), std::forward<_Pattern>(__pattern))))
441     -> decltype(      lazy_split_view(std::forward<_Range>(__range), std::forward<_Pattern>(__pattern)))
442     { return          lazy_split_view(std::forward<_Range>(__range), std::forward<_Pattern>(__pattern)); }
443 
444   template <class _Pattern>
445     requires constructible_from<decay_t<_Pattern>, _Pattern>
446   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI
447   constexpr auto operator()(_Pattern&& __pattern) const
448       noexcept(is_nothrow_constructible_v<decay_t<_Pattern>, _Pattern>) {
449     return __range_adaptor_closure_t(std::__bind_back(*this, std::forward<_Pattern>(__pattern)));
450   }
451 };
452 } // namespace __lazy_split_view
453 
454 inline namespace __cpo {
455   inline constexpr auto lazy_split = __lazy_split_view::__fn{};
456 } // namespace __cpo
457 } // namespace views
458 
459 } // namespace ranges
460 
461 #endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_INCOMPLETE_RANGES)
462 
463 _LIBCPP_END_NAMESPACE_STD
464 
465 #endif // _LIBCPP___RANGES_LAZY_SPLIT_VIEW_H
466