Skip to content
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

<algorithm>: ranges::minmax should dereference iterators only once #3366

Merged
merged 17 commits into from
Feb 3, 2023

Conversation

fsb4000
Copy link
Contributor

@fsb4000 fsb4000 commented Jan 27, 2023

Fixes #2900

After #2958 the original repro works, but the issue still exists.

I also found that if we have only one element we also have the issue.

@fsb4000 fsb4000 requested a review from a team as a code owner January 27, 2023 16:52
@fsb4000 fsb4000 changed the title fix ranges::minmax <algorithm>: ranges::minmax should dereference iterators only once Jan 27, 2023
stl/inc/algorithm Outdated Show resolved Hide resolved
stl/inc/algorithm Outdated Show resolved Hide resolved
@StephanTLavavej StephanTLavavej added bug Something isn't working ranges C++20/23 ranges labels Jan 28, 2023
stl/inc/algorithm Outdated Show resolved Hide resolved
Co-authored-by: Alex Guteniev <[email protected]>
Co-authored-by: timsong-cpp <[email protected]>
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
stl/inc/algorithm Outdated Show resolved Hide resolved
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
@StephanTLavavej

This comment was marked as resolved.

tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
@fsb4000 fsb4000 requested a review from strega-nil-ms February 1, 2023 05:05
@StephanTLavavej
Copy link
Member

This new pattern is unusual, but I rate it only 2 squirrels out of 5. (The Standard has an example, WG21-N4928 [dcl.init.aggr]/6, where a default member initializer refers to previous members, that's at least 3 squirrels.) I probably would have commented it, but I don't think it's worth resetting testing again. It does seem to be an improvement compared to the previous version, thanks!

@fsb4000
Copy link
Contributor Author

fsb4000 commented Feb 1, 2023

It does seem to be an improvement compared to the previous version, thanks!

Good, I found it there:
https://github.com/llvm/llvm-project/blob/c4e38fadfa2a615467a8c9071f12edc4cdce5eb8/libcxx/include/__algorithm/ranges_minmax.h#L89

libc++ also has the bug, I created: https://reviews.llvm.org/D142864

@StephanTLavavej StephanTLavavej dismissed strega-nil-ms’s stale review February 1, 2023 23:40

Approved by Mirror Universe Nicole

@StephanTLavavej StephanTLavavej self-assigned this Feb 2, 2023
@StephanTLavavej
Copy link
Member

I'm mirroring this to the MSVC-internal repo - please notify me if any further changes are pushed.

stl/inc/algorithm Outdated Show resolved Hide resolved
stl/inc/algorithm Outdated Show resolved Hide resolved
stl/inc/algorithm Outdated Show resolved Hide resolved
tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
Co-authored-by: Casey Carter <[email protected]>
@fsb4000 fsb4000 requested review from StephanTLavavej and CaseyCarter and removed request for strega-nil-ms and StephanTLavavej February 2, 2023 14:53
@fsb4000
Copy link
Contributor Author

fsb4000 commented Feb 2, 2023

@StephanTLavavej
I pushed some changes after Casey's code review

stl/inc/algorithm Outdated Show resolved Hide resolved
@CaseyCarter
Copy link
Member

@StephanTLavavej I pushed some changes after Casey's code review

As did I.

tests/std/tests/P0896R4_ranges_alg_minmax/test.cpp Outdated Show resolved Hide resolved
stl/inc/algorithm Outdated Show resolved Hide resolved
stl/inc/algorithm Outdated Show resolved Hide resolved
@StephanTLavavej
Copy link
Member

Everyone's joining the commit party! (I pushed tiny comment changes and removed parameter names for the defaulted function.)

@StephanTLavavej StephanTLavavej merged commit 0150312 into microsoft:main Feb 3, 2023
@StephanTLavavej
Copy link
Member

Thanks for minimizing bugs while maximizing performance! 📉 😸 📈

CaseyCarter added a commit to CaseyCarter/STL that referenced this pull request Feb 3, 2023
The fix for microsoft#2900 in microsoft#3366 did not take advantage of the fact that the minimum and maximum elements of a range are always distinct except when the range has only one element. It couldn't easily do so due to the way `ranges::minmax` and `ranges::minmax_element` share the common backend `ranges::_Minmax_element_unchecked`.

This PR introduces a new backend for `ranges::minmax` (`ranges::_Minmax_fn::_Minmax_fwd_unchecked`) and makes `ranges::_Minmax_element_unchecked` the private member `ranges::_Minmax_element_fn::_Minmax_element_fwd_unchecked`. Since the two are distinct, `_Minmax_fwd_unchecked` can deal in values instead of iterators, and we can unroll the first loop iteration to detect the single-element case naturally. Since no additional branch is needed, we can enable the fix for microsoft#2900 unconditionally.

This refactoring is also probably a minor throughput and perf improvement, since `minmax` no longer needs to instantiate the "old" backend's return type and the new backend is tail-called.

Drive-by: Fully qualify the names of ugly functions called by `ranges::minmax` and `ranges::minmax_element`.
CaseyCarter added a commit to CaseyCarter/STL that referenced this pull request Feb 3, 2023
The fix for microsoft#2900 in microsoft#3366 did not take advantage of the fact that the minimum and maximum elements of a range are always distinct except when the range has only one element. It couldn't easily do so due to the way `ranges::minmax` and `ranges::minmax_element` share the common backend `ranges::_Minmax_element_unchecked`.

This PR introduces a new backend for `ranges::minmax` (`ranges::_Minmax_fn::_Minmax_fwd_unchecked`) and makes `ranges::_Minmax_element_unchecked` the private member `ranges::_Minmax_element_fn::_Minmax_element_fwd_unchecked`. Since the two are distinct, `_Minmax_fwd_unchecked` can deal in values instead of iterators, and we can unroll the first loop iteration to detect the single-element case naturally. Since no additional branch is needed, we can enable the fix for microsoft#2900 unconditionally.

Drive-by: Fully qualify the names of ugly functions called by `ranges::minmax` and `ranges::minmax_element`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working ranges C++20/23 ranges
Projects
None yet
Development

Successfully merging this pull request may close these issues.

<algorithm>: ranges::minmax initializes minmax_result with the moved value
7 participants