-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Optimize is_permutation for vector<bool>
#6148
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
base: main
Are you sure you want to change the base?
Changes from all commits
408cd46
90e156c
bf9ff31
549a9d3
5a0ba81
443e021
08b2657
4ca22be
21888e2
9aad0b0
b767508
3f5385f
d01fcda
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,83 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
|
|
||
| #include <benchmark/benchmark.h> | ||
| // | ||
| #include <algorithm> | ||
| #include <cstddef> | ||
| #include <random> | ||
| #include <vector> | ||
|
|
||
| #include "utility.hpp" | ||
|
|
||
| using namespace std; | ||
|
|
||
| enum class equality { eq, neq }; | ||
| enum class args { three, four }; | ||
|
|
||
|
|
||
| template <equality Eq, args Args> | ||
| void perm_arr_check(benchmark::State& state) { | ||
| const auto size = static_cast<size_t>(state.range(0)); | ||
| vector<bool> v1 = random_vector<bool>(size); | ||
| vector<bool> v2; | ||
| if constexpr (Eq == equality::eq) { | ||
| v2 = v1; | ||
| } else { | ||
| v2 = random_vector<bool>(size, 1u); | ||
| } | ||
|
|
||
| auto a1 = make_unique<bool[]>(size); | ||
| auto a2 = make_unique<bool[]>(size); | ||
| copy(v1.begin(), v1.end(), a1.get()); | ||
| copy(v2.begin(), v2.end(), a2.get()); | ||
|
|
||
| for (auto _ : state) { | ||
| benchmark::DoNotOptimize(a1.get()); | ||
| benchmark::DoNotOptimize(a2.get()); | ||
| bool r; | ||
| if constexpr (Args == args::three) { | ||
| r = is_permutation(a1.get(), a1.get() + size, a2.get()); | ||
| } else { | ||
| r = is_permutation(a1.get(), a1.get() + size, a2.get(), a2.get() + size); | ||
| } | ||
| benchmark::DoNotOptimize(r); | ||
| } | ||
| } | ||
|
|
||
|
|
||
| template <equality Eq, args Args> | ||
| void perm_vbool_check(benchmark::State& state) { | ||
| const auto size = static_cast<size_t>(state.range(0)); | ||
| vector<bool> v1 = random_vector<bool>(size); | ||
| vector<bool> v2; | ||
| if constexpr (Eq == equality::eq) { | ||
| v2 = v1; | ||
| } else { | ||
| v2 = random_vector<bool>(size, 1u); | ||
| } | ||
|
|
||
| for (auto _ : state) { | ||
| benchmark::DoNotOptimize(v1); | ||
| benchmark::DoNotOptimize(v2); | ||
| bool r; | ||
| if constexpr (Args == args::three) { | ||
| r = is_permutation(v1.begin(), v1.end(), v2.begin()); | ||
| } else { | ||
| r = is_permutation(v1.begin(), v1.end(), v2.begin(), v2.end()); | ||
| } | ||
| benchmark::DoNotOptimize(r); | ||
| } | ||
| } | ||
|
|
||
| BENCHMARK(perm_arr_check<equality::eq, args::three>)->RangeMultiplier(64)->Range(64, 64 << 10); | ||
| BENCHMARK(perm_arr_check<equality::eq, args::four>)->RangeMultiplier(64)->Range(64, 64 << 10); | ||
| BENCHMARK(perm_arr_check<equality::neq, args::three>)->RangeMultiplier(64)->Range(64, 64 << 10); | ||
| BENCHMARK(perm_arr_check<equality::neq, args::four>)->RangeMultiplier(64)->Range(64, 64 << 10); | ||
|
|
||
| BENCHMARK(perm_vbool_check<equality::eq, args::three>)->RangeMultiplier(64)->Range(64, 64 << 10); | ||
| BENCHMARK(perm_vbool_check<equality::eq, args::four>)->RangeMultiplier(64)->Range(64, 64 << 10); | ||
| BENCHMARK(perm_vbool_check<equality::neq, args::three>)->RangeMultiplier(64)->Range(64, 64 << 10); | ||
| BENCHMARK(perm_vbool_check<equality::neq, args::four>)->RangeMultiplier(64)->Range(64, 64 << 10); | ||
|
|
||
| BENCHMARK_MAIN(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1270,6 +1270,21 @@ namespace ranges { | |
| } // namespace ranges | ||
| #endif // _HAS_CXX20 | ||
|
|
||
| template <class _FwdIt1, class _FwdIt2> | ||
| _NODISCARD _CONSTEXPR20 bool _Is_permutation_of_bool(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _FwdIt2 _Last2) { | ||
| if constexpr (!_Is_vb_iterator<_FwdIt1> && !_Is_vb_iterator<_FwdIt2>) { | ||
| auto _Pair = _STD mismatch(_First1, _Last1, _First2); | ||
|
Comment on lines
+1275
to
+1276
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. No. This is intentional optimization decision. It is explained in the PR description.
|
||
| _First1 = _STD move(_Pair.first); | ||
| _First2 = _STD move(_Pair.second); | ||
|
|
||
| if (_First1 == _Last1) { | ||
| return true; | ||
| } | ||
| } | ||
|
|
||
| return _STD count(_First1, _Last1, true) == _STD count(_First2, _Last2, true); | ||
| } | ||
|
|
||
| _EXPORT_STD template <class _FwdIt1, class _FwdIt2, class _Pr> | ||
| _NODISCARD _CONSTEXPR20 bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _FwdIt2 _First2, _Pr _Pred) { | ||
| // test if [_First1, _Last1) == permuted [_First2, ...) | ||
|
|
@@ -1278,6 +1293,18 @@ _NODISCARD _CONSTEXPR20 bool is_permutation(_FwdIt1 _First1, _FwdIt1 _Last1, _Fw | |
| const auto _ULast1 = _STD _Get_unwrapped(_Last1); | ||
| auto _UFirst2 = _STD _Get_unwrapped_n(_First2, _STD _Idl_distance<_FwdIt1>(_UFirst1, _ULast1)); | ||
|
|
||
| if constexpr (is_same_v<_Iter_value_t<decltype(_UFirst1)>, bool> | ||
| && is_same_v<_Iter_value_t<decltype(_UFirst2)>, bool> // | ||
| && _Is_ranges_random_iter_v<decltype(_UFirst1)> // | ||
| && _Is_ranges_random_iter_v<decltype(_UFirst2)> | ||
|
Comment on lines
+1296
to
+1299
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The 4-arg version checks the wrapped iterator instead. The check it pre-existing.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Checking the unwrapped iterators. |
||
| && _Is_any_of_v<_Pr, | ||
| #if _HAS_CXX20 | ||
| _RANGES equal_to, | ||
| #endif | ||
| equal_to<>, equal_to<bool>>) { | ||
| return _STD _Is_permutation_of_bool(_UFirst1, _ULast1, _UFirst2, _UFirst2 + (_ULast1 - _UFirst1)); | ||
| } | ||
|
|
||
| for (;; ++_UFirst1, (void) ++_UFirst2) { // trim matching prefix | ||
| if (_UFirst1 == _ULast1) { // everything matched | ||
| return true; | ||
|
|
@@ -1310,11 +1337,21 @@ _NODISCARD _CONSTEXPR20 bool is_permutation( | |
| auto _ULast1 = _STD _Get_unwrapped(_Last1); | ||
| auto _UFirst2 = _STD _Get_unwrapped(_First2); | ||
| auto _ULast2 = _STD _Get_unwrapped(_Last2); | ||
| if constexpr (_Is_ranges_random_iter_v<_FwdIt1> && _Is_ranges_random_iter_v<_FwdIt2>) { | ||
| if constexpr (_Is_ranges_random_iter_v<decltype(_UFirst1)> && _Is_ranges_random_iter_v<decltype(_UFirst2)>) { | ||
| if (_ULast1 - _UFirst1 != _ULast2 - _UFirst2) { | ||
| return false; | ||
| } | ||
|
|
||
| if constexpr (is_same_v<_Iter_value_t<decltype(_UFirst1)>, bool> | ||
| && is_same_v<_Iter_value_t<decltype(_UFirst2)>, bool> | ||
| && _Is_any_of_v<_Pr, | ||
| #if _HAS_CXX20 | ||
| _RANGES equal_to, | ||
| #endif | ||
| equal_to<>, equal_to<bool>>) { | ||
| return _STD _Is_permutation_of_bool(_UFirst1, _ULast1, _UFirst2, _ULast2); | ||
| } | ||
|
|
||
| for (; _UFirst1 != _ULast1; ++_UFirst1, (void) ++_UFirst2) { // trim matching prefix | ||
| if (!_Pred(*_UFirst1, *_UFirst2)) { | ||
| // found first inequality, check match counts in suffix | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
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.
I think this one is premature. I don't attempt to handle
std::ranges::is_permutationyet, so there's no distinct sentinel type. When we handle it, we'll see how it should be done.