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_N_H 11134723edSLouis Dionne #define _LIBCPP___ALGORITHM_SEARCH_N_H 12134723edSLouis Dionne 13134723edSLouis Dionne #include <__algorithm/comp.h> 14101d1e9bSNikolas Klauser #include <__algorithm/iterator_operations.h> 154d81a46fSArthur O'Dwyer #include <__config> 16101d1e9bSNikolas Klauser #include <__functional/identity.h> 17101d1e9bSNikolas Klauser #include <__iterator/advance.h> 18101d1e9bSNikolas Klauser #include <__iterator/concepts.h> 19101d1e9bSNikolas Klauser #include <__iterator/distance.h> 20134723edSLouis Dionne #include <__iterator/iterator_traits.h> 21101d1e9bSNikolas Klauser #include <__ranges/concepts.h> 22*09e3a360SLouis Dionne #include <__type_traits/enable_if.h> 23*09e3a360SLouis Dionne #include <__type_traits/invoke.h> 24e698c595SNikolas Klauser #include <__type_traits/is_callable.h> 257ae66e5eSNikolas Klauser #include <__utility/convert_to_integral.h> 26101d1e9bSNikolas Klauser #include <__utility/pair.h> 27134723edSLouis Dionne 28134723edSLouis Dionne #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 29134723edSLouis Dionne # pragma GCC system_header 30134723edSLouis Dionne #endif 31134723edSLouis Dionne 32134723edSLouis Dionne _LIBCPP_BEGIN_NAMESPACE_STD 33134723edSLouis Dionne 34101d1e9bSNikolas Klauser template <class _AlgPolicy, class _Pred, class _Iter, class _Sent, class _SizeT, class _Type, class _Proj> 359783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter, _Iter> __search_n_forward_impl( 369783f28cSLouis Dionne _Iter __first, _Sent __last, _SizeT __count, const _Type& __value, _Pred& __pred, _Proj& __proj) { 37134723edSLouis Dionne if (__count <= 0) 38101d1e9bSNikolas Klauser return std::make_pair(__first, __first); 39134723edSLouis Dionne while (true) { 40101d1e9bSNikolas Klauser // Find first element in sequence that matchs __value, with a mininum of loop checks 41134723edSLouis Dionne while (true) { 42101d1e9bSNikolas Klauser if (__first == __last) { // return __last if no element matches __value 43101d1e9bSNikolas Klauser _IterOps<_AlgPolicy>::__advance_to(__first, __last); 44101d1e9bSNikolas Klauser return std::make_pair(__first, __first); 45101d1e9bSNikolas Klauser } 46101d1e9bSNikolas Klauser if (std::__invoke(__pred, std::__invoke(__proj, *__first), __value)) 47134723edSLouis Dionne break; 48134723edSLouis Dionne ++__first; 49134723edSLouis Dionne } 50101d1e9bSNikolas Klauser // *__first matches __value, now match elements after here 51101d1e9bSNikolas Klauser _Iter __m = __first; 52101d1e9bSNikolas Klauser _SizeT __c(0); 53134723edSLouis Dionne while (true) { 54134723edSLouis Dionne if (++__c == __count) // If pattern exhausted, __first is the answer (works for 1 element pattern) 55101d1e9bSNikolas Klauser return std::make_pair(__first, ++__m); 56101d1e9bSNikolas Klauser if (++__m == __last) { // Otherwise if source exhaused, pattern not found 57101d1e9bSNikolas Klauser _IterOps<_AlgPolicy>::__advance_to(__first, __last); 58101d1e9bSNikolas Klauser return std::make_pair(__first, __first); 59101d1e9bSNikolas Klauser } 60101d1e9bSNikolas Klauser 61101d1e9bSNikolas Klauser // if there is a mismatch, restart with a new __first 629783f28cSLouis Dionne if (!std::__invoke(__pred, std::__invoke(__proj, *__m), __value)) { 63134723edSLouis Dionne __first = __m; 64134723edSLouis Dionne ++__first; 65134723edSLouis Dionne break; 66134723edSLouis Dionne } // else there is a match, check next elements 67134723edSLouis Dionne } 68134723edSLouis Dionne } 69134723edSLouis Dionne } 70134723edSLouis Dionne 71101d1e9bSNikolas Klauser template <class _AlgPolicy, class _Pred, class _Iter, class _Sent, class _SizeT, class _Type, class _Proj, class _DiffT> 729783f28cSLouis Dionne _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 std::pair<_Iter, _Iter> __search_n_random_access_impl( 739783f28cSLouis Dionne _Iter __first, _Sent __last, _SizeT __count, const _Type& __value, _Pred& __pred, _Proj& __proj, _DiffT __size1) { 74101d1e9bSNikolas Klauser using difference_type = typename iterator_traits<_Iter>::difference_type; 75101d1e9bSNikolas Klauser if (__count == 0) 76101d1e9bSNikolas Klauser return std::make_pair(__first, __first); 77101d1e9bSNikolas Klauser if (__size1 < static_cast<_DiffT>(__count)) { 78101d1e9bSNikolas Klauser _IterOps<_AlgPolicy>::__advance_to(__first, __last); 79101d1e9bSNikolas Klauser return std::make_pair(__first, __first); 80101d1e9bSNikolas Klauser } 81101d1e9bSNikolas Klauser 82101d1e9bSNikolas Klauser const auto __s = __first + __size1 - difference_type(__count - 1); // Start of pattern match can't go beyond here 831f047593SNikolas Klauser while (true) { 84101d1e9bSNikolas Klauser // Find first element in sequence that matchs __value, with a mininum of loop checks 851f047593SNikolas Klauser while (true) { 86101d1e9bSNikolas Klauser if (__first >= __s) { // return __last if no element matches __value 87101d1e9bSNikolas Klauser _IterOps<_AlgPolicy>::__advance_to(__first, __last); 88101d1e9bSNikolas Klauser return std::make_pair(__first, __first); 89101d1e9bSNikolas Klauser } 90101d1e9bSNikolas Klauser if (std::__invoke(__pred, std::__invoke(__proj, *__first), __value)) 911f047593SNikolas Klauser break; 921f047593SNikolas Klauser ++__first; 9376a76518SNikolas Klauser } 941f047593SNikolas Klauser // *__first matches __value_, now match elements after here 95101d1e9bSNikolas Klauser auto __m = __first; 96101d1e9bSNikolas Klauser _SizeT __c(0); 971f047593SNikolas Klauser while (true) { 981f047593SNikolas Klauser if (++__c == __count) // If pattern exhausted, __first is the answer (works for 1 element pattern) 99101d1e9bSNikolas Klauser return std::make_pair(__first, __first + _DiffT(__count)); 1001f047593SNikolas Klauser ++__m; // no need to check range on __m because __s guarantees we have enough source 101101d1e9bSNikolas Klauser 102101d1e9bSNikolas Klauser // if there is a mismatch, restart with a new __first 1039783f28cSLouis Dionne if (!std::__invoke(__pred, std::__invoke(__proj, *__m), __value)) { 1041f047593SNikolas Klauser __first = __m; 1051f047593SNikolas Klauser ++__first; 1061f047593SNikolas Klauser break; 1071f047593SNikolas Klauser } // else there is a match, check next elements 1081f047593SNikolas Klauser } 1091f047593SNikolas Klauser } 11076a76518SNikolas Klauser } 11176a76518SNikolas Klauser 11276a24727SNikolas Klauser template <class _Iter, 11376a24727SNikolas Klauser class _Sent, 11476a24727SNikolas Klauser class _DiffT, 11576a24727SNikolas Klauser class _Type, 11676a24727SNikolas Klauser class _Pred, 11776a24727SNikolas Klauser class _Proj, 11876a24727SNikolas Klauser __enable_if_t<__has_random_access_iterator_category<_Iter>::value, int> = 0> 11976a24727SNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter, _Iter> 12076a24727SNikolas Klauser __search_n_impl(_Iter __first, _Sent __last, _DiffT __count, const _Type& __value, _Pred& __pred, _Proj& __proj) { 1219783f28cSLouis Dionne return std::__search_n_random_access_impl<_ClassicAlgPolicy>( 1229783f28cSLouis Dionne __first, __last, __count, __value, __pred, __proj, __last - __first); 123101d1e9bSNikolas Klauser } 124101d1e9bSNikolas Klauser 12576a24727SNikolas Klauser template <class _Iter1, 12676a24727SNikolas Klauser class _Sent1, 12776a24727SNikolas Klauser class _DiffT, 12876a24727SNikolas Klauser class _Type, 12976a24727SNikolas Klauser class _Pred, 13076a24727SNikolas Klauser class _Proj, 1319783f28cSLouis Dionne __enable_if_t<__has_forward_iterator_category<_Iter1>::value && 13276a24727SNikolas Klauser !__has_random_access_iterator_category<_Iter1>::value, 13376a24727SNikolas Klauser int> = 0> 13476a24727SNikolas Klauser _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> 13576a24727SNikolas Klauser __search_n_impl(_Iter1 __first, _Sent1 __last, _DiffT __count, const _Type& __value, _Pred& __pred, _Proj& __proj) { 1369783f28cSLouis Dionne return std::__search_n_forward_impl<_ClassicAlgPolicy>(__first, __last, __count, __value, __pred, __proj); 137101d1e9bSNikolas Klauser } 138101d1e9bSNikolas Klauser 139134723edSLouis Dionne template <class _ForwardIterator, class _Size, class _Tp, class _BinaryPredicate> 14017e0686aSNikolas Klauser [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator search_n( 1419783f28cSLouis Dionne _ForwardIterator __first, _ForwardIterator __last, _Size __count, const _Tp& __value, _BinaryPredicate __pred) { 1429783f28cSLouis Dionne static_assert( 14325783158SLouis Dionne __is_callable<_BinaryPredicate&, decltype(*__first), const _Tp&>::value, "The comparator has to be callable"); 144101d1e9bSNikolas Klauser auto __proj = __identity(); 145101d1e9bSNikolas Klauser return std::__search_n_impl(__first, __last, std::__convert_to_integral(__count), __value, __pred, __proj).first; 146134723edSLouis Dionne } 147134723edSLouis Dionne 148134723edSLouis Dionne template <class _ForwardIterator, class _Size, class _Tp> 14917e0686aSNikolas Klauser [[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _ForwardIterator 1509783f28cSLouis Dionne search_n(_ForwardIterator __first, _ForwardIterator __last, _Size __count, const _Tp& __value) { 151e07ca2aeSAlvin Wong return std::search_n(__first, __last, std::__convert_to_integral(__count), __value, __equal_to()); 152134723edSLouis Dionne } 153134723edSLouis Dionne 154134723edSLouis Dionne _LIBCPP_END_NAMESPACE_STD 155134723edSLouis Dionne 156134723edSLouis Dionne #endif // _LIBCPP___ALGORITHM_SEARCH_N_H 157