Skip to content

Commit aaa67b6

Browse files
committed
Reduce AssignmentsIntersection size
1 parent 8e3badc commit aaa67b6

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
@@ -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
}
@@ -326,11 +344,12 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
326344
.package_assignments
327345
.iter()
328346
.take(self.current_decision_level.0 as usize)
329-
.map(|(&pid, pa)| match pa.assignments_intersection {
330-
AssignmentsIntersection::Decision((_, version_index, _)) => (pid, version_index),
331-
AssignmentsIntersection::Derivations(_) => {
332-
panic!("Derivations in the Decision part")
333-
}
347+
.map(|(&pid, pa)| {
348+
assert!(
349+
pa.assignments_intersection.is_decision,
350+
"Derivations in the Decision part",
351+
);
352+
(pid, pa.assignments_intersection.decision_version_index)
334353
})
335354
.collect::<Map<_, _>>();
336355

@@ -373,7 +392,7 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
373392

374393
// Reset the assignments intersection.
375394
pa.assignments_intersection =
376-
AssignmentsIntersection::Derivations(last.accumulated_intersection);
395+
AssignmentsIntersection::derivations(last.accumulated_intersection);
377396
true
378397
}
379398
});
@@ -461,7 +480,7 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
461480
pub(crate) fn term_intersection_for_package(&self, package_id: PackageId) -> Option<Term> {
462481
self.package_assignments
463482
.get(&package_id)
464-
.map(|pa| pa.assignments_intersection.term())
483+
.map(|pa| pa.assignments_intersection.term)
465484
}
466485

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

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

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

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)