Skip to content

Commit 9b2518e

Browse files
authored
perf: remove not_intersected_yet (#87)
1 parent ee7b084 commit 9b2518e

File tree

3 files changed

+50
-75
lines changed

3 files changed

+50
-75
lines changed

src/internal/incompatibility.rs

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -143,32 +143,6 @@ impl<P: Package, V: Version> Incompatibility<P, V> {
143143
}
144144
}
145145

146-
/// CF definition of Relation enum.
147-
pub fn relation(&self, mut terms: impl FnMut(&P) -> Option<Term<V>>) -> Relation<P> {
148-
let mut relation = Relation::Satisfied;
149-
for (package, incompat_term) in self.package_terms.iter() {
150-
match terms(package).map(|term| incompat_term.relation_with(&term)) {
151-
Some(term::Relation::Satisfied) => {}
152-
Some(term::Relation::Contradicted) => {
153-
return Relation::Contradicted(package.clone());
154-
}
155-
None | Some(term::Relation::Inconclusive) => {
156-
// If a package is not present, the intersection is the same as [Term::any].
157-
// According to the rules of satisfactions, the relation would be inconclusive.
158-
// It could also be satisfied if the incompatibility term was also [Term::any],
159-
// but we systematically remove those from incompatibilities
160-
// so we're safe on that front.
161-
if relation == Relation::Satisfied {
162-
relation = Relation::AlmostSatisfied(package.clone());
163-
} else {
164-
relation = Relation::Inconclusive;
165-
}
166-
}
167-
}
168-
}
169-
relation
170-
}
171-
172146
/// Check if an incompatibility should mark the end of the algorithm
173147
/// because it satisfies the root package.
174148
pub fn is_terminal(&self, root_package: &P, root_version: &V) -> bool {
@@ -246,6 +220,34 @@ impl<P: Package, V: Version> Incompatibility<P, V> {
246220
}
247221
}
248222

