Skip to content

Commit 5f878d6

Browse files
committed
Reduce AssignmentsIntersection size
1 parent 5ce70ea commit 5f878d6

File tree

1 file changed

+99
-91
lines changed

1 file changed

+99
-91
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_id: PackageId, 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_id) {
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_id)
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_id)
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
}
@@ -328,11 +346,12 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
328346
.package_assignments
329347
.iter()
330348
.take(self.current_decision_level.0 as usize)
331-
.map(|(&pid, pa)| match pa.assignments_intersection {
332-
AssignmentsIntersection::Decision((_, version_index, _)) => (pid, version_index),
333-
AssignmentsIntersection::Derivations(_) => {
334-
panic!("Derivations in the Decision part")
335-
}
349+
.map(|(&pid, pa)| {
350+
assert!(
351+
pa.assignments_intersection.is_decision,
352+
"Derivations in the Decision part",
353+
);
354+
(pid, pa.assignments_intersection.decision_version_index)
336355
})
337356
.collect::<Map<_, _>>();
338357

@@ -375,7 +394,7 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
375394

376395
// Reset the assignments intersection.
377396
pa.assignments_intersection =
378-
AssignmentsIntersection::Derivations(last.accumulated_intersection);
397+
AssignmentsIntersection::derivations(last.accumulated_intersection);
379398
true
380399
}
381400
});
@@ -463,7 +482,7 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
463482
pub(crate) fn term_intersection_for_package(&self, package_id: PackageId) -> Option<Term> {
464483
self.package_assignments
465484
.get(&package_id)
466-
.map(|pa| pa.assignments_intersection.term())
485+
.map(|pa| pa.assignments_intersection.term)
467486
}
468487

469488
/// Figure out if the satisfier and previous satisfier are of different decision levels.
@@ -545,10 +564,11 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
545564
let accum_term = if let Some(cause) = satisfier_cause {
546565
store[cause].get(satisfier_pid).unwrap().negate()
547566
} else {
548-
match satisfier_pa.assignments_intersection {
549-
AssignmentsIntersection::Derivations(_) => panic!("must be a decision"),
550-
AssignmentsIntersection::Decision((_, _, term)) => term,
551-
}
567+
assert!(
568+
satisfier_pa.assignments_intersection.is_decision,
569+
"must be a decision",
570+
);
571+
satisfier_pa.assignments_intersection.term
552572
};
553573

554574
let incompat_term = incompat
@@ -590,49 +610,37 @@ impl<M: Eq + Clone + Debug + Display> PackageAssignments<M> {
590610
debug_assert_eq!(dd.accumulated_intersection.intersection(start_term), empty);
591611
return (Some(dd.cause), dd.global_index, dd.decision_level);
592612
}
593-
// If it wasn't found in the derivations,
594-
// it must be the decision which is last (if called in the right context).
595-
match &self.assignments_intersection {
596-
AssignmentsIntersection::Decision((global_index, _, _)) => {
597-
(None, *global_index, self.highest_decision_level)
598-
}
599-
AssignmentsIntersection::Derivations(accumulated_intersection) => {
600-
let p = package_store.pkg(package_id).unwrap();
601-
unreachable!(
602-
"while processing package {p}: \
603-
accum_term = {accumulated_intersection} has overlap with incompat_term = {start_term}, \
604-
which means the last assignment should have been a decision, \
605-
but instead it was a derivation. This shouldn't be possible! \
606-
(Maybe your Version ordering is broken?)"
607-
)
608-
}
613+
// If it wasn't found in the derivations, it must be the decision which is last (if called in the right context).
614+
let AssignmentsIntersection {
615+
term,
616+
is_decision,
617+
decision_global_index,
618+
..
619+
} = self.assignments_intersection;
620+
if !is_decision {
621+
let p = package_store.pkg(package_id).unwrap();
622+
unreachable!(
623+
"while processing package {p}: \
624+
accum_term = {term} has overlap with incompat_term = {start_term}, \
625+
which means the last assignment should have been a decision, \
626+
but instead it was a derivation. This shouldn't be possible! \
627+
(Maybe your Version ordering is broken?)"
628+
)
609629
}
630+
(None, decision_global_index, self.highest_decision_level)
610631
}
611632
}
612633

613634
impl AssignmentsIntersection {
614-
/// Returns the term intersection of all assignments (decision included).
615-
fn term(&self) -> Term {
616-
match *self {
617-
Self::Decision((_, _, term)) => term,
618-
Self::Derivations(term) => term,
619-
}
620-
}
621-
622635
/// A package is a potential pick if there isn't an already
623636
/// selected version (no "decision")
624637
/// and if it contains at least one positive derivation term
625638
/// in the partial solution.
626639
fn potential_package_filter(&self, package_id: PackageId) -> Option<(PackageId, VersionSet)> {
627-
match self {
628-
Self::Decision(_) => None,
629-
Self::Derivations(term_intersection) => {
630-
if term_intersection.is_positive() {
631-
Some((package_id, term_intersection.unwrap_positive()))
632-
} else {
633-
None
634-
}
635-
}
640+
if !self.is_decision && self.term.is_positive() {
641+
Some((package_id, self.term.unwrap_positive()))
642+
} else {
643+
None
636644
}
637645
}
638646
}

0 commit comments

Comments
 (0)