Skip to content

Commit 1b7878a

Browse files
committed
[libc++] Tiny optimizations for is_permutation
Replace hand-written loops with vectorized std::mismatch, std::find_if, and std::count_if
1 parent 6003c30 commit 1b7878a

File tree

1 file changed

+22
-19
lines changed

1 file changed

+22
-19
lines changed

libcxx/include/__algorithm/is_permutation.h

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,13 @@
1111
#define _LIBCPP___ALGORITHM_IS_PERMUTATION_H
1212

1313
#include <__algorithm/comp.h>
14+
#include <__algorithm/count_if.h>
15+
#include <__algorithm/find_if.h>
1416
#include <__algorithm/iterator_operations.h>
17+
#include <__algorithm/mismatch.h>
1518
#include <__config>
1619
#include <__functional/identity.h>
20+
#include <__functional/reference_wrapper.h>
1721
#include <__iterator/concepts.h>
1822
#include <__iterator/distance.h>
1923
#include <__iterator/iterator_traits.h>
@@ -82,28 +86,28 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation_impl(
8286

8387
for (auto __i = __first1; __i != __last1; ++__i) {
8488
// Have we already counted the number of *__i in [f1, l1)?
85-
auto __match = __first1;
86-
for (; __match != __i; ++__match) {
87-
if (std::__invoke(__pred, std::__invoke(__proj1, *__match), std::__invoke(__proj1, *__i)))
88-
break;
89-
}
89+
auto __match = std::find_if(__first1, __i, [&](typename iterator_traits<_Iter1>::reference __x) -> bool {
90+
return std::__invoke(__pred, std::__invoke(__proj1, __x), std::__invoke(__proj1, *__i));
91+
});
9092

9193
if (__match == __i) {
9294
// Count number of *__i in [f2, l2)
93-
_D1 __c2 = 0;
94-
for (auto __j = __first2; __j != __last2; ++__j) {
95-
if (std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj2, *__j)))
96-
++__c2;
97-
}
95+
__identity __ident1;
96+
auto __predicate1 = [&](typename iterator_traits<_Iter2>::reference __x) -> bool {
97+
return std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj2, __x));
98+
};
99+
_D1 __c2 = std::__count_if<_AlgPolicy>(__first2, __last2, __predicate1, __ident1);
98100
if (__c2 == 0)
99101
return false;
100102

101103
// Count number of *__i in [__i, l1) (we can start with 1)
102-
_D1 __c1 = 1;
103-
for (auto __j = _IterOps<_AlgPolicy>::next(__i); __j != __last1; ++__j) {
104-
if (std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj1, *__j)))
105-
++__c1;
106-
}
104+
__identity __ident2;
105+
auto __predicate2 = [&](typename iterator_traits<_Iter1>::reference __x) -> bool {
106+
return std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj1, __x));
107+
};
108+
auto __start = _IterOps<_AlgPolicy>::next(__i);
109+
_D1 __c1 = std::__count_if<_AlgPolicy>(__start, __last1, __predicate2, __ident2);
110+
__c1 += 1;
107111
if (__c1 != __c2)
108112
return false;
109113
}
@@ -117,10 +121,9 @@ template <class _AlgPolicy, class _ForwardIterator1, class _Sentinel1, class _Fo
117121
[[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation(
118122
_ForwardIterator1 __first1, _Sentinel1 __last1, _ForwardIterator2 __first2, _BinaryPredicate&& __pred) {
119123
// Shorten sequences as much as possible by lopping of any equal prefix.
120-
for (; __first1 != __last1; ++__first1, (void)++__first2) {
121-
if (!__pred(*__first1, *__first2))
122-
break;
123-
}
124+
auto __result = std::mismatch(__first1, __last1, __first2, std::ref(__pred));
125+
__first1 = __result.first;
126+
__first2 = __result.second;
124127

125128
if (__first1 == __last1)
126129
return true;

0 commit comments

Comments
 (0)