223+
impl<'a, P: Package, V: Version + 'a> Incompatibility<P, V> {
224+
/// CF definition of Relation enum.
225+
pub fn relation(&self, terms: impl Fn(&P) -> Option<&'a Term<V>>) -> Relation<P> {
226+
let mut relation = Relation::Satisfied;
227+
for (package, incompat_term) in self.package_terms.iter() {
228+
match terms(package).map(|term| incompat_term.relation_with(&term)) {
229+
Some(term::Relation::Satisfied) => {}
230+
Some(term::Relation::Contradicted) => {
231+
return Relation::Contradicted(package.clone());
232+
}
233+
None | Some(term::Relation::Inconclusive) => {
234+
// If a package is not present, the intersection is the same as [Term::any].
235+
// According to the rules of satisfactions, the relation would be inconclusive.
236+
// It could also be satisfied if the incompatibility term was also [Term::any],
237+
// but we systematically remove those from incompatibilities
238+
// so we're safe on that front.
239+
if relation == Relation::Satisfied {
240+
relation = Relation::AlmostSatisfied(package.clone());
241+
} else {
242+
relation = Relation::Inconclusive;
243+
}
244+
}
245+
}
246+
}
247+
relation
248+
}
249+
}
250+
249251
impl<P: Package, V: Version> fmt::Display for Incompatibility<P, V> {
250252
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
251253
write!(

src/internal/memory.rs

Lines changed: 15 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,7 @@ pub struct Memory<P: Package, V: Version> {
2626
#[derive(Clone)]
2727
enum PackageAssignments<V: Version> {
2828
Decision((V, Term<V>)),
29-
Derivations {
30-
intersected: Term<V>,
31-
not_intersected_yet: Vec<Term<V>>,
32-
},
29+
Derivations(Term<V>),
3330
}
3431

3532
impl<P: Package, V: Version> Memory<P, V> {
@@ -46,9 +43,9 @@ impl<P: Package, V: Version> Memory<P, V> {
4643
}
4744

4845
/// Retrieve intersection of terms in memory related to package.
49-
pub fn term_intersection_for_package(&mut self, package: &P) -> Option<&Term<V>> {
46+
pub fn term_intersection_for_package(&self, package: &P) -> Option<&Term<V>> {
5047
self.assignments
51-
.get_mut(package)
48+
.get(package)
5249
.map(|pa| pa.assignment_intersection())
5350
}
5451

@@ -93,18 +90,12 @@ impl<P: Package, V: Version> Memory<P, V> {
9390
Entry::Occupied(mut o) => match o.get_mut() {
9491
// Check that add_derivation is never called in the wrong context.
9592
PackageAssignments::Decision(_) => debug_assert!(false),
96-
PackageAssignments::Derivations {
97-
intersected: _,
98-
not_intersected_yet,
99-
} => {
100-
not_intersected_yet.push(term);
93+
PackageAssignments::Derivations(t) => {
94+
*t = t.intersection(&term);
10195
}
10296
},
10397
Entry::Vacant(v) => {
104-
v.insert(PackageAssignments::Derivations {
105-
intersected: term,
106-
not_intersected_yet: Vec::new(),
107-
});
98+
v.insert(PackageAssignments::Derivations(term));
10899
}
109100
}
110101
}
@@ -115,9 +106,9 @@ impl<P: Package, V: Version> Memory<P, V> {
115106
/// selected version (no "decision")
116107
/// and if it contains at least one positive derivation term
117108
/// in the partial solution.
118-
pub fn potential_packages(&mut self) -> impl Iterator<Item = (&P, &Range<V>)> {
109+
pub fn potential_packages(&self) -> impl Iterator<Item = (&P, &Range<V>)> {
119110
self.assignments
120-
.iter_mut()
111+
.iter()
121112
.filter_map(|(p, pa)| pa.potential_package_filter(p))
122113
}
123114

@@ -131,13 +122,8 @@ impl<P: Package, V: Version> Memory<P, V> {
131122
PackageAssignments::Decision((v, _)) => {
132123
solution.insert(p.clone(), v.clone());
133124
}
134-
PackageAssignments::Derivations {
135-
intersected,
136-
not_intersected_yet,
137-
} => {
138-
if intersected.is_positive()
139-
|| not_intersected_yet.iter().any(|t| t.is_positive())
140-
{
125+
PackageAssignments::Derivations(intersected) => {
126+
if intersected.is_positive() {
141127
return None;
142128
}
143129
}
@@ -149,20 +135,10 @@ impl<P: Package, V: Version> Memory<P, V> {
149135

150136
impl<V: Version> PackageAssignments<V> {
151137
/// Returns intersection of all assignments (decision included).
152-
/// Mutates itself to store the intersection result.
153-
fn assignment_intersection(&mut self) -> &Term<V> {
138+
fn assignment_intersection(&self) -> &Term<V> {
154139
match self {
155140
PackageAssignments::Decision((_, term)) => term,
156-
PackageAssignments::Derivations {
157-
intersected,
158-
not_intersected_yet,
159-
} => {
160-
for derivation in not_intersected_yet.iter() {
161-
*intersected = intersected.intersection(&derivation);
162-
}
163-
not_intersected_yet.clear();
164-
intersected
165-
}
141+
PackageAssignments::Derivations(term) => term,
166142
}
167143
}
168144

@@ -171,17 +147,13 @@ impl<V: Version> PackageAssignments<V> {
171147
/// and if it contains at least one positive derivation term
172148
/// in the partial solution.
173149
fn potential_package_filter<'a, P: Package>(
174-
&'a mut self,
150+
&'a self,
175151
package: &'a P,
176152
) -> Option<(&'a P, &'a Range<V>)> {
177153
match self {
178154
PackageAssignments::Decision(_) => None,
179-
PackageAssignments::Derivations {
180-
intersected,
181-
not_intersected_yet,
182-
} => {
183-
if intersected.is_positive() || not_intersected_yet.iter().any(|t| t.is_positive())
184-
{
155+
PackageAssignments::Derivations(intersected) => {
156+
if intersected.is_positive() {
185157
Some((package, self.assignment_intersection().unwrap_positive()))
186158
} else {
187159
None

src/internal/partial_solution.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ impl<P: Package, V: Version> PartialSolution<P, V> {
9696
}
9797

9898
/// Compute, cache and retrieve the intersection of all terms for this package.
99-
pub fn term_intersection_for_package(&mut self, package: &P) -> Option<&Term<V>> {
99+
pub fn term_intersection_for_package(&self, package: &P) -> Option<&Term<V>> {
100100
self.memory.term_intersection_for_package(package)
101101
}
102102

@@ -130,7 +130,7 @@ impl<P: Package, V: Version> PartialSolution<P, V> {
130130

131131
/// Extract potential packages for the next iteration of unit propagation.
132132
/// Return `None` if there is no suitable package anymore, which stops the algorithm.
133-
pub fn potential_packages(&mut self) -> Option<impl Iterator<Item = (&P, &Range<V>)>> {
133+
pub fn potential_packages(&self) -> Option<impl Iterator<Item = (&P, &Range<V>)>> {
134134
let mut iter = self.memory.potential_packages().peekable();
135135
if iter.peek().is_some() {
136136
Some(iter)
@@ -151,12 +151,13 @@ impl<P: Package, V: Version> PartialSolution<P, V> {
151151
new_incompatibilities: std::ops::Range<IncompId<P, V>>,
152152
store: &Arena<Incompatibility<P, V>>,
153153
) {
154+
let exact = &Term::exact(version.clone());
154155
let not_satisfied = |incompat: &Incompatibility<P, V>| {
155156
incompat.relation(|p| {
156157
if p == &package {
157-
Some(Term::exact(version.clone()))
158+
Some(exact)
158159
} else {
159-
self.memory.term_intersection_for_package(p).cloned()
160+
self.memory.term_intersection_for_package(p)
160161
}
161162
}) != Relation::Satisfied
162163
};
@@ -169,8 +170,8 @@ impl<P: Package, V: Version> PartialSolution<P, V> {
169170
}
170171

171172
/// Check if the terms in the partial solution satisfy the incompatibility.
172-
pub fn relation(&mut self, incompat: &Incompatibility<P, V>) -> Relation<P> {
173-
incompat.relation(|package| self.memory.term_intersection_for_package(package).cloned())
173+
pub fn relation(&self, incompat: &Incompatibility<P, V>) -> Relation<P> {
174+
incompat.relation(|package| self.memory.term_intersection_for_package(package))
174175
}
175176

176177
/// Find satisfier and previous satisfier decision level.

0 commit comments

Comments
 (0)