Skip to content

Commit 0942d13

Browse files
committed
Reduce AssignmentsIntersection size
1 parent 51a9e62 commit 0942d13

File tree

2 files changed

+101
-94
lines changed

2 files changed

+101
-94
lines changed

src/internal/partial_solution.rs

Lines changed: 100 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -133,19 +133,41 @@ impl<M: Clone + Debug + Display> Display for DatedDerivation<M> {
133133
}
134134
}
135135

136-
#[derive(Clone, Debug)]
137-
enum AssignmentsIntersection {
138-
Decision((u32, Version, Term)),
139-
Derivations(Term),
136+
#[derive(Clone, Debug, Default)]
137+
struct AssignmentsIntersection {
138+
term: Term,
139+
is_decision: bool,
140+
decision_global_index: u32,
141+
decision_version: Version,
142+
}
143+
144+
impl AssignmentsIntersection {
145+
fn decision(global_index: u32, version: Version) -> Self {
146+
Self {
147+
term: Term::exact(version),
148+
is_decision: true,
149+
decision_global_index: global_index,
150+
decision_version: version,
151+
}
152+
}
153+
154+
fn derivations(term: Term) -> Self {
155+
Self {
156+
term,
157+
..Default::default()
158+
}
159+
}
140160
}
141161

142162
impl Display for AssignmentsIntersection {
143163
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
144-
match self {
145-
Self::Decision((lvl, version, _)) => {
146-
write!(f, "Decision: level {}, v = {}", lvl, version.get())
147-
}
148-
Self::Derivations(term) => write!(f, "Derivations term: {}", term),
164+
if self.is_decision {
165+
let lvl = self.decision_global_index;
166+
let version = self.decision_version.get();
167+
write!(f, "Decision: level {lvl}, v = {version}")
168+
} else {
169+
let term = self.term;
170+
write!(f, "Derivations term: {term}")
149171
}
150172
}
151173
}
@@ -192,25 +214,26 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
192214
pub(crate) fn add_decision(&mut self, package: Package, version: Version) {
193215
// Check that add_decision is never used in the wrong context.
194216
if cfg!(debug_assertions) {
195-
match self.package_assignments.get_mut(&package) {
196-
None => panic!("Derivations must already exist"),
197-
Some(pa) => match &pa.assignments_intersection {
198-
// Cannot be called when a decision has already been taken.
199-
AssignmentsIntersection::Decision(_) => panic!("Already existing decision"),
200-
// Cannot be called if the versions is not contained in the terms' intersection.
201-
AssignmentsIntersection::Derivations(term) => {
202-
debug_assert!(
203-
term.contains(version),
204-
"{} was expected to be contained in {}",
205-
version.get(),
206-
term,
207-
)
208-
}
209-
},
210-
}
217+
let pa = self
218+
.package_assignments
219+
.get_mut(&package)
220+
.expect("Derivations must already exist");
221+
// Cannot be called when a decision has already been taken.
222+
assert!(
223+
!pa.assignments_intersection.is_decision,
224+
"Already existing decision",
225+
);
226+
// Cannot be called if the versions is not contained in the terms' intersection.
227+
let term = pa.assignments_intersection.term;
228+
assert!(
229+
term.contains(version),
230+
"{} was expected to be contained in {}",
231+
version.get(),
232+
term,
233+
);
211234
assert_eq!(
212235
self.changed_this_decision_level,
213-
self.package_assignments.len()
236+
self.package_assignments.len(),
214237
);
215238
}
216239
let new_idx = self.current_decision_level.0 as usize;
@@ -220,11 +243,8 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
220243
.get_full_mut(&package)
221244
.expect("Derivations must already exist");
222245
pa.highest_decision_level = self.current_decision_level;
223-
pa.assignments_intersection = AssignmentsIntersection::Decision((
224-
self.next_global_index,
225-
version,
226-
Term::exact(version),
227-
));
246+
pa.assignments_intersection =
247+
AssignmentsIntersection::decision(self.next_global_index, version);
228248
// Maintain that the beginning of the `package_assignments` Have all decisions in sorted order.
229249
if new_idx != old_idx {
230250
self.package_assignments.swap_indices(new_idx, old_idx);
@@ -253,21 +273,19 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
253273
let idx = occupied.index();
254274
let pa = occupied.get_mut();
255275
pa.highest_decision_level = self.current_decision_level;
256-
match &mut pa.assignments_intersection {
257-
// Check that add_derivation is never called in the wrong context.
258-
AssignmentsIntersection::Decision(_) => {
259-
panic!("add_derivation should not be called after a decision")
260-
}
261-
AssignmentsIntersection::Derivations(t) => {
262-
*t = t.intersection(dated_derivation.accumulated_intersection);
263-
dated_derivation.accumulated_intersection = *t;
264-
if t.is_positive() {
265-
// we can use `swap_indices` to make `changed_this_decision_level` only go down by 1
266-
// but the copying is slower then the larger search
267-
self.changed_this_decision_level =
268-
std::cmp::min(self.changed_this_decision_level, idx);
269-
}
270-
}
276+
// Check that add_derivation is never called in the wrong context.
277+
assert!(
278+
!pa.assignments_intersection.is_decision,
279+
"add_derivation should not be called after a decision",
280+
);
281+
let t = &mut pa.assignments_intersection.term;
282+
*t = t.intersection(dated_derivation.accumulated_intersection);
283+
dated_derivation.accumulated_intersection = *t;
284+
if t.is_positive() {
285+
// we can use `swap_indices` to make `changed_this_decision_level` only go down by 1
286+
// but the copying is slower then the larger search
287+
self.changed_this_decision_level =
288+
std::cmp::min(self.changed_this_decision_level, idx);
271289
}
272290
pa.dated_derivations.push(dated_derivation);
273291
}
@@ -281,7 +299,7 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
281299
smallest_decision_level: self.current_decision_level,
282300
highest_decision_level: self.current_decision_level,
283301
dated_derivations: SmallVec::One([dated_derivation]),
284-
assignments_intersection: AssignmentsIntersection::Derivations(term),
302+
assignments_intersection: AssignmentsIntersection::derivations(term),
285303
});
286304
}
287305
}
@@ -325,13 +343,13 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
325343
self.package_assignments
326344
.iter()
327345
.take(self.current_decision_level.0 as usize)
328-
.map(|(&p, pa)| match pa.assignments_intersection {
329-
AssignmentsIntersection::Decision((_, v, _)) => {
330-
(package_store.pkg(p).unwrap().clone(), v)
331-
}
332-
AssignmentsIntersection::Derivations(_) => {
333-
panic!("Derivations in the Decision part")
334-
}
346+
.map(|(&p, pa)| {
347+
assert!(
348+
pa.assignments_intersection.is_decision,
349+
"Derivations in the Decision part",
350+
);
351+
let v = pa.assignments_intersection.decision_version;
352+
(package_store.pkg(p).unwrap().clone(), v)
335353
})
336354
.collect()
337355
}
@@ -368,7 +386,7 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
368386

369387
// Reset the assignments intersection.
370388
pa.assignments_intersection =
371-
AssignmentsIntersection::Derivations(last.accumulated_intersection);
389+
AssignmentsIntersection::derivations(last.accumulated_intersection);
372390
true
373391
}
374392
});
@@ -452,7 +470,7 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
452470
pub(crate) fn term_intersection_for_package(&self, package: Package) -> Option<Term> {
453471
self.package_assignments
454472
.get(&package)
455-
.map(|pa| pa.assignments_intersection.term())
473+
.map(|pa| pa.assignments_intersection.term)
456474
}
457475

