2 //===----------------------------------------------------------------------===//
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
8 //===----------------------------------------------------------------------===//
10 #ifndef _LIBCPP___ALGORITHM_FIND_END_OF_H
11 #define _LIBCPP___ALGORITHM_FIND_END_OF_H
13 #include <__algorithm/comp.h>
14 #include <__algorithm/iterator_operations.h>
15 #include <__algorithm/search.h>
17 #include <__functional/identity.h>
18 #include <__functional/invoke.h>
19 #include <__iterator/advance.h>
20 #include <__iterator/iterator_traits.h>
21 #include <__iterator/next.h>
22 #include <__iterator/reverse_iterator.h>
23 #include <__utility/pair.h>
25 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26 # pragma GCC system_header
29 _LIBCPP_BEGIN_NAMESPACE_STD
31 template < class _AlgPolicy
,
39 _LIBCPP_HIDE_FROM_ABI
inline _LIBCPP_CONSTEXPR_SINCE_CXX14 pair
<_Iter1
, _Iter1
> __find_end_impl(
48 forward_iterator_tag
) {
49 // modeled after search algorithm
50 _Iter1 __match_first
= _IterOps
<_AlgPolicy
>::next(__first1
, __last1
); // __last1 is the "default" answer
51 _Iter1 __match_last
= __match_first
;
52 if (__first2
== __last2
)
53 return pair
<_Iter1
, _Iter1
>(__match_last
, __match_last
);
56 if (__first1
== __last1
) // if source exhausted return last correct answer (or __last1 if never found)
57 return pair
<_Iter1
, _Iter1
>(__match_first
, __match_last
);
58 if (std::__invoke(__pred
, std::__invoke(__proj1
, *__first1
), std::__invoke(__proj2
, *__first2
)))
62 // *__first1 matches *__first2, now match elements after here
63 _Iter1 __m1
= __first1
;
64 _Iter2 __m2
= __first2
;
66 if (++__m2
== __last2
) { // Pattern exhaused, record answer and search for another one
67 __match_first
= __first1
;
68 __match_last
= ++__m1
;
72 if (++__m1
== __last1
) // Source exhausted, return last answer
73 return pair
<_Iter1
, _Iter1
>(__match_first
, __match_last
);
74 // mismatch, restart with a new __first
75 if (!std::__invoke(__pred
, std::__invoke(__proj1
, *__m1
), std::__invoke(__proj2
, *__m2
))) {
78 } // else there is a match, check next elements
83 template < class _IterOps
,
91 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Iter1
__find_end(
99 bidirectional_iterator_tag
,
100 bidirectional_iterator_tag
) {
101 auto __last1
= _IterOps::next(__first1
, __sent1
);
102 auto __last2
= _IterOps::next(__first2
, __sent2
);
103 // modeled after search algorithm (in reverse)
104 if (__first2
== __last2
)
105 return __last1
; // Everything matches an empty sequence
106 _Iter1 __l1
= __last1
;
107 _Iter2 __l2
= __last2
;
110 // Find last element in sequence 1 that matchs *(__last2-1), with a mininum of loop checks
112 if (__first1
== __l1
) // return __last1 if no element matches *__first2
114 if (std::__invoke(__pred
, std::__invoke(__proj1
, *--__l1
), std::__invoke(__proj2
, *__l2
)))
117 // *__l1 matches *__l2, now match elements before here
121 if (__m2
== __first2
) // If pattern exhausted, __m1 is the answer (works for 1 element pattern)
123 if (__m1
== __first1
) // Otherwise if source exhaused, pattern not found
126 // if there is a mismatch, restart with a new __l1
127 if (!std::__invoke(__pred
, std::__invoke(__proj1
, *--__m1
), std::__invoke(__proj2
, *--__m2
))) {
129 } // else there is a match, check next elements
134 template < class _AlgPolicy
,
142 _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _Iter1
__find_end(
150 random_access_iterator_tag
,
151 random_access_iterator_tag
) {
152 typedef typename iterator_traits
<_Iter1
>::difference_type _D1
;
153 auto __last1
= _IterOps
<_AlgPolicy
>::next(__first1
, __sent1
);
154 auto __last2
= _IterOps
<_AlgPolicy
>::next(__first2
, __sent2
);
155 // Take advantage of knowing source and pattern lengths. Stop short when source is smaller than pattern
156 auto __len2
= __last2
- __first2
;
159 auto __len1
= __last1
- __first1
;
162 const _Iter1 __s
= __first1
+ _D1(__len2
- 1); // End of pattern match can't go before here
163 _Iter1 __l1
= __last1
;
164 _Iter2 __l2
= __last2
;
170 if (std::__invoke(__pred
, std::__invoke(__proj1
, *--__l1
), std::__invoke(__proj2
, *__l2
)))
176 if (__m2
== __first2
)
178 // no need to check range on __m1 because __s guarantees we have enough source
179 if (!std::__invoke(__pred
, std::__invoke(__proj1
, *--__m1
), std::__invoke(*--__m2
))) {
186 template <class _ForwardIterator1
, class _ForwardIterator2
, class _BinaryPredicate
>
187 _LIBCPP_NODISCARD
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator1
__find_end_classic(
188 _ForwardIterator1 __first1
,
189 _ForwardIterator1 __last1
,
190 _ForwardIterator2 __first2
,
191 _ForwardIterator2 __last2
,
192 _BinaryPredicate
& __pred
) {
193 auto __proj
= __identity();
194 return std::__find_end_impl
<_ClassicAlgPolicy
>(
202 typename iterator_traits
<_ForwardIterator1
>::iterator_category(),
203 typename iterator_traits
<_ForwardIterator2
>::iterator_category())
207 template <class _ForwardIterator1
, class _ForwardIterator2
, class _BinaryPredicate
>
208 _LIBCPP_NODISCARD
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1
find_end(
209 _ForwardIterator1 __first1
,
210 _ForwardIterator1 __last1
,
211 _ForwardIterator2 __first2
,
212 _ForwardIterator2 __last2
,
213 _BinaryPredicate __pred
) {
214 return std::__find_end_classic(__first1
, __last1
, __first2
, __last2
, __pred
);
217 template <class _ForwardIterator1
, class _ForwardIterator2
>
218 _LIBCPP_NODISCARD
inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1
219 find_end(_ForwardIterator1 __first1
, _ForwardIterator1 __last1
, _ForwardIterator2 __first2
, _ForwardIterator2 __last2
) {
220 return std::find_end(__first1
, __last1
, __first2
, __last2
, __equal_to());
223 _LIBCPP_END_NAMESPACE_STD
225 #endif // _LIBCPP___ALGORITHM_FIND_END_OF_H