@@ -16,26 +16,36 @@ import 'term.dart';
16
16
class PartialSolution {
17
17
/// The assignments that have been made so far, in the order they were
18
18
/// assigned.
19
- final assignments = < Assignment > [];
19
+ final _assignments = < Assignment > [];
20
+
21
+ /// The decisions made for each package.
22
+ final _decisions = < String , PackageId > {};
20
23
21
24
/// The intersection of all positive [Assignment] s for each package, minus any
22
25
/// negative [Assignment] s that refer to that package.
23
26
///
24
- /// This is derived from [assignments ] .
25
- final positive = < String , Term > {};
27
+ /// This is derived from [_assignments ] .
28
+ final _positive = < String , Term > {};
26
29
27
30
/// The union of all negative [Assignment] s for each package.
28
31
///
29
32
/// If a package has any positive [Assignment] s, it doesn't appear in this
30
33
/// map.
31
34
///
32
- /// This is derived from [assignments] .
33
- final negative = < String , Map <PackageRef , Term >> {};
35
+ /// This is derived from [_assignments] .
36
+ final _negative = < String , Map <PackageRef , Term >> {};
37
+
38
+ /// Returns all the decisions that have been made in this partial solution.
39
+ Iterable <PackageId > get decisions => _decisions.values;
34
40
35
- // The current decision level—that is, the number of decisions in
36
- // [assignments].
37
- int get decisionLevel => _decisionLevel;
38
- var _decisionLevel = 0 ;
41
+ /// Returns all [PackageRange] s that have been assigned but are not yet
42
+ /// satisfied.
43
+ Iterable <PackageRange > get unsatisfied => _positive.values
44
+ .where ((term) => ! _decisions.containsKey (term.package.name))
45
+ .map ((term) => term.package);
46
+
47
+ // The current decision level—that is, the length of [decisions].
48
+ int get decisionLevel => _decisions.length;
39
49
40
50
/// The number of distinct solutions that have been attempted so far.
41
51
int get attemptedSolutions => _attemptedSolutions;
@@ -44,27 +54,29 @@ class PartialSolution {
44
54
/// Whether the solver is currently backtracking.
45
55
var _backtracking = false ;
46
56
47
- /// Adds an assignment of [package] to [isPositive] to [assignments] .
48
- ///
49
- /// If [decision] is `true` , this is a decision (a speculative assignment
50
- /// rather than one that's automatically propagated from incompatibilities)
51
- /// and the [decisionLevel] should be incremented.
52
- void assign (PackageName package, bool isPositive,
53
- {Incompatibility cause, bool decision: false }) {
54
- if (decision) {
55
- // When we make a new decision after backtracking, count an additional
56
- // attempted solution. If we backtrack multiple times in a row, though, we
57
- // only want to count one, since we haven't actually started attempting a
58
- // new solution.
59
- if (_backtracking) _attemptedSolutions++ ;
60
- _backtracking = false ;
61
- _decisionLevel++ ;
62
- }
57
+ /// Adds an assignment of [package] as a decision and increments the
58
+ /// [decisionLevel] .
59
+ void decide (PackageId package) {
60
+ // When we make a new decision after backtracking, count an additional
61
+ // attempted solution. If we backtrack multiple times in a row, though, we
62
+ // only want to count one, since we haven't actually started attempting a
63
+ // new solution.
64
+ if (_backtracking) _attemptedSolutions++ ;
65
+ _backtracking = false ;
66
+ _decisions[package.name] = package;
67
+ _assign (
68
+ new Assignment .decision (package, decisionLevel, _assignments.length));
69
+ }
70
+
71
+ /// Adds an assignment of [package] as a derivation.
72
+ void derive (PackageName package, bool isPositive, Incompatibility cause) {
73
+ _assign (new Assignment .derivation (
74
+ package, isPositive, cause, decisionLevel, _assignments.length));
75
+ }
63
76
64
- var assignment = new Assignment (
65
- package, isPositive, _decisionLevel, assignments.length,
66
- cause: cause);
67
- assignments.add (assignment);
77
+ /// Adds [assignment] to [_assignments] and [_positive] or [_negative] .
78
+ void _assign (Assignment assignment) {
79
+ _assignments.add (assignment);
68
80
_register (assignment);
69
81
}
70
82
@@ -74,56 +86,55 @@ class PartialSolution {
74
86
_backtracking = true ;
75
87
76
88
var packages = new Set <String >();
77
- while (assignments .last.decisionLevel > decisionLevel) {
78
- var removed = assignments .removeLast ();
89
+ while (_assignments .last.decisionLevel > decisionLevel) {
90
+ var removed = _assignments .removeLast ();
79
91
packages.add (removed.package.name);
92
+ if (removed.isDecision) _decisions.remove (removed.package.name);
80
93
}
81
- _decisionLevel = decisionLevel;
82
94
83
- // Re-compute [positive ] and [negative ] for the packages that were removed.
95
+ // Re-compute [_positive ] and [_negative ] for the packages that were removed.
84
96
for (var package in packages) {
85
- positive .remove (package);
86
- negative .remove (package);
97
+ _positive .remove (package);
98
+ _negative .remove (package);
87
99
}
88
100
89
- for (var assignment in assignments ) {
101
+ for (var assignment in _assignments ) {
90
102
if (packages.contains (assignment.package.name)) {
91
103
_register (assignment);
92
104
}
93
105
}
94
106
}
95
107
96
- /// Registers [assignment] in [positive ] or [negative ] .
108
+ /// Registers [assignment] in [_positive ] or [_negative ] .
97
109
void _register (Assignment assignment) {
98
110
var name = assignment.package.name;
99
- var oldPositive = positive [name];
111
+ var oldPositive = _positive [name];
100
112
if (oldPositive != null ) {
101
- positive [name] = oldPositive.intersect (assignment);
113
+ _positive [name] = oldPositive.intersect (assignment);
102
114
return ;
103
115
}
104
116
105
117
var ref = assignment.package.toRef ();
106
- var negativeByRef = negative [name];
118
+ var negativeByRef = _negative [name];
107
119
var oldNegative = negativeByRef == null ? null : negativeByRef[ref];
108
120
var term =
109
121
oldNegative == null ? assignment : assignment.intersect (oldNegative);
110
122
111
123
if (term.isPositive) {
112
- negative .remove (name);
113
- positive [name] = term;
124
+ _negative .remove (name);
125
+ _positive [name] = term;
114
126
} else {
115
- negative .putIfAbsent (name, () => {})[ref] = term;
127
+ _negative .putIfAbsent (name, () => {})[ref] = term;
116
128
}
117
129
}
118
130
119
- /// Returns the first entry in [assignments] such that the sublist of
120
- /// assignments up to and including that entry collectively satisfies
121
- /// [term] .
131
+ /// Returns the first [Assignment] in this solution such that the sublist of
132
+ /// assignments up to and including that entry collectively satisfies [term] .
122
133
///
123
134
/// Throws a [StateError] if [term] isn't satisfied by [this] .
124
135
Assignment satisfier (Term term) {
125
136
Term assignedTerm;
126
- for (var assignment in assignments ) {
137
+ for (var assignment in _assignments ) {
127
138
if (assignment.package.name != term.package.name) continue ;
128
139
129
140
if (! assignment.package.isRoot &&
@@ -149,20 +160,20 @@ class PartialSolution {
149
160
150
161
/// Returns whether [this] satisfies [other] .
151
162
///
152
- /// That is, whether [other] must be true given that [ assignments] are all
153
- /// true .
163
+ /// That is, whether [other] must be true given the assignments in this
164
+ /// partial solution .
154
165
bool satisfies (Term term) => relation (term) == SetRelation .subset;
155
166
156
167
/// Returns the relationship between the package versions allowed by all
157
168
/// assignments in [this] and those allowed by [term] .
158
169
SetRelation relation (Term term) {
159
- var positive = this .positive [term.package.name];
170
+ var positive = _positive [term.package.name];
160
171
if (positive != null ) return positive.relation (term);
161
172
162
173
// If there are no assignments related to [term], that means the
163
174
// assignments allow any version of any package, which is a superset of
164
175
// [term].
165
- var byRef = this .negative [term.package.name];
176
+ var byRef = _negative [term.package.name];
166
177
if (byRef == null ) return SetRelation .overlapping;
167
178
168
179
// not foo from git is a superset of foo from hosted
0 commit comments