Skip to content

Commit 25f8d01

Browse files
committed
Auto merge of rust-lang#114231 - ttsugriy:binary_search_slice, r=cjgillot
[rustc_data_structures] Use partition_point to find slice range end. This PR uses approach introduced in rust-lang#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 ```
2 parents 8424f8e + 97bc528 commit 25f8d01

File tree

1 file changed

+4
-21
lines changed
  • compiler/rustc_data_structures/src/binary_search_util

1 file changed

+4
-21
lines changed

compiler/rustc_data_structures/src/binary_search_util/mod.rs

+4-21
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,10 @@ where
1818
return &[];
1919
};
2020

21-
// Now search forward to find the *last* one.
22-
let mut end = start;
23-
let mut previous = start;
24-
let mut step = 1;
25-
loop {
26-
end = end.saturating_add(step).min(size);
27-
if end == size || key_fn(&data[end]) != *key {
28-
break;
29-
}
30-
previous = end;
31-
step *= 2;
32-
}
33-
step = end - previous;
34-
while step > 1 {
35-
let half = step / 2;
36-
let mid = end - half;
37-
if key_fn(&data[mid]) != *key {
38-
end = mid;
39-
}
40-
step -= half;
41-
}
21+
// Find the first entry with key > `key`. Skip `start` entries since
22+
// key_fn(&data[start]) == *key
23+
let offset = start + 1;
24+
let end = data[offset..].partition_point(|x| key_fn(x) <= *key) + offset;
4225

4326
&data[start..end]
4427
}

0 commit comments

Comments
 (0)