1fe6060f1SDimitry Andric // -*- C++ -*- 2fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 3fe6060f1SDimitry Andric // 4fe6060f1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5fe6060f1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 6fe6060f1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7fe6060f1SDimitry Andric // 8fe6060f1SDimitry Andric //===----------------------------------------------------------------------===// 9fe6060f1SDimitry Andric 10fe6060f1SDimitry Andric #ifndef _LIBCPP___ALGORITHM_SEARCH_H 11fe6060f1SDimitry Andric #define _LIBCPP___ALGORITHM_SEARCH_H 12fe6060f1SDimitry Andric 13fe6060f1SDimitry Andric #include <__algorithm/comp.h> 14753f127fSDimitry Andric #include <__algorithm/iterator_operations.h> 15fe6060f1SDimitry Andric #include <__config> 16753f127fSDimitry Andric #include <__functional/identity.h> 1706c3fb27SDimitry Andric #include <__functional/invoke.h> 18753f127fSDimitry Andric #include <__iterator/advance.h> 19753f127fSDimitry Andric #include <__iterator/concepts.h> 20fe6060f1SDimitry Andric #include <__iterator/iterator_traits.h> 2106c3fb27SDimitry Andric #include <__type_traits/enable_if.h> 22753f127fSDimitry Andric #include <__type_traits/is_callable.h> 2381ad6265SDimitry Andric #include <__utility/pair.h> 24fe6060f1SDimitry Andric 25fe6060f1SDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 26fe6060f1SDimitry Andric # pragma GCC system_header 27fe6060f1SDimitry Andric #endif 28fe6060f1SDimitry Andric 29fe6060f1SDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD 30fe6060f1SDimitry Andric 31753f127fSDimitry Andric template <class _AlgPolicy, 32cb14a3feSDimitry Andric class _Iter1, 33cb14a3feSDimitry Andric class _Sent1, 34cb14a3feSDimitry Andric class _Iter2, 35cb14a3feSDimitry Andric class _Sent2, 36753f127fSDimitry Andric class _Pred, 37753f127fSDimitry Andric class _Proj1, 38753f127fSDimitry Andric class _Proj2> 39cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_forward_impl( 40cb14a3feSDimitry Andric _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { 41fe6060f1SDimitry Andric if (__first2 == __last2) 42753f127fSDimitry Andric return std::make_pair(__first1, __first1); // Everything matches an empty sequence 43fe6060f1SDimitry Andric while (true) { 44fe6060f1SDimitry Andric // Find first element in sequence 1 that matchs *__first2, with a mininum of loop checks 45fe6060f1SDimitry Andric while (true) { 46753f127fSDimitry Andric if (__first1 == __last1) { // return __last1 if no element matches *__first2 47753f127fSDimitry Andric _IterOps<_AlgPolicy>::__advance_to(__first1, __last1); 48753f127fSDimitry Andric return std::make_pair(__first1, __first1); 49753f127fSDimitry Andric } 50753f127fSDimitry Andric if (std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) 51fe6060f1SDimitry Andric break; 52fe6060f1SDimitry Andric ++__first1; 53fe6060f1SDimitry Andric } 54fe6060f1SDimitry Andric // *__first1 matches *__first2, now match elements after here 55753f127fSDimitry Andric _Iter1 __m1 = __first1; 56753f127fSDimitry Andric _Iter2 __m2 = __first2; 57fe6060f1SDimitry Andric while (true) { 58fe6060f1SDimitry Andric if (++__m2 == __last2) // If pattern exhausted, __first1 is the answer (works for 1 element pattern) 59753f127fSDimitry Andric return std::make_pair(__first1, ++__m1); 60753f127fSDimitry Andric if (++__m1 == __last1) { // Otherwise if source exhaused, pattern not found 61753f127fSDimitry Andric return std::make_pair(__m1, __m1); 62753f127fSDimitry Andric } 63753f127fSDimitry Andric 64753f127fSDimitry Andric // if there is a mismatch, restart with a new __first1 65cb14a3feSDimitry Andric if (!std::__invoke(__pred, std::__invoke(__proj1, *__m1), std::__invoke(__proj2, *__m2))) { 66fe6060f1SDimitry Andric ++__first1; 67fe6060f1SDimitry Andric break; 68fe6060f1SDimitry Andric } // else there is a match, check next elements 69fe6060f1SDimitry Andric } 70fe6060f1SDimitry Andric } 71fe6060f1SDimitry Andric } 72fe6060f1SDimitry Andric 73753f127fSDimitry Andric template <class _AlgPolicy, 74cb14a3feSDimitry Andric class _Iter1, 75cb14a3feSDimitry Andric class _Sent1, 76cb14a3feSDimitry Andric class _Iter2, 77cb14a3feSDimitry Andric class _Sent2, 78753f127fSDimitry Andric class _Pred, 79753f127fSDimitry Andric class _Proj1, 80753f127fSDimitry Andric class _Proj2, 81753f127fSDimitry Andric class _DiffT1, 82753f127fSDimitry Andric class _DiffT2> 83cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_random_access_impl( 84cb14a3feSDimitry Andric _Iter1 __first1, 85cb14a3feSDimitry Andric _Sent1 __last1, 86cb14a3feSDimitry Andric _Iter2 __first2, 87cb14a3feSDimitry Andric _Sent2 __last2, 88753f127fSDimitry Andric _Pred& __pred, 89753f127fSDimitry Andric _Proj1& __proj1, 90753f127fSDimitry Andric _Proj2& __proj2, 91753f127fSDimitry Andric _DiffT1 __size1, 92753f127fSDimitry Andric _DiffT2 __size2) { 93753f127fSDimitry Andric const _Iter1 __s = __first1 + __size1 - _DiffT1(__size2 - 1); // Start of pattern match can't go beyond here 94fe6060f1SDimitry Andric 95fe6060f1SDimitry Andric while (true) { 96fe6060f1SDimitry Andric while (true) { 97753f127fSDimitry Andric if (__first1 == __s) { 98753f127fSDimitry Andric _IterOps<_AlgPolicy>::__advance_to(__first1, __last1); 99753f127fSDimitry Andric return std::make_pair(__first1, __first1); 100753f127fSDimitry Andric } 101753f127fSDimitry Andric if (std::__invoke(__pred, std::__invoke(__proj1, *__first1), std::__invoke(__proj2, *__first2))) 102fe6060f1SDimitry Andric break; 103fe6060f1SDimitry Andric ++__first1; 104fe6060f1SDimitry Andric } 105fe6060f1SDimitry Andric 106753f127fSDimitry Andric _Iter1 __m1 = __first1; 107753f127fSDimitry Andric _Iter2 __m2 = __first2; 108fe6060f1SDimitry Andric while (true) { 109fe6060f1SDimitry Andric if (++__m2 == __last2) 110753f127fSDimitry Andric return std::make_pair(__first1, __first1 + _DiffT1(__size2)); 111fe6060f1SDimitry Andric ++__m1; // no need to check range on __m1 because __s guarantees we have enough source 112753f127fSDimitry Andric if (!std::__invoke(__pred, std::__invoke(__proj1, *__m1), std::__invoke(__proj2, *__m2))) { 113fe6060f1SDimitry Andric ++__first1; 114fe6060f1SDimitry Andric break; 115fe6060f1SDimitry Andric } 116fe6060f1SDimitry Andric } 117fe6060f1SDimitry Andric } 118fe6060f1SDimitry Andric } 119fe6060f1SDimitry Andric 120*0fca6ea1SDimitry Andric template <class _Iter1, 121*0fca6ea1SDimitry Andric class _Sent1, 122*0fca6ea1SDimitry Andric class _Iter2, 123*0fca6ea1SDimitry Andric class _Sent2, 124*0fca6ea1SDimitry Andric class _Pred, 125*0fca6ea1SDimitry Andric class _Proj1, 126*0fca6ea1SDimitry Andric class _Proj2, 127cb14a3feSDimitry Andric __enable_if_t<__has_random_access_iterator_category<_Iter1>::value && 128*0fca6ea1SDimitry Andric __has_random_access_iterator_category<_Iter2>::value, 129*0fca6ea1SDimitry Andric int> = 0> 130*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_impl( 131*0fca6ea1SDimitry Andric _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { 132753f127fSDimitry Andric auto __size2 = __last2 - __first2; 133753f127fSDimitry Andric if (__size2 == 0) 134753f127fSDimitry Andric return std::make_pair(__first1, __first1); 135753f127fSDimitry Andric 136753f127fSDimitry Andric auto __size1 = __last1 - __first1; 137753f127fSDimitry Andric if (__size1 < __size2) { 138753f127fSDimitry Andric return std::make_pair(__last1, __last1); 139753f127fSDimitry Andric } 140753f127fSDimitry Andric 141cb14a3feSDimitry Andric return std::__search_random_access_impl<_ClassicAlgPolicy>( 142cb14a3feSDimitry Andric __first1, __last1, __first2, __last2, __pred, __proj1, __proj2, __size1, __size2); 143753f127fSDimitry Andric } 144753f127fSDimitry Andric 145*0fca6ea1SDimitry Andric template < 146*0fca6ea1SDimitry Andric class _Iter1, 147*0fca6ea1SDimitry Andric class _Sent1, 148*0fca6ea1SDimitry Andric class _Iter2, 149*0fca6ea1SDimitry Andric class _Sent2, 150*0fca6ea1SDimitry Andric class _Pred, 151*0fca6ea1SDimitry Andric class _Proj1, 152*0fca6ea1SDimitry Andric class _Proj2, 153cb14a3feSDimitry Andric __enable_if_t<__has_forward_iterator_category<_Iter1>::value && __has_forward_iterator_category<_Iter2>::value && 154cb14a3feSDimitry Andric !(__has_random_access_iterator_category<_Iter1>::value && 155*0fca6ea1SDimitry Andric __has_random_access_iterator_category<_Iter2>::value), 156*0fca6ea1SDimitry Andric int> = 0> 157*0fca6ea1SDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_impl( 158*0fca6ea1SDimitry Andric _Iter1 __first1, _Sent1 __last1, _Iter2 __first2, _Sent2 __last2, _Pred& __pred, _Proj1& __proj1, _Proj2& __proj2) { 159cb14a3feSDimitry Andric return std::__search_forward_impl<_ClassicAlgPolicy>(__first1, __last1, __first2, __last2, __pred, __proj1, __proj2); 160753f127fSDimitry Andric } 161753f127fSDimitry Andric 162fe6060f1SDimitry Andric template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate> 163*0fca6ea1SDimitry Andric _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1 164cb14a3feSDimitry Andric search(_ForwardIterator1 __first1, 165cb14a3feSDimitry Andric _ForwardIterator1 __last1, 166cb14a3feSDimitry Andric _ForwardIterator2 __first2, 167cb14a3feSDimitry Andric _ForwardIterator2 __last2, 168fe6060f1SDimitry Andric _BinaryPredicate __pred) { 169753f127fSDimitry Andric static_assert(__is_callable<_BinaryPredicate, decltype(*__first1), decltype(*__first2)>::value, 170753f127fSDimitry Andric "BinaryPredicate has to be callable"); 171753f127fSDimitry Andric auto __proj = __identity(); 172753f127fSDimitry Andric return std::__search_impl(__first1, __last1, __first2, __last2, __pred, __proj, __proj).first; 173fe6060f1SDimitry Andric } 174fe6060f1SDimitry Andric 175fe6060f1SDimitry Andric template <class _ForwardIterator1, class _ForwardIterator2> 176*0fca6ea1SDimitry Andric _LIBCPP_NODISCARD inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1 177cb14a3feSDimitry Andric search(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2) { 178bdd1243dSDimitry Andric return std::search(__first1, __last1, __first2, __last2, __equal_to()); 179fe6060f1SDimitry Andric } 180fe6060f1SDimitry Andric 18106c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 17 182fe6060f1SDimitry Andric template <class _ForwardIterator, class _Searcher> 183*0fca6ea1SDimitry Andric [[nodiscard]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator 184fe6060f1SDimitry Andric search(_ForwardIterator __f, _ForwardIterator __l, const _Searcher& __s) { 185fe6060f1SDimitry Andric return __s(__f, __l).first; 186fe6060f1SDimitry Andric } 187fe6060f1SDimitry Andric 188fe6060f1SDimitry Andric #endif 189fe6060f1SDimitry Andric 190fe6060f1SDimitry Andric _LIBCPP_END_NAMESPACE_STD 191fe6060f1SDimitry Andric 192fe6060f1SDimitry Andric #endif // _LIBCPP___ALGORITHM_SEARCH_H 193