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, 32*cb14a3feSDimitry Andric class _Iter1, 33*cb14a3feSDimitry Andric class _Sent1, 34*cb14a3feSDimitry Andric class _Iter2, 35*cb14a3feSDimitry Andric class _Sent2, 36753f127fSDimitry Andric class _Pred, 37753f127fSDimitry Andric class _Proj1, 38753f127fSDimitry Andric class _Proj2> 39*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_forward_impl( 40*cb14a3feSDimitry 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 65*cb14a3feSDimitry 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, 74*cb14a3feSDimitry Andric class _Iter1, 75*cb14a3feSDimitry Andric class _Sent1, 76*cb14a3feSDimitry Andric class _Iter2, 77*cb14a3feSDimitry Andric class _Sent2, 78753f127fSDimitry Andric class _Pred, 79753f127fSDimitry Andric class _Proj1, 80753f127fSDimitry Andric class _Proj2, 81753f127fSDimitry Andric class _DiffT1, 82753f127fSDimitry Andric class _DiffT2> 83*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_random_access_impl( 84*cb14a3feSDimitry Andric _Iter1 __first1, 85*cb14a3feSDimitry Andric _Sent1 __last1, 86*cb14a3feSDimitry Andric _Iter2 __first2, 87*cb14a3feSDimitry 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*cb14a3feSDimitry Andric template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Pred, class _Proj1, class _Proj2> 121*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_impl( 122*cb14a3feSDimitry Andric _Iter1 __first1, 123*cb14a3feSDimitry Andric _Sent1 __last1, 124*cb14a3feSDimitry Andric _Iter2 __first2, 125*cb14a3feSDimitry Andric _Sent2 __last2, 126753f127fSDimitry Andric _Pred& __pred, 127753f127fSDimitry Andric _Proj1& __proj1, 128753f127fSDimitry Andric _Proj2& __proj2, 129*cb14a3feSDimitry Andric __enable_if_t<__has_random_access_iterator_category<_Iter1>::value && 130*cb14a3feSDimitry Andric __has_random_access_iterator_category<_Iter2>::value>* = nullptr) { 131753f127fSDimitry Andric auto __size2 = __last2 - __first2; 132753f127fSDimitry Andric if (__size2 == 0) 133753f127fSDimitry Andric return std::make_pair(__first1, __first1); 134753f127fSDimitry Andric 135753f127fSDimitry Andric auto __size1 = __last1 - __first1; 136753f127fSDimitry Andric if (__size1 < __size2) { 137753f127fSDimitry Andric return std::make_pair(__last1, __last1); 138753f127fSDimitry Andric } 139753f127fSDimitry Andric 140*cb14a3feSDimitry Andric return std::__search_random_access_impl<_ClassicAlgPolicy>( 141*cb14a3feSDimitry Andric __first1, __last1, __first2, __last2, __pred, __proj1, __proj2, __size1, __size2); 142753f127fSDimitry Andric } 143753f127fSDimitry Andric 144*cb14a3feSDimitry Andric template <class _Iter1, class _Sent1, class _Iter2, class _Sent2, class _Pred, class _Proj1, class _Proj2> 145*cb14a3feSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __search_impl( 146*cb14a3feSDimitry Andric _Iter1 __first1, 147*cb14a3feSDimitry Andric _Sent1 __last1, 148*cb14a3feSDimitry Andric _Iter2 __first2, 149*cb14a3feSDimitry Andric _Sent2 __last2, 150753f127fSDimitry Andric _Pred& __pred, 151753f127fSDimitry Andric _Proj1& __proj1, 152753f127fSDimitry Andric _Proj2& __proj2, 153*cb14a3feSDimitry Andric __enable_if_t<__has_forward_iterator_category<_Iter1>::value && __has_forward_iterator_category<_Iter2>::value && 154*cb14a3feSDimitry Andric !(__has_random_access_iterator_category<_Iter1>::value && 155*cb14a3feSDimitry Andric __has_random_access_iterator_category<_Iter2>::value)>* = nullptr) { 156*cb14a3feSDimitry Andric return std::__search_forward_impl<_ClassicAlgPolicy>(__first1, __last1, __first2, __last2, __pred, __proj1, __proj2); 157753f127fSDimitry Andric } 158753f127fSDimitry Andric 159fe6060f1SDimitry Andric template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate> 160*cb14a3feSDimitry Andric _LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1 161*cb14a3feSDimitry Andric search(_ForwardIterator1 __first1, 162*cb14a3feSDimitry Andric _ForwardIterator1 __last1, 163*cb14a3feSDimitry Andric _ForwardIterator2 __first2, 164*cb14a3feSDimitry Andric _ForwardIterator2 __last2, 165fe6060f1SDimitry Andric _BinaryPredicate __pred) { 166753f127fSDimitry Andric static_assert(__is_callable<_BinaryPredicate, decltype(*__first1), decltype(*__first2)>::value, 167753f127fSDimitry Andric "BinaryPredicate has to be callable"); 168753f127fSDimitry Andric auto __proj = __identity(); 169753f127fSDimitry Andric return std::__search_impl(__first1, __last1, __first2, __last2, __pred, __proj, __proj).first; 170fe6060f1SDimitry Andric } 171fe6060f1SDimitry Andric 172fe6060f1SDimitry Andric template <class _ForwardIterator1, class _ForwardIterator2> 173*cb14a3feSDimitry Andric _LIBCPP_NODISCARD_EXT inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator1 174*cb14a3feSDimitry Andric search(_ForwardIterator1 __first1, _ForwardIterator1 __last1, _ForwardIterator2 __first2, _ForwardIterator2 __last2) { 175bdd1243dSDimitry Andric return std::search(__first1, __last1, __first2, __last2, __equal_to()); 176fe6060f1SDimitry Andric } 177fe6060f1SDimitry Andric 17806c3fb27SDimitry Andric #if _LIBCPP_STD_VER >= 17 179fe6060f1SDimitry Andric template <class _ForwardIterator, class _Searcher> 1805f757f3fSDimitry Andric _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator 181fe6060f1SDimitry Andric search(_ForwardIterator __f, _ForwardIterator __l, const _Searcher& __s) { 182fe6060f1SDimitry Andric return __s(__f, __l).first; 183fe6060f1SDimitry Andric } 184fe6060f1SDimitry Andric 185fe6060f1SDimitry Andric #endif 186fe6060f1SDimitry Andric 187fe6060f1SDimitry Andric _LIBCPP_END_NAMESPACE_STD 188fe6060f1SDimitry Andric 189fe6060f1SDimitry Andric #endif // _LIBCPP___ALGORITHM_SEARCH_H 190