Skip to content

Commit 475d355

Browse files
committed
Reduce AssignmentsIntersection size
1 parent c5c4a3c commit 475d355

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: Package, 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) {
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)
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)
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(|(&p, pa)| match pa.assignments_intersection {
330-
AssignmentsIntersection::Decision((_, version_index, _)) => (p, version_index),
331-
AssignmentsIntersection::Derivations(_) => {
332-
panic!("Derivations in the Decision part")
333-
}
347+
.map(|(&p, pa)| {
348+
assert!(
349+
pa.assignments_intersection.is_decision,
350+
"Derivations in the Decision part",
351+
);
352+
(p, 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
});
@@ -457,7 +476,7 @@ impl<DP: DependencyProvider> PartialSolution<DP> {
457476
pub(crate) fn term_intersection_for_package(&self, package: Package) -> Option<Term> {
458477
self.package_assignments
459478
.get(&package)
460-
.map(|pa| pa.assignments_intersection.term())
479+
.map(|pa| pa.assignments_intersection.term)
461480
}
462481

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

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

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

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)