diff options
| author | bors <bors@rust-lang.org> | 2024-01-18 18:54:54 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2024-01-18 18:54:54 +0000 |
| commit | 25f8d01fd8bda339612d0c0a8844173a09205f7c (patch) | |
| tree | 168ed76d3740138f6680caedd0ffb4d0bbea4a72 | |
| parent | 8424f8e8cdf07010967a57584fd647b30e930d4d (diff) | |
| parent | 97bc528877b698df2f61dd743b1a155ca3f5eead (diff) | |
| download | rust-25f8d01fd8bda339612d0c0a8844173a09205f7c.tar.gz rust-25f8d01fd8bda339612d0c0a8844173a09205f7c.zip | |
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
```
| -rw-r--r-- | compiler/rustc_data_structures/src/binary_search_util/mod.rs | 25 |
1 files changed, 4 insertions, 21 deletions
diff --git a/compiler/rustc_data_structures/src/binary_search_util/mod.rs b/compiler/rustc_data_structures/src/binary_search_util/mod.rs index bc8a6b9eac0..1c6e227cec4 100644 --- a/compiler/rustc_data_structures/src/binary_search_util/mod.rs +++ b/compiler/rustc_data_structures/src/binary_search_util/mod.rs @@ -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] } |
