[libc++] "Bottom-up heapsort" improvement to sort_heap. https://en.wikipedia.org/wiki/Heapsort#Bottom-up_heapsort In `pop_heap` specifically, the item we insert at the top and sift downward is guaranteed to be leaf-sized, so we expect it to go pretty far down. Sift it down as if it were INT_MIN, and then bubble it back up if needed. Also known as "heapsort with bounce." Numbers are here: https://godbolt.org/z/cvfnYW6fe Fixes #10008. Differential Revision: https://reviews.llvm.org/D118003
Fixes https://github.com/llvm/llvm-project/issues/10008
As the issue description says:
[__sift_down] is normally used to put in the correct position an element that was previously a leaf of a heap
(as in the pop_heap implementation). [When] that element was a leaf, it is likely that it will move down when
placed in the root.An optimization is to move down the empty space at the root by swapping it with the largest child.
When the empty space becomes a leaf, the last element is moved to its place and moved up if necessary.The advantage is that only one comparison per step is needed to move the empty space down.
A demo is here: https://godbolt.org/z/M8do8sWhT
For the same 100,000 random elements made into a heap using make_heap:
libstdc++ sort_heap takes 1,934,727 moves; 1,534,715 comparisons.
libc++ trunk sort_heap takes 1,900,731 moves; 2,831,757 comparisons.
libc++ after this patch takes 1,764,997 moves; 1,534,701 comparisons.
(Note that this really is apples to apples: hashing proves that libstdc++'s make_heap produces the exact same 100,000-element sequence as libc++'s make_heap.)