mirror of
https://github.com/rust-lang/rust.git
synced 2025-02-09 05:23:07 +00:00
Auto merge of #114231 - ttsugriy:binary_search_slice, r=cjgillot
[rustc_data_structures] Use partition_point to find slice range end. This PR uses approach introduced in https://github.com/rust-lang/rust/pull/114152 to find the end of the range. It's much easier to understand and reason about invariants of such implementation. Technically it's possible to make it even shorter by returning `&[start..end]` unconditionally because even if searched item is not present in the slice, `start` and `end` would point at the same index, so the range would be empty. The reason I decided not to use this shorter implementation is because it would involve more comparisons in case there are no elements in the slice with key equal to `key`. Also, not that it matters much, but this implementation also improves perf according to the benchmark below: https://gist.github.com/ttsugriy/63c0ed39ae132b131931fa1f8a3dea55 The results on my M1 macbook air are: ``` Running benches/bin_search_slice_benchmark.rs (target/release/deps/bin_search_slice_benchmark-90fa6d68c3bd1298) Benchmarking multiply add/binary_search_slice: Collecting 100 samples in estimated 5.0002 s (1 multiply add/binary_search_slice time: [44.719 ns 44.918 ns 45.158 ns] No change in performance detected. Found 3 outliers among 100 measurements (3.00%) 1 (1.00%) high mild 2 (2.00%) high severe Benchmarking multiply add/binary_search_slice_new: Collecting 100 samples in estimated 5.0001 multiply add/binary_search_slice_new time: [36.955 ns 37.060 ns 37.221 ns] No change in performance detected. Found 7 outliers among 100 measurements (7.00%) 3 (3.00%) high mild 4 (4.00%) high severe ```
This commit is contained in:
commit
25f8d01fd8
@ -18,27 +18,10 @@ where
|
||||
return &[];
|
||||
};
|
||||
|
||||
// Now search forward to find the *last* one.
|
||||
let mut end = start;
|
||||
let mut previous = start;
|
||||
let mut step = 1;
|
||||
loop {
|
||||
end = end.saturating_add(step).min(size);
|
||||
if end == size || key_fn(&data[end]) != *key {
|
||||
break;
|
||||
}
|
||||
previous = end;
|
||||
step *= 2;
|
||||
}
|
||||
step = end - previous;
|
||||
while step > 1 {
|
||||
let half = step / 2;
|
||||
let mid = end - half;
|
||||
if key_fn(&data[mid]) != *key {
|
||||
end = mid;
|
||||
}
|
||||
step -= half;
|
||||
}
|
||||
// Find the first entry with key > `key`. Skip `start` entries since
|
||||
// key_fn(&data[start]) == *key
|
||||
let offset = start + 1;
|
||||
let end = data[offset..].partition_point(|x| key_fn(x) <= *key) + offset;
|
||||
|
||||
&data[start..end]
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user