-
Notifications
You must be signed in to change notification settings - Fork 15.5k
[libc++] Add __find_end optimizations back
#171374
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
__find_end optimizations back (#100685)"__find_end optimizations back
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
This essentially reverts llvm#100685 and fixes the bidirectional and random access specializations to be actually used.
39ed635 to
6bd55e7
Compare
ldionne
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is related to #129318, but doesn't solve it entirely since we need to do a proper investigation of whether additional gains are possible.
|
@llvm/pr-subscribers-libcxx Author: Nikolas Klauser (philnik777) ChangesThis essentially reverts #100685 and fixes the bidirectional and random access specializations to be actually used. Full diff: https://github.com/llvm/llvm-project/pull/171374.diff 1 Files Affected:
diff --git a/libcxx/include/__algorithm/find_end.h b/libcxx/include/__algorithm/find_end.h
index 86b4a3e2e3689..84b43e31a3a59 100644
--- a/libcxx/include/__algorithm/find_end.h
+++ b/libcxx/include/__algorithm/find_end.h
@@ -76,6 +76,111 @@ _LIBCPP_HIDE_FROM_ABI inline _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1>
}
}
+template <class _AlgPolicy,
+ class _Pred,
+ class _Iter1,
+ class _Sent1,
+ class _Iter2,
+ class _Sent2,
+ class _Proj1,
+ class _Proj2>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 pair<_Iter1, _Iter1> __find_end_impl(
+ _Iter1 __first1,
+ _Sent1 __sent1,
+ _Iter2 __first2,
+ _Sent2 __sent2,
+ _Pred& __pred,
+ _Proj1& __proj1,
+ _Proj2& __proj2,
+ bidirectional_iterator_tag,
+ bidirectional_iterator_tag) {
+ auto __last1 = _IterOps<_AlgPolicy>::next(__first1, __sent1);
+ auto __last2 = _IterOps<_AlgPolicy>::next(__first2, __sent2);
+ // modeled after search algorithm (in reverse)
+ if (__first2 == __last2)
+ return std::make_pair(__last1, __last1); // Everything matches an empty sequence
+ _Iter1 __l1 = __last1;
+ _Iter2 __l2 = __last2;
+ --__l2;
+ while (true) {
+ // Find last element in sequence 1 that matches *(__last2-1), with a mininum of loop checks
+ while (true) {
+ if (__first1 == __l1) // return __last1 if no element matches *__first2
+ return std::make_pair(__last1, __last1);
+ if (std::__invoke(__pred, std::__invoke(__proj1, *--__l1), std::__invoke(__proj2, *__l2)))
+ break;
+ }
+ // *__l1 matches *__l2, now match elements before here
+ _Iter1 __match_last = __l1;
+ _Iter1 __m1 = __l1;
+ _Iter2 __m2 = __l2;
+ while (true) {
+ if (__m2 == __first2) // If pattern exhausted, __m1 is the answer (works for 1 element pattern)
+ return std::make_pair(__m1, ++__match_last);
+ if (__m1 == __first1) // Otherwise if source exhaused, pattern not found
+ return std::make_pair(__last1, __last1);
+
+ // if there is a mismatch, restart with a new __l1
+ if (!std::__invoke(__pred, std::__invoke(__proj1, *--__m1), std::__invoke(__proj2, *--__m2))) {
+ break;
+ } // else there is a match, check next elements
+ }
+ }
+}
+
+template <class _AlgPolicy,
+ class _Pred,
+ class _Iter1,
+ class _Sent1,
+ class _Iter2,
+ class _Sent2,
+ class _Proj1,
+ class _Proj2>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_Iter1, _Iter1> __find_end_impl(
+ _Iter1 __first1,
+ _Sent1 __sent1,
+ _Iter2 __first2,
+ _Sent2 __sent2,
+ _Pred& __pred,
+ _Proj1& __proj1,
+ _Proj2& __proj2,
+ random_access_iterator_tag,
+ random_access_iterator_tag) {
+ typedef typename iterator_traits<_Iter1>::difference_type _D1;
+ auto __last1 = _IterOps<_AlgPolicy>::next(__first1, __sent1);
+ auto __last2 = _IterOps<_AlgPolicy>::next(__first2, __sent2);
+ // Take advantage of knowing source and pattern lengths. Stop short when source is smaller than pattern
+ auto __len2 = __last2 - __first2;
+ if (__len2 == 0)
+ return std::make_pair(__last1, __last1);
+ auto __len1 = __last1 - __first1;
+ if (__len1 < __len2)
+ return std::make_pair(__last1, __last1);
+ const _Iter1 __s = __first1 + _D1(__len2 - 1); // End of pattern match can't go before here
+ _Iter1 __l1 = __last1;
+ _Iter2 __l2 = __last2;
+ --__l2;
+ while (true) {
+ while (true) {
+ if (__s == __l1)
+ return std::make_pair(__last1, __last1);
+ if (std::__invoke(__pred, std::__invoke(__proj1, *--__l1), std::__invoke(__proj2, *__l2)))
+ break;
+ }
+ _Iter1 __last_match = __l1;
+ _Iter1 __m1 = __l1;
+ _Iter2 __m2 = __l2;
+ while (true) {
+ if (__m2 == __first2)
+ return std::make_pair(__m1, ++__last_match);
+ // no need to check range on __m1 because __s guarantees we have enough source
+ if (!std::__invoke(__pred, std::__invoke(__proj1, *--__m1), std::__invoke(__proj2, *--__m2))) {
+ break;
+ }
+ }
+ }
+}
+
template <class _ForwardIterator1, class _ForwardIterator2, class _BinaryPredicate>
[[__nodiscard__]] inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _ForwardIterator1 __find_end_classic(
_ForwardIterator1 __first1,
|
This essentially reverts #100685 and fixes the bidirectional and random access specializations to be actually used.