458476
/// Figure out if the satisfier and previous satisfier are of different decision levels.
@@ -534,10 +552,11 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
534552
let accum_term = if let &Some(cause) = satisfier_cause {
535553
store[cause].get(satisfier_package).unwrap().negate()
536554
} else {
537-
match satisfier_pa.assignments_intersection {
538-
AssignmentsIntersection::Derivations(_) => panic!("must be a decision"),
539-
AssignmentsIntersection::Decision((_, _, term)) => term,
540-
}
555+
assert!(
556+
satisfier_pa.assignments_intersection.is_decision,
557+
"must be a decision",
558+
);
559+
satisfier_pa.assignments_intersection.term
541560
};
542561

543562
let incompat_term = incompat
@@ -579,49 +598,37 @@ impl<M: Clone + Debug + Display> PackageAssignments<M> {
579598
debug_assert_eq!(dd.accumulated_intersection.intersection(start_term), empty);
580599
return (Some(dd.cause), dd.global_index, dd.decision_level);
581600
}
582-
// If it wasn't found in the derivations,
583-
// it must be the decision which is last (if called in the right context).
584-
match &self.assignments_intersection {
585-
AssignmentsIntersection::Decision((global_index, _, _)) => {
586-
(None, *global_index, self.highest_decision_level)
587-
}
588-
AssignmentsIntersection::Derivations(accumulated_intersection) => {
589-
let pkg = package_store.pkg(package).unwrap();
590-
unreachable!(
591-
"while processing package {pkg}: \
592-
accum_term = {accumulated_intersection} has overlap with incompat_term = {start_term}, \
593-
which means the last assignment should have been a decision, \
594-
but instead it was a derivation. This shouldn't be possible! \
595-
(Maybe your Version ordering is broken?)"
596-
)
597-
}
601+
// If it wasn't found in the derivations, it must be the decision which is last (if called in the right context).
602+
let AssignmentsIntersection {
603+
term,
604+
is_decision,
605+
decision_global_index,
606+
..
607+
} = self.assignments_intersection;
608+
if !is_decision {
609+
let pkg = package_store.pkg(package).unwrap();
610+
unreachable!(
611+
"while processing package {pkg}: \
612+
accum_term = {term} has overlap with incompat_term = {start_term}, \
613+
which means the last assignment should have been a decision, \
614+
but instead it was a derivation. This shouldn't be possible! \
615+
(Maybe your Version ordering is broken?)"
616+
)
598617
}
618+
(None, decision_global_index, self.highest_decision_level)
599619
}
600620
}
601621

