Skip to content

Commit 88a5755

Browse files
committed
[libc++] Optimize search_n
1 parent ccd76c5 commit 88a5755

File tree

2 files changed

+36
-33
lines changed

2 files changed

+36
-33
lines changed

libcxx/include/__algorithm/ranges_search_n.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,8 +54,8 @@ struct __search_n {
5454
}
5555

5656
if constexpr (random_access_iterator<_Iter1>) {
57-
auto __ret = std::__search_n_random_access_impl<_RangeAlgPolicy>(
58-
__first, __last, __count, __value, __pred, __proj, __size);
57+
auto __ret =
58+
std::__search_n_random_access_impl<_RangeAlgPolicy>(__first, __count, __value, __pred, __proj, __size);
5959
return {std::move(__ret.first), std::move(__ret.second)};
6060
}
6161
}

libcxx/include/__algorithm/search_n.h

Lines changed: 34 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,9 @@
1111
#define _LIBCPP___ALGORITHM_SEARCH_N_H
1212

1313
#include <__algorithm/comp.h>
14+
#include <__algorithm/find.h>
1415
#include <__algorithm/iterator_operations.h>
16+
#include <__algorithm/unwrap_iter.h>
1517
#include <__config>
1618
#include <__functional/identity.h>
1719
#include <__iterator/advance.h>
@@ -68,43 +70,35 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter, _Iter> __search_
6870
}
6971
}
7072

71-
template <class _AlgPolicy, class _Pred, class _Iter, class _Sent, class _SizeT, class _Type, class _Proj, class _DiffT>
73+
template <class _AlgPolicy, class _Pred, class _Iter, class _SizeT, class _Type, class _Proj, class _DiffT>
7274
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 std::pair<_Iter, _Iter> __search_n_random_access_impl(
73-
_Iter __first, _Sent __last, _SizeT __count, const _Type& __value, _Pred& __pred, _Proj& __proj, _DiffT __size1) {
74-
using difference_type = typename iterator_traits<_Iter>::difference_type;
75+
_Iter __first, _SizeT __count_in, const _Type& __value, _Pred& __pred, _Proj& __proj, _DiffT __size) {
76+
auto __last = __first + __size;
77+
auto __count = static_cast<_DiffT>(__count_in);
78+
7579
if (__count == 0)
7680
return std::make_pair(__first, __first);
77-
if (__size1 < static_cast<_DiffT>(__count)) {
78-
_IterOps<_AlgPolicy>::__advance_to(__first, __last);
79-
return std::make_pair(__first, __first);
80-
}
81+
if (__size < __count)
82+
return std::make_pair(__last, __last);
8183

82-
const auto __s = __first + __size1 - difference_type(__count - 1); // Start of pattern match can't go beyond here
84+
_Iter __try_match_until = __last - __count;
85+
_Iter __match_start = __first;
86+
_Iter __matched_until = __first;
8387
while (true) {
84-
// Find first element in sequence that matchs __value, with a mininum of loop checks
85-
while (true) {
86-
if (__first >= __s) { // return __last if no element matches __value
87-
_IterOps<_AlgPolicy>::__advance_to(__first, __last);
88-
return std::make_pair(__first, __first);
89-
}
90-
if (std::__invoke(__pred, std::__invoke(__proj, *__first), __value))
91-
break;
92-
++__first;
93-
}
94-
// *__first matches __value_, now match elements after here
95-
auto __m = __first;
96-
_SizeT __c(0);
88+
if (__match_start > __try_match_until)
89+
return std::make_pair(__last, __last);
90+
91+
_Iter __check = __match_start + __count;
92+
9793
while (true) {
98-
if (++__c == __count) // If pattern exhausted, __first is the answer (works for 1 element pattern)
99-
return std::make_pair(__first, __first + _DiffT(__count));
100-
++__m; // no need to check range on __m because __s guarantees we have enough source
94+
if (__check == __matched_until)
95+
return std::make_pair(__match_start, __match_start + __count);
10196

102-
// if there is a mismatch, restart with a new __first
103-
if (!std::__invoke(__pred, std::__invoke(__proj, *__m), __value)) {
104-
__first = __m;
105-
++__first;
97+
if (!std::__invoke(__pred, std::__invoke(__proj, *--__check), __value)) {
98+
__matched_until = __match_start + __count;
99+
__match_start = ++__check;
106100
break;
107-
} // else there is a match, check next elements
101+
}
108102
}
109103
}
110104
}
@@ -119,7 +113,7 @@ template <class _Iter,
119113
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter, _Iter>
120114
__search_n_impl(_Iter __first, _Sent __last, _DiffT __count, const _Type& __value, _Pred& __pred, _Proj& __proj) {
121115
return std::__search_n_random_access_impl<_ClassicAlgPolicy>(
122-
__first, __last, __count, __value, __pred, __proj, __last - __first);
116+
__first, __count, __value, __pred, __proj, __last - __first);
123117
}
124118

125119
template <class _Iter1,
@@ -142,7 +136,16 @@ template <class _ForwardIterator, class _Size, class _Tp, class _BinaryPredicate
142136
static_assert(
143137
__is_callable<_BinaryPredicate&, decltype(*__first), const _Tp&>::value, "The comparator has to be callable");
144138
auto __proj = __identity();
145-
return std::__search_n_impl(__first, __last, std::__convert_to_integral(__count), __value, __pred, __proj).first;
139+
return std::__rewrap_iter(
140+
__first,
141+
std::__search_n_impl(
142+
std::__unwrap_iter(__first),
143+
std::__unwrap_iter(__last),
144+
std::__convert_to_integral(__count),
145+
__value,
146+
__pred,
147+
__proj)
148+
.first);
146149
}
147150

148151
template <class _ForwardIterator, class _Size, class _Tp>

0 commit comments

Comments
 (0)