xref: /freebsd-src/contrib/llvm-project/libcxx/include/__algorithm/ranges_find_last.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
2*0fca6ea1SDimitry Andric //
3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*0fca6ea1SDimitry Andric //
7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===//
8*0fca6ea1SDimitry Andric 
9*0fca6ea1SDimitry Andric #ifndef _LIBCPP___ALGORITHM_RANGES_FIND_LAST_H
10*0fca6ea1SDimitry Andric #define _LIBCPP___ALGORITHM_RANGES_FIND_LAST_H
11*0fca6ea1SDimitry Andric 
12*0fca6ea1SDimitry Andric #include <__config>
13*0fca6ea1SDimitry Andric #include <__functional/identity.h>
14*0fca6ea1SDimitry Andric #include <__functional/invoke.h>
15*0fca6ea1SDimitry Andric #include <__functional/ranges_operations.h>
16*0fca6ea1SDimitry Andric #include <__iterator/concepts.h>
17*0fca6ea1SDimitry Andric #include <__iterator/indirectly_comparable.h>
18*0fca6ea1SDimitry Andric #include <__iterator/next.h>
19*0fca6ea1SDimitry Andric #include <__iterator/prev.h>
20*0fca6ea1SDimitry Andric #include <__iterator/projected.h>
21*0fca6ea1SDimitry Andric #include <__ranges/access.h>
22*0fca6ea1SDimitry Andric #include <__ranges/concepts.h>
23*0fca6ea1SDimitry Andric #include <__ranges/subrange.h>
24*0fca6ea1SDimitry Andric #include <__utility/move.h>
25*0fca6ea1SDimitry Andric 
26*0fca6ea1SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
27*0fca6ea1SDimitry Andric #  pragma GCC system_header
28*0fca6ea1SDimitry Andric #endif
29*0fca6ea1SDimitry Andric 
30*0fca6ea1SDimitry Andric _LIBCPP_PUSH_MACROS
31*0fca6ea1SDimitry Andric #include <__undef_macros>
32*0fca6ea1SDimitry Andric 
33*0fca6ea1SDimitry Andric #if _LIBCPP_STD_VER >= 23
34*0fca6ea1SDimitry Andric 
35*0fca6ea1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
36*0fca6ea1SDimitry Andric 
37*0fca6ea1SDimitry Andric namespace ranges {
38*0fca6ea1SDimitry Andric 
39*0fca6ea1SDimitry Andric template <class _Iter, class _Sent, class _Pred, class _Proj>
40*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI constexpr subrange<_Iter>
41*0fca6ea1SDimitry Andric __find_last_impl(_Iter __first, _Sent __last, _Pred __pred, _Proj& __proj) {
42*0fca6ea1SDimitry Andric   if (__first == __last) {
43*0fca6ea1SDimitry Andric     return subrange<_Iter>(__first, __first);
44*0fca6ea1SDimitry Andric   }
45*0fca6ea1SDimitry Andric 
46*0fca6ea1SDimitry Andric   if constexpr (bidirectional_iterator<_Iter>) {
47*0fca6ea1SDimitry Andric     auto __last_it = ranges::next(__first, __last);
48*0fca6ea1SDimitry Andric     for (auto __it = ranges::prev(__last_it); __it != __first; --__it) {
49*0fca6ea1SDimitry Andric       if (__pred(std::invoke(__proj, *__it))) {
50*0fca6ea1SDimitry Andric         return subrange<_Iter>(std::move(__it), std::move(__last_it));
51*0fca6ea1SDimitry Andric       }
52*0fca6ea1SDimitry Andric     }
53*0fca6ea1SDimitry Andric     if (__pred(std::invoke(__proj, *__first))) {
54*0fca6ea1SDimitry Andric       return subrange<_Iter>(std::move(__first), std::move(__last_it));
55*0fca6ea1SDimitry Andric     }
56*0fca6ea1SDimitry Andric     return subrange<_Iter>(__last_it, __last_it);
57*0fca6ea1SDimitry Andric   } else {
58*0fca6ea1SDimitry Andric     bool __found = false;
59*0fca6ea1SDimitry Andric     _Iter __found_it;
60*0fca6ea1SDimitry Andric     for (; __first != __last; ++__first) {
61*0fca6ea1SDimitry Andric       if (__pred(std::invoke(__proj, *__first))) {
62*0fca6ea1SDimitry Andric         __found    = true;
63*0fca6ea1SDimitry Andric         __found_it = __first;
64*0fca6ea1SDimitry Andric       }
65*0fca6ea1SDimitry Andric     }
66*0fca6ea1SDimitry Andric 
67*0fca6ea1SDimitry Andric     if (__found) {
68*0fca6ea1SDimitry Andric       return subrange<_Iter>(std::move(__found_it), std::move(__first));
69*0fca6ea1SDimitry Andric     } else {
70*0fca6ea1SDimitry Andric       return subrange<_Iter>(__first, __first);
71*0fca6ea1SDimitry Andric     }
72*0fca6ea1SDimitry Andric   }
73*0fca6ea1SDimitry Andric }
74*0fca6ea1SDimitry Andric 
75*0fca6ea1SDimitry Andric namespace __find_last {
76*0fca6ea1SDimitry Andric struct __fn {
77*0fca6ea1SDimitry Andric   template <class _Type>
78*0fca6ea1SDimitry Andric   struct __op {
79*0fca6ea1SDimitry Andric     const _Type& __value;
80*0fca6ea1SDimitry Andric     template <class _Elem>
81*0fca6ea1SDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator()(_Elem&& __elem) const {
82*0fca6ea1SDimitry Andric       return std::forward<_Elem>(__elem) == __value;
83*0fca6ea1SDimitry Andric     }
84*0fca6ea1SDimitry Andric   };
85*0fca6ea1SDimitry Andric 
86*0fca6ea1SDimitry Andric   template <forward_iterator _Iter, sentinel_for<_Iter> _Sent, class _Type, class _Proj = identity>
87*0fca6ea1SDimitry Andric     requires indirect_binary_predicate<ranges::equal_to, projected<_Iter, _Proj>, const _Type*>
88*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static subrange<_Iter>
89*0fca6ea1SDimitry Andric   operator()(_Iter __first, _Sent __last, const _Type& __value, _Proj __proj = {}) {
90*0fca6ea1SDimitry Andric     return ranges::__find_last_impl(std::move(__first), std::move(__last), __op<_Type>{__value}, __proj);
91*0fca6ea1SDimitry Andric   }
92*0fca6ea1SDimitry Andric 
93*0fca6ea1SDimitry Andric   template <forward_range _Range, class _Type, class _Proj = identity>
94*0fca6ea1SDimitry Andric     requires indirect_binary_predicate<ranges::equal_to, projected<iterator_t<_Range>, _Proj>, const _Type*>
95*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static borrowed_subrange_t<_Range>
96*0fca6ea1SDimitry Andric   operator()(_Range&& __range, const _Type& __value, _Proj __proj = {}) {
97*0fca6ea1SDimitry Andric     return ranges::__find_last_impl(ranges::begin(__range), ranges::end(__range), __op<_Type>{__value}, __proj);
98*0fca6ea1SDimitry Andric   }
99*0fca6ea1SDimitry Andric };
100*0fca6ea1SDimitry Andric } // namespace __find_last
101*0fca6ea1SDimitry Andric 
102*0fca6ea1SDimitry Andric namespace __find_last_if {
103*0fca6ea1SDimitry Andric struct __fn {
104*0fca6ea1SDimitry Andric   template <class _Pred>
105*0fca6ea1SDimitry Andric   struct __op {
106*0fca6ea1SDimitry Andric     _Pred& __pred;
107*0fca6ea1SDimitry Andric     template <class _Elem>
108*0fca6ea1SDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator()(_Elem&& __elem) const {
109*0fca6ea1SDimitry Andric       return std::invoke(__pred, std::forward<_Elem>(__elem));
110*0fca6ea1SDimitry Andric     }
111*0fca6ea1SDimitry Andric   };
112*0fca6ea1SDimitry Andric 
113*0fca6ea1SDimitry Andric   template <forward_iterator _Iter,
114*0fca6ea1SDimitry Andric             sentinel_for<_Iter> _Sent,
115*0fca6ea1SDimitry Andric             class _Proj = identity,
116*0fca6ea1SDimitry Andric             indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
117*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static subrange<_Iter>
118*0fca6ea1SDimitry Andric   operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) {
119*0fca6ea1SDimitry Andric     return ranges::__find_last_impl(std::move(__first), std::move(__last), __op<_Pred>{__pred}, __proj);
120*0fca6ea1SDimitry Andric   }
121*0fca6ea1SDimitry Andric 
122*0fca6ea1SDimitry Andric   template <forward_range _Range,
123*0fca6ea1SDimitry Andric             class _Proj = identity,
124*0fca6ea1SDimitry Andric             indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
125*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static borrowed_subrange_t<_Range>
126*0fca6ea1SDimitry Andric   operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) {
127*0fca6ea1SDimitry Andric     return ranges::__find_last_impl(ranges::begin(__range), ranges::end(__range), __op<_Pred>{__pred}, __proj);
128*0fca6ea1SDimitry Andric   }
129*0fca6ea1SDimitry Andric };
130*0fca6ea1SDimitry Andric } // namespace __find_last_if
131*0fca6ea1SDimitry Andric 
132*0fca6ea1SDimitry Andric namespace __find_last_if_not {
133*0fca6ea1SDimitry Andric struct __fn {
134*0fca6ea1SDimitry Andric   template <class _Pred>
135*0fca6ea1SDimitry Andric   struct __op {
136*0fca6ea1SDimitry Andric     _Pred& __pred;
137*0fca6ea1SDimitry Andric     template <class _Elem>
138*0fca6ea1SDimitry Andric     _LIBCPP_HIDE_FROM_ABI constexpr decltype(auto) operator()(_Elem&& __elem) const {
139*0fca6ea1SDimitry Andric       return !std::invoke(__pred, std::forward<_Elem>(__elem));
140*0fca6ea1SDimitry Andric     }
141*0fca6ea1SDimitry Andric   };
142*0fca6ea1SDimitry Andric 
143*0fca6ea1SDimitry Andric   template <forward_iterator _Iter,
144*0fca6ea1SDimitry Andric             sentinel_for<_Iter> _Sent,
145*0fca6ea1SDimitry Andric             class _Proj = identity,
146*0fca6ea1SDimitry Andric             indirect_unary_predicate<projected<_Iter, _Proj>> _Pred>
147*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static subrange<_Iter>
148*0fca6ea1SDimitry Andric   operator()(_Iter __first, _Sent __last, _Pred __pred, _Proj __proj = {}) {
149*0fca6ea1SDimitry Andric     return ranges::__find_last_impl(std::move(__first), std::move(__last), __op<_Pred>{__pred}, __proj);
150*0fca6ea1SDimitry Andric   }
151*0fca6ea1SDimitry Andric 
152*0fca6ea1SDimitry Andric   template <forward_range _Range,
153*0fca6ea1SDimitry Andric             class _Proj = identity,
154*0fca6ea1SDimitry Andric             indirect_unary_predicate<projected<iterator_t<_Range>, _Proj>> _Pred>
155*0fca6ea1SDimitry Andric   [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr static borrowed_subrange_t<_Range>
156*0fca6ea1SDimitry Andric   operator()(_Range&& __range, _Pred __pred, _Proj __proj = {}) {
157*0fca6ea1SDimitry Andric     return ranges::__find_last_impl(ranges::begin(__range), ranges::end(__range), __op<_Pred>{__pred}, __proj);
158*0fca6ea1SDimitry Andric   }
159*0fca6ea1SDimitry Andric };
160*0fca6ea1SDimitry Andric } // namespace __find_last_if_not
161*0fca6ea1SDimitry Andric 
162*0fca6ea1SDimitry Andric inline namespace __cpo {
163*0fca6ea1SDimitry Andric inline constexpr auto find_last        = __find_last::__fn{};
164*0fca6ea1SDimitry Andric inline constexpr auto find_last_if     = __find_last_if::__fn{};
165*0fca6ea1SDimitry Andric inline constexpr auto find_last_if_not = __find_last_if_not::__fn{};
166*0fca6ea1SDimitry Andric } // namespace __cpo
167*0fca6ea1SDimitry Andric } // namespace ranges
168*0fca6ea1SDimitry Andric 
169*0fca6ea1SDimitry Andric _LIBCPP_END_NAMESPACE_STD
170*0fca6ea1SDimitry Andric 
171*0fca6ea1SDimitry Andric #endif // _LIBCPP_STD_VER >= 23
172*0fca6ea1SDimitry Andric 
173*0fca6ea1SDimitry Andric _LIBCPP_POP_MACROS
174*0fca6ea1SDimitry Andric 
175*0fca6ea1SDimitry Andric #endif // _LIBCPP___ALGORITHM_RANGES_FIND_LAST_H
176