mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-01 23:12:02 +00:00
Improve slice.binary_search_by()'s best-case performance to O(1)
This commit is contained in:
parent
0248c6f178
commit
18e44a1be4
@ -7,15 +7,21 @@ enum Cache {
|
||||
L3,
|
||||
}
|
||||
|
||||
impl Cache {
|
||||
fn size(&self) -> usize {
|
||||
match self {
|
||||
Cache::L1 => 1000, // 8kb
|
||||
Cache::L2 => 10_000, // 80kb
|
||||
Cache::L3 => 1_000_000, // 8Mb
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn binary_search<F>(b: &mut Bencher, cache: Cache, mapper: F)
|
||||
where
|
||||
F: Fn(usize) -> usize,
|
||||
{
|
||||
let size = match cache {
|
||||
Cache::L1 => 1000, // 8kb
|
||||
Cache::L2 => 10_000, // 80kb
|
||||
Cache::L3 => 1_000_000, // 8Mb
|
||||
};
|
||||
let size = cache.size();
|
||||
let v = (0..size).map(&mapper).collect::<Vec<_>>();
|
||||
let mut r = 0usize;
|
||||
b.iter(move || {
|
||||
@ -24,7 +30,18 @@ where
|
||||
// Lookup the whole range to get 50% hits and 50% misses.
|
||||
let i = mapper(r % size);
|
||||
black_box(v.binary_search(&i).is_ok());
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
fn binary_search_worst_case(b: &mut Bencher, cache: Cache) {
|
||||
let size = cache.size();
|
||||
|
||||
let mut v = vec![0; size];
|
||||
let i = 1;
|
||||
v[size - 1] = i;
|
||||
b.iter(move || {
|
||||
black_box(v.binary_search(&i).is_ok());
|
||||
});
|
||||
}
|
||||
|
||||
#[bench]
|
||||
@ -57,6 +74,21 @@ fn binary_search_l3_with_dups(b: &mut Bencher) {
|
||||
binary_search(b, Cache::L3, |i| i / 16 * 16);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn binary_search_l1_worst_case(b: &mut Bencher) {
|
||||
binary_search_worst_case(b, Cache::L1);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn binary_search_l2_worst_case(b: &mut Bencher) {
|
||||
binary_search_worst_case(b, Cache::L2);
|
||||
}
|
||||
|
||||
#[bench]
|
||||
fn binary_search_l3_worst_case(b: &mut Bencher) {
|
||||
binary_search_worst_case(b, Cache::L3);
|
||||
}
|
||||
|
||||
macro_rules! rotate {
|
||||
($fn:ident, $n:expr, $mapper:expr) => {
|
||||
#[bench]
|
||||
|
@ -2167,7 +2167,11 @@ impl<T> [T] {
|
||||
// - `mid >= 0`: by definition
|
||||
// - `mid < size`: `mid = size / 2 + size / 4 + size / 8 ...`
|
||||
let cmp = f(unsafe { s.get_unchecked(mid) });
|
||||
base = if cmp == Greater { base } else { mid };
|
||||
if cmp == Equal {
|
||||
return Ok(mid);
|
||||
} else if cmp == Less {
|
||||
base = mid
|
||||
}
|
||||
size -= half;
|
||||
}
|
||||
// SAFETY: base is always in [0, size) because base <= mid.
|
||||
|
@ -73,13 +73,13 @@ fn test_binary_search_implementation_details() {
|
||||
let b = [1, 1, 2, 2, 3, 3, 3];
|
||||
assert_eq!(b.binary_search(&1), Ok(1));
|
||||
assert_eq!(b.binary_search(&2), Ok(3));
|
||||
assert_eq!(b.binary_search(&3), Ok(6));
|
||||
assert_eq!(b.binary_search(&3), Ok(5));
|
||||
let b = [1, 1, 1, 1, 1, 3, 3, 3, 3];
|
||||
assert_eq!(b.binary_search(&1), Ok(4));
|
||||
assert_eq!(b.binary_search(&3), Ok(8));
|
||||
assert_eq!(b.binary_search(&3), Ok(6));
|
||||
let b = [1, 1, 1, 1, 3, 3, 3, 3, 3];
|
||||
assert_eq!(b.binary_search(&1), Ok(3));
|
||||
assert_eq!(b.binary_search(&3), Ok(8));
|
||||
assert_eq!(b.binary_search(&1), Ok(2));
|
||||
assert_eq!(b.binary_search(&3), Ok(4));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
Loading…
Reference in New Issue
Block a user