Skip to content

Commit 0974ddb

Browse files
committed
Reduce AssignmentsIntersection size
1 parent aaa8e5e commit 0974ddb

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
@@ -133,19 +133,41 @@ impl<M: Eq + Clone + Debug + Display> Display for DatedDerivation<M> {
133133
}
134134
}
135135

136-
#[derive(Clone, Debug)]
137-
enum AssignmentsIntersection {
138-
Decision((u32, VersionIndex, 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_index: VersionIndex,
142+
}
143+
144+
impl AssignmentsIntersection {
145+
fn decision(global_index: u32, version_index: VersionIndex) -> Self {
146+
Self {
147+
term: Term::exact(version_index),
148+
is_decision: true,
149+
decision_global_index: global_index,
150+
decision_version_index: version_index,
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_index, _)) => {
146-
write!(f, "Decision: level {}, v = {}", lvl, version_index.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_index.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_id: PackageId, version_index: VersionIndex) {
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_id) {
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_index),
204-
"{} was expected to be contained in {}",
205-
version_index.get(),
206-
term,
207-
)
208-
}
209-
},
210-
}
217+
let pa = self
218+
.package_assignments
219+
.get_mut(&package_id)
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_index),
230+
"{} was expected to be contained in {}",
231+
version_index.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_id)
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_index,
226-
Term::exact(version_index),
227-
));
246+
pa.assignments_intersection =
247+
AssignmentsIntersection::decision(self.next_global_index, version_index);
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
}
@@ -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(|(&pid, pa)| match pa.assignments_intersection {
331-
AssignmentsIntersection::Decision((_, version_index, _)) => (pid, version_index),
332-
AssignmentsIntersection::Derivations(_) => {
333-
panic!("Derivations in the Decision part")
334-
}
348+
.map(|(&pid, pa)| {
349+
assert!(
350+
pa.assignments_intersection.is_decision,
351+
"Derivations in the Decision part",
352+
);
353+
(pid, 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
});
@@ -462,7 +481,7 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
462481
pub(crate) fn term_intersection_for_package(&self, package_id: PackageId) -> Option<Term> {
463482
self.package_assignments
464483
.get(&package_id)
465-
.map(|pa| pa.assignments_intersection.term())
484+
.map(|pa| pa.assignments_intersection.term)
466485
}
467486

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

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

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

0 commit comments

Comments
 (0)