Skip to content

Commit 97adc7e

Browse files
committed
[libc++] Tiny optimizations for is_permutation
1 parent 3dc7991 commit 97adc7e

File tree

1 file changed

+23
-20
lines changed

1 file changed

+23
-20
lines changed

libcxx/include/__algorithm/is_permutation.h

Lines changed: 23 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,10 @@
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>
1720
#include <__iterator/concepts.h>
@@ -82,28 +85,29 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 bool __is_permutation_impl(
8285

8386
for (auto __i = __first1; __i != __last1; ++__i) {
8487
// 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-
}
88+
auto __match = std::find_if(__first1, __i, [&](const auto& __x) {
89+
return bool(std::__invoke(__pred, std::__invoke(__proj1, __x), std::__invoke(__proj1, *__i)));
90+
});
9091

9192
if (__match == __i) {
93+
auto __proj = std::__identity();
94+
9295
// 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-
}
96+
auto __predicate2 = [&](const auto& __x) {
97+
return bool(std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj2, __x)));
98+
};
99+
_D1 __c2 = std::__count_if<_AlgPolicy>(__first2, __last2, __predicate2, __proj);
100+
98101
if (__c2 == 0)
99102
return false;
100103

101-
// 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+
// Count number of *__i in [__i, l1)
105+
auto __predicate1 = [&](const auto& __x) {
106+
return bool(std::__invoke(__pred, std::__invoke(__proj1, *__i), std::__invoke(__proj1, __x)));
107+
};
108+
_D1 __c1 = std::__count_if<_AlgPolicy>(_IterOps<_AlgPolicy>::next(__i), __last1, __predicate1, __proj);
109+
++__c1; // Add 1 for *__i itself
110+
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, __pred);
125+
__first1 = __result.first;
126+
__first2 = __result.second;
124127

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

0 commit comments

Comments
 (0)