Skip to content

Instantly share code, notes, and snippets.

@ttsugriy
Created July 28, 2023 04:14
Show Gist options
  • Save ttsugriy/757030eb2249f17e062159249e7eafa7 to your computer and use it in GitHub Desktop.
Save ttsugriy/757030eb2249f17e062159249e7eafa7 to your computer and use it in GitHub Desktop.
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 d40172a2e2f..c6e3354025a 100644
--- a/compiler/rustc_data_structures/src/binary_search_util/mod.rs
+++ b/compiler/rustc_data_structures/src/binary_search_util/mod.rs
@@ -10,59 +10,22 @@ pub fn binary_search_slice<'d, E, K>(data: &'d [E], key_fn: impl Fn(&E) -> K, ke
where
K: Ord,
{
- let Ok(mid) = data.binary_search_by_key(key, &key_fn) else {
+ let size = data.len();
+ let start = data.partition_point(|x| key_fn(x) < *key);
+ // at this point start either points at the first entry with equal key
+ // or is equal to size in case all elements have smaller keys
+ // invariant: start == size || key_fn(&data[start]) >= *key
+ if start == size || key_fn(&data[start]) != *key {
return &[];
};
- let size = data.len();
-
- // We get back *some* element with the given key -- so do
- // a galloping search backwards to find the *first* one.
- let mut start = mid;
- let mut previous = mid;
- let mut step = 1;
- loop {
- start = start.saturating_sub(step);
- if start == 0 || key_fn(&data[start]) != *key {
- break;
- }
- previous = start;
- step *= 2;
- }
- step = previous - start;
- while step > 1 {
- let half = step / 2;
- let mid = start + half;
- if key_fn(&data[mid]) != *key {
- start = mid;
- }
- step -= half;
- }
- // adjust by one if we have overshot
- if start < size && key_fn(&data[start]) != *key {
- start += 1;
- }
+ // invariant: start < size && key_fn(&data[start]) == *key
- // Now search forward to find the *last* one.
- let mut end = mid;
- let mut previous = mid;
- 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
+ // invariant: offset == size || key_fn(&data[offset]) >= *key
+ let offset = start + 1;
+ let end = data[offset..].partition_point(|x| key_fn(x) <= *key) + offset;
+ // invariant: end == size || key_fn(&data[end]) > *key
&data[start..end]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment