Skip to content

Commit a65790c

Browse files
committed
Reduce AssignmentsIntersection size
1 parent 23102b4 commit a65790c

File tree

2 files changed

+100
-92
lines changed

2 files changed

+100
-92
lines changed

src/internal/partial_solution.rs

Lines changed: 99 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -134,19 +134,41 @@ impl<M: Eq + Clone + Debug + Display> Display for DatedDerivation<M> {
134134
}
135135
}
136136

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

143163
impl Display for AssignmentsIntersection {
144164
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145-
match self {
146-
Self::Decision((lvl, version_index, _)) => {
147-
write!(f, "Decision: level {}, v = {}", lvl, version_index.get())
148-
}
149-
Self::Derivations(term) => write!(f, "Derivations term: {}", term),
165+
if self.is_decision {
166+
let lvl = self.decision_global_index;
167+
let version = self.decision_version_index.get();
168+
write!(f, "Decision: level {lvl}, v = {version}")
169+
} else {
170+
let term = self.term;
171+
write!(f, "Derivations term: {term}")
150172
}
151173
}
152174
}
@@ -193,25 +215,26 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
193215
pub(crate) fn add_decision(&mut self, package: Package, version_index: VersionIndex) {
194216
// Check that add_decision is never used in the wrong context.
195217
if cfg!(debug_assertions) {
196-
match self.package_assignments.get_mut(&package) {
197-
None => panic!("Derivations must already exist"),
198-
Some(pa) => match &pa.assignments_intersection {
199-
// Cannot be called when a decision has already been taken.
200-
AssignmentsIntersection::Decision(_) => panic!("Already existing decision"),
201-
// Cannot be called if the versions is not contained in the terms' intersection.
202-
AssignmentsIntersection::Derivations(term) => {
203-
debug_assert!(
204-
term.contains(version_index),
205-
"{} was expected to be contained in {}",
206-
version_index.get(),
207-
term,
208-
)
209-
}
210-
},
211-
}
218+
let pa = self
219+
.package_assignments
220+
.get_mut(&package)
221+
.expect("Derivations must already exist");
222+
// Cannot be called when a decision has already been taken.
223+
assert!(
224+
!pa.assignments_intersection.is_decision,
225+
"Already existing decision",
226+
);
227+
// Cannot be called if the versions is not contained in the terms' intersection.
228+
let term = pa.assignments_intersection.term;
229+
assert!(
230+
term.contains(version_index),
231+
"{} was expected to be contained in {}",
232+
version_index.get(),
233+
term,
234+
);
212235
assert_eq!(
213236
self.changed_this_decision_level,
214-
self.package_assignments.len()
237+
self.package_assignments.len(),
215238
);
216239
}
217240
let new_idx = self.current_decision_level.0 as usize;
@@ -221,11 +244,8 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
221244
.get_full_mut(&package)
222245
.expect("Derivations must already exist");
223246
pa.highest_decision_level = self.current_decision_level;
224-
pa.assignments_intersection = AssignmentsIntersection::Decision((
225-
self.next_global_index,
226-
version_index,
227-
Term::exact(version_index),
228-
));
247+
pa.assignments_intersection =
248+
AssignmentsIntersection::decision(self.next_global_index, version_index);
229249
// Maintain that the beginning of the `package_assignments` Have all decisions in sorted order.
230250
if new_idx != old_idx {
231251
self.package_assignments.swap_indices(new_idx, old_idx);
@@ -254,21 +274,19 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
254274
let idx = occupied.index();
255275
let pa = occupied.get_mut();
256276
pa.highest_decision_level = self.current_decision_level;
257-
match &mut pa.assignments_intersection {
258-
// Check that add_derivation is never called in the wrong context.
259-
AssignmentsIntersection::Decision(_) => {
260-
panic!("add_derivation should not be called after a decision")
261-
}
262-
AssignmentsIntersection::Derivations(t) => {
263-
*t = t.intersection(dated_derivation.accumulated_intersection);
264-
dated_derivation.accumulated_intersection = *t;
265-
if t.is_positive() {
266-
// we can use `swap_indices` to make `changed_this_decision_level` only go down by 1
267-
// but the copying is slower then the larger search
268-
self.changed_this_decision_level =
269-
std::cmp::min(self.changed_this_decision_level, idx);
270-
}
271-
}
277+
// Check that add_derivation is never called in the wrong context.
278+
assert!(
279+
!pa.assignments_intersection.is_decision,
280+
"add_derivation should not be called after a decision",
281+
);
282+
let t = &mut pa.assignments_intersection.term;
283+
*t = t.intersection(dated_derivation.accumulated_intersection);
284+
dated_derivation.accumulated_intersection = *t;
285+
if t.is_positive() {
286+
// we can use `swap_indices` to make `changed_this_decision_level` only go down by 1
287+
// but the copying is slower then the larger search
288+
self.changed_this_decision_level =
289+
std::cmp::min(self.changed_this_decision_level, idx);
272290
}
273291
pa.dated_derivations.push(dated_derivation);
274292
}
@@ -282,7 +300,7 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
282300
smallest_decision_level: self.current_decision_level,
283301
highest_decision_level: self.current_decision_level,
284302
dated_derivations: SmallVec::One([dated_derivation]),
285-
assignments_intersection: AssignmentsIntersection::Derivations(term),
303+
assignments_intersection: AssignmentsIntersection::derivations(term),
286304
});
287305
}
288306
}
@@ -327,11 +345,12 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
327345
.package_assignments
328346
.iter()
329347
.take(self.current_decision_level.0 as usize)
330-
.map(|(&p, pa)| match pa.assignments_intersection {
331-
AssignmentsIntersection::Decision((_, version_index, _)) => (p, version_index),
332-
AssignmentsIntersection::Derivations(_) => {
333-
panic!("Derivations in the Decision part")
334-
}
348+
.map(|(&p, pa)| {
349+
assert!(
350+
pa.assignments_intersection.is_decision,
351+
"Derivations in the Decision part",
352+
);
353+
(p, pa.assignments_intersection.decision_version_index)
335354
})
336355
.collect::<Map<_, _>>();
337356

@@ -374,7 +393,7 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
374393

375394
// Reset the assignments intersection.
376395
pa.assignments_intersection =
377-
AssignmentsIntersection::Derivations(last.accumulated_intersection);
396+
AssignmentsIntersection::derivations(last.accumulated_intersection);
378397
true
379398
}
380399
});
@@ -458,7 +477,7 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
458477
pub(crate) fn term_intersection_for_package(&self, package: Package) -> Option<Term> {
459478
self.package_assignments
460479
.get(&package)
461-
.map(|pa| pa.assignments_intersection.term())
480+
.map(|pa| pa.assignments_intersection.term)
462481
}
463482

464483
/// Figure out if the satisfier and previous satisfier are of different decision levels.
@@ -540,10 +559,11 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
540559
let accum_term = if let &Some(cause) = satisfier_cause {
541560
store[cause].get(satisfier_package).unwrap().negate()
542561
} else {
543-
match satisfier_pa.assignments_intersection {
544-
AssignmentsIntersection::Derivations(_) => panic!("must be a decision"),
545-
AssignmentsIntersection::Decision((_, _, term)) => term,
546-
}
562+
assert!(
563+
satisfier_pa.assignments_intersection.is_decision,
564+
"must be a decision",
565+
);
566+
satisfier_pa.assignments_intersection.term
547567
};
548568

549569
let incompat_term = incompat
@@ -585,49 +605,37 @@ impl<M: Eq + Clone + Debug + Display> PackageAssignments<M> {
585605
debug_assert_eq!(dd.accumulated_intersection.intersection(start_term), empty);
586606
return (Some(dd.cause), dd.global_index, dd.decision_level);
587607
}
588-
// If it wasn't found in the derivations,
589-
// it must be the decision which is last (if called in the right context).
590-
match &self.assignments_intersection {
591-
AssignmentsIntersection::Decision((global_index, _, _)) => {
592-
(None, *global_index, self.highest_decision_level)
593-
}
594-
AssignmentsIntersection::Derivations(accumulated_intersection) => {
595-
let pkg = package_store.pkg(package).unwrap();
596-
unreachable!(
597-
"while processing package {pkg}: \
598-
accum_term = {accumulated_intersection} has overlap with incompat_term = {start_term}, \
599-
which means the last assignment should have been a decision, \
600-
but instead it was a derivation. This shouldn't be possible! \
601-
(Maybe your Version ordering is broken?)"
602-
)
603-
}
608+
// If it wasn't found in the derivations, it must be the decision which is last (if called in the right context).
609+
let AssignmentsIntersection {
610+
term,
611+
is_decision,
612+
decision_global_index,
613+
..
614+
} = self.assignments_intersection;
615+
if !is_decision {
616+
let pkg = package_store.pkg(package).unwrap();
617+
unreachable!(
618+
"while processing package {pkg}: \
619+
accum_term = {term} has overlap with incompat_term = {start_term}, \
620+
which means the last assignment should have been a decision, \
621+
but instead it was a derivation. This shouldn't be possible! \
622+
(Maybe your Version ordering is broken?)"
623+
)
604624
}
625+
(None, decision_global_index, self.highest_decision_level)
605626
}
606627
}
607628

608629
impl AssignmentsIntersection {
609-
/// Returns the term intersection of all assignments (decision included).
610-
fn term(&self) -> Term {
611-
match *self {
612-
Self::Decision((_, _, term)) => term,
613-
Self::Derivations(term) => term,
614-
}
615-
}
616-
617630
/// A package is a potential pick if there isn't an already
618631
/// selected version (no "decision")
619632
/// and if it contains at least one positive derivation term
620633
/// in the partial solution.
621634
fn potential_package_filter(&self, package: Package) -> Option<(Package, VersionSet)> {
622-
match self {
623-
Self::Decision(_) => None,
624-
Self::Derivations(term_intersection) => {
625-
if term_intersection.is_positive() {
626-
Some((package, term_intersection.unwrap_positive()))
627-
} else {
628-
None
629-
}
630-
}
635+
if !self.is_decision && self.term.is_positive() {
636+
Some((package, self.term.unwrap_positive()))
637+
} else {
638+
None
631639
}
632640
}
633641
}

src/term.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ use crate::{VersionIndex, 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)