Skip to content

Commit 2cb789c

Browse files
committed
Remove unpredictable branch from kmerge::sift_down
1 parent 80cd4e9 commit 2cb789c

File tree

1 file changed

+11
-7
lines changed

1 file changed

+11
-7
lines changed

src/kmerge_impl.rs

+11-7
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,13 @@ fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
7474
debug_assert!(index <= heap.len());
7575
let mut pos = index;
7676
let mut child = 2 * pos + 1;
77-
// the `pos` conditional is to avoid a bounds check
78-
while pos < heap.len() && child < heap.len() {
79-
let right = child + 1;
80-
77+
// Require the right child to be present
78+
// This allows to find the index of the smallest child without a branch
79+
// that wouldn't be predicted if present
80+
while child + 1 < heap.len() {
8181
// pick the smaller of the two children
82-
if right < heap.len() && less_than(&heap[right], &heap[child]) {
83-
child = right;
84-
}
82+
// use aritmethic to avoid an unpredictable branch
83+
child += less_than(&heap[child+1], &heap[child]) as usize;
8584

8685
// sift down is done if we are already in order
8786
if !less_than(&heap[child], &heap[pos]) {
@@ -91,6 +90,11 @@ fn sift_down<T, S>(heap: &mut [T], index: usize, mut less_than: S)
9190
pos = child;
9291
child = 2 * pos + 1;
9392
}
93+
// Check if the last (left) child was an only child
94+
// if it is then it has to be compared with the parent
95+
if child + 1 == heap.len() && less_than(&heap[child], &heap[pos]) {
96+
heap.swap(pos, child);
97+
}
9498
}
9599

96100
/// An iterator adaptor that merges an abitrary number of base iterators in ascending order.

0 commit comments

Comments
 (0)