xref: /llvm-project/libcxx/include/__algorithm/search.h (revision 09e3a360581dc36d0820d3fb6da9bd7cfed87b5d)
1134723edSLouis Dionne // -*- C++ -*-
2134723edSLouis Dionne //===----------------------------------------------------------------------===//
3134723edSLouis Dionne //
4134723edSLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5134723edSLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
6134723edSLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7134723edSLouis Dionne //
8134723edSLouis Dionne //===----------------------------------------------------------------------===//
9134723edSLouis Dionne 
10134723edSLouis Dionne #ifndef _LIBCPP___ALGORITHM_SEARCH_H
11134723edSLouis Dionne #define _LIBCPP___ALGORITHM_SEARCH_H
12134723edSLouis Dionne 
13134723edSLouis Dionne #include <__algorithm/comp.h>
14101d1e9bSNikolas Klauser #include <__algorithm/iterator_operations.h>
15d03aa7d6SLouis Dionne #include <__config>
16101d1e9bSNikolas Klauser #include <__functional/identity.h>
17101d1e9bSNikolas Klauser #include <__iterator/advance.h>
18101d1e9bSNikolas Klauser #include <__iterator/concepts.h>
19134723edSLouis Dionne #include <__iterator/iterator_traits.h>
20e698c595SNikolas Klauser #include <__type_traits/enable_if.h>
21*09e3a360SLouis Dionne #include <__type_traits/invoke.h>
22101d1e9bSNikolas Klauser #include <__type_traits/is_callable.h>
23ea2206d7SArthur O'Dwyer #include <__utility/pair.h>
24134723edSLouis Dionne 
25134723edSLouis Dionne #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
26134723edSLouis Dionne #  pragma GCC system_header
27134723edSLouis Dionne #endif
28134723edSLouis Dionne 
29134723edSLouis Dionne _LIBCPP_BEGIN_NAMESPACE_STD
30134723edSLouis Dionne 
31101d1e9bSNikolas Klauser template <class _AlgPolicy,
329783f28cSLouis Dionne           class _Iter1,
339783f28cSLouis Dionne           class _Sent1,
349783f28cSLouis Dionne           class _Iter2,
359783f28cSLouis Dionne           class _Sent2,
36101d1e9bSNikolas Klauser           class _Pred,
37101d1e9bSNikolas Klauser           class _Proj1,
38101d1e9bSNikolas Klauser           class _Proj2>
399783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_forward_impl(
409783f28cSLouis Dionne     _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) {
41d03aa7d6SLouis Dionne   if (__first2 == __last2)
42101d1e9bSNikolas Klauser     return std::make_pair(__first1, __first1); // Everything matches an empty sequence
43d03aa7d6SLouis Dionne   while (true) {
44d03aa7d6SLouis Dionne     // Find first element in sequence 1 that matchs *__first2, with a mininum of loop checks
45d03aa7d6SLouis Dionne     while (true) {
46101d1e9bSNikolas Klauser       if (__first1 == __last1) { // return __last1 if no element matches *__first2
47101d1e9bSNikolas Klauser         _IterOps<_AlgPolicy>::__advance_to(__first1, __last1);
48101d1e9bSNikolas Klauser         return std::make_pair(__first1, __first1);
49101d1e9bSNikolas Klauser       }
50101d1e9bSNikolas Klauser       if (std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2)))
51d03aa7d6SLouis Dionne         break;
52d03aa7d6SLouis Dionne       ++__first1;
53d03aa7d6SLouis Dionne     }
54d03aa7d6SLouis Dionne     // *__first1 matches *__first2, now match elements after here
55101d1e9bSNikolas Klauser     _Iter1 __m1 = __first1;
56101d1e9bSNikolas Klauser     _Iter2 __m2 = __first2;
57d03aa7d6SLouis Dionne     while (true) {
58d03aa7d6SLouis Dionne       if (++__m2 == __last2) // If pattern exhausted, __first1 is the answer (works for 1 element pattern)
59101d1e9bSNikolas Klauser         return std::make_pair(__first1, ++__m1);
60101d1e9bSNikolas Klauser       if (++__m1 == __last1) { // Otherwise if source exhaused, pattern not found
61101d1e9bSNikolas Klauser         return std::make_pair(__m1, __m1);
62101d1e9bSNikolas Klauser       }
63101d1e9bSNikolas Klauser 
64101d1e9bSNikolas Klauser       // if there is a mismatch, restart with a new __first1
659783f28cSLouis Dionne       if (!std::__invoke(__pred, std::__invoke(__proj1, *__m1), std::__invoke(__proj2, *__m2))) {
66d03aa7d6SLouis Dionne         ++__first1;
67d03aa7d6SLouis Dionne         break;
68d03aa7d6SLouis Dionne       } // else there is a match, check next elements
69d03aa7d6SLouis Dionne     }
70d03aa7d6SLouis Dionne   }
71d03aa7d6SLouis Dionne }
72d03aa7d6SLouis Dionne 
73101d1e9bSNikolas Klauser template <class _AlgPolicy,
749783f28cSLouis Dionne           class _Iter1,
759783f28cSLouis Dionne           class _Sent1,
769783f28cSLouis Dionne           class _Iter2,
779783f28cSLouis Dionne           class _Sent2,
78101d1e9bSNikolas Klauser           class _Pred,
79101d1e9bSNikolas Klauser           class _Proj1,
80101d1e9bSNikolas Klauser           class _Proj2,
81101d1e9bSNikolas Klauser           class _DiffT1,
82101d1e9bSNikolas Klauser           class _DiffT2>
839783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_random_access_impl(
849783f28cSLouis Dionne     _Iter1 __first1,
859783f28cSLouis Dionne     _Sent1 __last1,
869783f28cSLouis Dionne     _Iter2 __first2,
879783f28cSLouis Dionne     _Sent2 __last2,
88101d1e9bSNikolas Klauser     _Pred& __pred,
89101d1e9bSNikolas Klauser     _Proj1& __proj1,
90101d1e9bSNikolas Klauser     _Proj2& __proj2,
91101d1e9bSNikolas Klauser     _DiffT1 __size1,
92101d1e9bSNikolas Klauser     _DiffT2 __size2) {
93101d1e9bSNikolas Klauser   const _Iter1 __s = __first1 + __size1 - _DiffT1(__size2 - 1); // Start of pattern match can't go beyond here
94d03aa7d6SLouis Dionne 
95d03aa7d6SLouis Dionne   while (true) {
96d03aa7d6SLouis Dionne     while (true) {
97101d1e9bSNikolas Klauser       if (__first1 == __s) {
98101d1e9bSNikolas Klauser         _IterOps<_AlgPolicy>::__advance_to(__first1, __last1);
99101d1e9bSNikolas Klauser         return std::make_pair(__first1, __first1);
100101d1e9bSNikolas Klauser       }
101101d1e9bSNikolas Klauser       if (std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2)))
102d03aa7d6SLouis Dionne         break;
103d03aa7d6SLouis Dionne       ++__first1;
104d03aa7d6SLouis Dionne     }
105d03aa7d6SLouis Dionne 
106101d1e9bSNikolas Klauser     _Iter1 __m1 = __first1;
107101d1e9bSNikolas Klauser     _Iter2 __m2 = __first2;
108d03aa7d6SLouis Dionne     while (true) {
109d03aa7d6SLouis Dionne       if (++__m2 == __last2)
110101d1e9bSNikolas Klauser         return std::make_pair(__first1, __first1 + _DiffT1(__size2));
111d03aa7d6SLouis Dionne       ++__m1; // no need to check range on __m1 because __s guarantees we have enough source
112101d1e9bSNikolas Klauser       if (!std::__invoke(__pred, std::__invoke(__proj1, *__m1), std::__invoke(__proj2, *__m2))) {
113d03aa7d6SLouis Dionne         ++__first1;
114d03aa7d6SLouis Dionne         break;
115d03aa7d6SLouis Dionne       }
116d03aa7d6SLouis Dionne     }
117d03aa7d6SLouis Dionne   }
118d03aa7d6SLouis Dionne }
119d03aa7d6SLouis Dionne 
12076a24727SNikolas Klauser template <class _Iter1,
12176a24727SNikolas Klauser           class _Sent1,
12276a24727SNikolas Klauser           class _Iter2,
12376a24727SNikolas Klauser           class _Sent2,
12476a24727SNikolas Klauser           class _Pred,
12576a24727SNikolas Klauser           class _Proj1,
12676a24727SNikolas Klauser           class _Proj2,
1279783f28cSLouis Dionne           __enable_if_t<__has_random_access_iterator_category<_Iter1>::value &&
12876a24727SNikolas Klauser                             __has_random_access_iterator_category<_Iter2>::value,
12976a24727SNikolas Klauser                         int> = 0>
13076a24727SNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_impl(
13176a24727SNikolas Klauser     _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) {
132101d1e9bSNikolas Klauser   auto __size2 = __last2 - __first2;
133101d1e9bSNikolas Klauser   if (__size2 == 0)
134101d1e9bSNikolas Klauser     return std::make_pair(__first1, __first1);
135101d1e9bSNikolas Klauser 
136101d1e9bSNikolas Klauser   auto __size1 = __last1 - __first1;
137101d1e9bSNikolas Klauser   if (__size1 < __size2) {
138101d1e9bSNikolas Klauser     return std::make_pair(__last1, __last1);
139101d1e9bSNikolas Klauser   }
140101d1e9bSNikolas Klauser 
1419783f28cSLouis Dionne   return std::__search_random_access_impl<_ClassicAlgPolicy>(
1429783f28cSLouis Dionne       __first1, __last1, __first2, __last2, __pred, __proj1, __proj2, __size1, __size2);
143101d1e9bSNikolas Klauser }
144101d1e9bSNikolas Klauser 
14576a24727SNikolas Klauser template <
14676a24727SNikolas Klauser     class _Iter1,
14776a24727SNikolas Klauser     class _Sent1,
14876a24727SNikolas Klauser     class _Iter2,
14976a24727SNikolas Klauser     class _Sent2,
15076a24727SNikolas Klauser     class _Pred,
15176a24727SNikolas Klauser     class _Proj1,
15276a24727SNikolas Klauser     class _Proj2,
1539783f28cSLouis Dionne     __enable_if_t<__has_forward_iterator_category<_Iter1>::value && __has_forward_iterator_category<_Iter2>::value &&
1549783f28cSLouis Dionne                       !(__has_random_access_iterator_category<_Iter1>::value &&
15576a24727SNikolas Klauser                         __has_random_access_iterator_category<_Iter2>::value),
15676a24727SNikolas Klauser                   int> = 0>
15776a24727SNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_impl(
15876a24727SNikolas Klauser     _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) {
1599783f28cSLouis Dionne   return std::__search_forward_impl<_ClassicAlgPolicy>(__first1, __last1, __first2, __last2, __pred, __proj1, __proj2);
160101d1e9bSNikolas Klauser }
161101d1e9bSNikolas Klauser 
162134723edSLouis Dionne template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
16317e0686aSNikolas Klauser [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1
1649783f28cSLouis Dionne search(_ForwardIterator1 __first1,
1659783f28cSLouis Dionne        _ForwardIterator1 __last1,
1669783f28cSLouis Dionne        _ForwardIterator2 __first2,
1679783f28cSLouis Dionne        _ForwardIterator2 __last2,
168134723edSLouis Dionne        _BinaryPredicate __pred) {
16925783158SLouis Dionne   static_assert(__is_callable<_BinaryPredicate&, decltype(*__first1), decltype(*__first2)>::value,
17025783158SLouis Dionne                 "The comparator has to be callable");
171101d1e9bSNikolas Klauser   auto __proj = __identity();
172101d1e9bSNikolas Klauser   return std::__search_impl(__first1, __last1, __first2, __last2, __pred, __proj, __proj).first;
173134723edSLouis Dionne }
174134723edSLouis Dionne 
175134723edSLouis Dionne template <class _ForwardIterator1, class _ForwardIterator2>
17617e0686aSNikolas Klauser [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1
1779783f28cSLouis Dionne search(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2) {
178e07ca2aeSAlvin Wong   return std::search(__first1, __last1, __first2, __last2, __equal_to());
179134723edSLouis Dionne }
180134723edSLouis Dionne 
1814f15267dSNikolas Klauser #if _LIBCPP_STD_VER >= 17
182134723edSLouis Dionne template <class _ForwardIterator, class _Searcher>
18383bc7b57SNikolas Klauser [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator
184134723edSLouis Dionne search(_ForwardIterator __f, _ForwardIterator __l, const _Searcher& __s) {
185134723edSLouis Dionne   return __s(__f, __l).first;
186134723edSLouis Dionne }
187134723edSLouis Dionne 
188134723edSLouis Dionne #endif
189134723edSLouis Dionne 
190134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD
191134723edSLouis Dionne 
192134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_SEARCH_H
193