602622
impl AssignmentsIntersection {
603-
/// Returns the term intersection of all assignments (decision included).
604-
fn term(&self) -> Term {
605-
match *self {
606-
Self::Decision((_, _, term)) => term,
607-
Self::Derivations(term) => term,
608-
}
609-
}
610-
611623
/// A package is a potential pick if there isn't an already
612624
/// selected version (no "decision")
613625
/// and if it contains at least one positive derivation term
614626
/// in the partial solution.
615627
fn potential_package_filter(&self, package: Package) -> Option<(Package, VersionSet)> {
616-
match self {
617-
Self::Decision(_) => None,
618-
Self::Derivations(term_intersection) => {
619-
if term_intersection.is_positive() {
620-
Some((package, term_intersection.unwrap_positive()))
621-
} else {
622-
None
623-
}
624-
}
628+
if !self.is_decision && self.term.is_positive() {
629+
Some((package, self.term.unwrap_positive()))
630+
} else {
631+
None
625632
}
626633
}
627634
}

src/term.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::{Version, VersionSet};
1818
/// Specifically, `Term::positive(VersionSet::empty())` means that there was a conflict
1919
/// (we need to select a version for the package but can't pick any),
2020
/// while `Term::negative(VersionSet::full())` would mean it is fine as long as we don't select the package.
21-
#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
21+
#[derive(Debug, Default, Copy, Clone, Eq, PartialEq, Hash)]
2222
#[repr(transparent)]
2323
pub struct Term(u64);
2424

0 commit comments

Comments
 (0)