mirror of
https://github.com/Noratrieb/cargo-minimize.git
synced 2026-01-14 16:35:01 +01:00
Minor optimization for now-overlapping paths
Naively, if we have items (1) foo, (2) foo::bar, (3) foo::baz, we would try to first try to remove all three of them, and then if that fails, try to remove just (1) and (2) ..except we should already know that that would fail since it still includes (1) which covers all three items anyway. So, try to be smarter about this and not do that. This is achieved by avoiding ever putting both foo and foo::whatever in the same try-set, as that gives no information on foo::whatever regardless of if the check passes or fails
This commit is contained in:
parent
2f9a0d45a1
commit
46c26f7af9
1 changed files with 41 additions and 4 deletions
|
|
@ -174,15 +174,22 @@ impl PassController {
|
||||||
if candidates.is_empty() {
|
if candidates.is_empty() {
|
||||||
self.state = PassControllerState::Success;
|
self.state = PassControllerState::Success;
|
||||||
} else {
|
} else {
|
||||||
let current = mem::take(candidates)
|
// We could just set `current=candidates; worklist=default()`,
|
||||||
.into_iter()
|
// but we are doing a minor optimization to split overlapping items into separate tries,
|
||||||
.collect::<BTreeSet<AstPath>>();
|
// so as to reduce the number of bisection steps that yield literally no new info.
|
||||||
|
let layers = layer_candidates(mem::take(candidates));
|
||||||
|
let mut worklist = Worklist::new();
|
||||||
|
for layer in layers.into_iter().rev() {
|
||||||
|
// .rev() so that we add shorter paths last, and process them first
|
||||||
|
worklist.push(layer);
|
||||||
|
}
|
||||||
|
let current = worklist.pop().unwrap().into_iter().collect();
|
||||||
|
|
||||||
self.state = PassControllerState::Bisecting {
|
self.state = PassControllerState::Bisecting {
|
||||||
committed: BTreeSet::new(),
|
committed: BTreeSet::new(),
|
||||||
failed: BTreeSet::new(),
|
failed: BTreeSet::new(),
|
||||||
current,
|
current,
|
||||||
worklist: Worklist::new(),
|
worklist,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -261,3 +268,33 @@ fn split_owned<T, From: IntoIterator<Item = T>, A: FromIterator<T>, B: FromItera
|
||||||
|
|
||||||
(first_half, second_half)
|
(first_half, second_half)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Split up a list of AstPath's into several sets such that none of those sets have
|
||||||
|
/// any of the AstPath's overlap.
|
||||||
|
/// I.e. so that we avoid having both ["foo"] and ["foo", "bar"] in the same set.
|
||||||
|
/// It is expected, but not guaranteed that the earlier sets would contain "less granular" items
|
||||||
|
/// (i.e. ["foo"] from the above example) and the latter sets would contain the "more granular" ones.
|
||||||
|
fn layer_candidates(mut candidates: Vec<AstPath>) -> Vec<Vec<AstPath>> {
|
||||||
|
candidates.sort(); // this *should* put less-granular/shorter-path items first
|
||||||
|
let mut layers: Vec<Vec<AstPath>> = vec![];
|
||||||
|
for candidate in candidates {
|
||||||
|
let mut appropriate_layer_no = None;
|
||||||
|
for (no, layer) in layers.iter().enumerate() {
|
||||||
|
if !layer
|
||||||
|
.iter()
|
||||||
|
.any(|known_path| candidate.has_prefix(known_path))
|
||||||
|
{
|
||||||
|
appropriate_layer_no = Some(no);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
match appropriate_layer_no {
|
||||||
|
Some(no) => layers[no].push(candidate),
|
||||||
|
None => {
|
||||||
|
let new_layer = vec![candidate];
|
||||||
|
layers.push(new_layer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layers
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue