OLD | NEW |
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 import 'package:collection/collection.dart'; | 5 import 'package:collection/collection.dart'; |
6 | 6 |
7 import 'utils.dart'; | 7 import 'utils.dart'; |
8 import 'version.dart'; | 8 import 'version.dart'; |
9 import 'version_constraint.dart'; | 9 import 'version_constraint.dart'; |
10 import 'version_range.dart'; | 10 import 'version_range.dart'; |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
69 // safely move through them linearly here. | 69 // safely move through them linearly here. |
70 ourRanges.moveNext(); | 70 ourRanges.moveNext(); |
71 theirRanges.moveNext(); | 71 theirRanges.moveNext(); |
72 while (ourRanges.current != null && theirRanges.current != null) { | 72 while (ourRanges.current != null && theirRanges.current != null) { |
73 if (ourRanges.current.allowsAny(theirRanges.current)) { | 73 if (ourRanges.current.allowsAny(theirRanges.current)) { |
74 return true; | 74 return true; |
75 } | 75 } |
76 | 76 |
77 // Move the constraint with the lower max value forward. This ensures that | 77 // Move the constraint with the lower max value forward. This ensures that |
78 // we keep both lists in sync as much as possible. | 78 // we keep both lists in sync as much as possible. |
79 if (compareMax(ourRanges.current, theirRanges.current) < 0) { | 79 if (allowsHigher(theirRanges.current, ourRanges.current)) { |
80 ourRanges.moveNext(); | 80 ourRanges.moveNext(); |
81 } else { | 81 } else { |
82 theirRanges.moveNext(); | 82 theirRanges.moveNext(); |
83 } | 83 } |
84 } | 84 } |
85 | 85 |
86 return false; | 86 return false; |
87 } | 87 } |
88 | 88 |
89 VersionConstraint intersect(VersionConstraint other) { | 89 VersionConstraint intersect(VersionConstraint other) { |
90 var ourRanges = ranges.iterator; | 90 var ourRanges = ranges.iterator; |
91 var theirRanges = _rangesFor(other).iterator; | 91 var theirRanges = _rangesFor(other).iterator; |
92 | 92 |
93 // Because both lists of ranges are ordered by minimum version, we can | 93 // Because both lists of ranges are ordered by minimum version, we can |
94 // safely move through them linearly here. | 94 // safely move through them linearly here. |
95 var newRanges = <VersionRange>[]; | 95 var newRanges = <VersionRange>[]; |
96 ourRanges.moveNext(); | 96 ourRanges.moveNext(); |
97 theirRanges.moveNext(); | 97 theirRanges.moveNext(); |
98 while (ourRanges.current != null && theirRanges.current != null) { | 98 while (ourRanges.current != null && theirRanges.current != null) { |
99 var intersection = ourRanges.current | 99 var intersection = ourRanges.current |
100 .intersect(theirRanges.current); | 100 .intersect(theirRanges.current); |
101 | 101 |
102 if (!intersection.isEmpty) newRanges.add(intersection); | 102 if (!intersection.isEmpty) newRanges.add(intersection); |
103 | 103 |
104 // Move the constraint with the lower max value forward. This ensures that | 104 // Move the constraint with the lower max value forward. This ensures that |
105 // we keep both lists in sync as much as possible, and that large ranges | 105 // we keep both lists in sync as much as possible, and that large ranges |
106 // have a chance to match multiple small ranges that they contain. | 106 // have a chance to match multiple small ranges that they contain. |
107 if (compareMax(ourRanges.current, theirRanges.current) < 0) { | 107 if (allowsHigher(theirRanges.current, ourRanges.current)) { |
108 ourRanges.moveNext(); | 108 ourRanges.moveNext(); |
109 } else { | 109 } else { |
110 theirRanges.moveNext(); | 110 theirRanges.moveNext(); |
111 } | 111 } |
112 } | 112 } |
113 | 113 |
114 if (newRanges.isEmpty) return VersionConstraint.empty; | 114 if (newRanges.isEmpty) return VersionConstraint.empty; |
115 if (newRanges.length == 1) return newRanges.single; | 115 if (newRanges.length == 1) return newRanges.single; |
116 | 116 |
117 return new VersionUnion.fromRanges(newRanges); | 117 return new VersionUnion.fromRanges(newRanges); |
118 } | 118 } |
119 | 119 |
| 120 VersionConstraint difference(VersionConstraint other) { |
| 121 var ourRanges = ranges.iterator; |
| 122 var theirRanges = _rangesFor(other).iterator; |
| 123 |
| 124 var newRanges = <VersionRange>[]; |
| 125 ourRanges.moveNext(); |
| 126 theirRanges.moveNext(); |
| 127 var current = ourRanges.current; |
| 128 |
| 129 theirNextRange() { |
| 130 if (theirRanges.moveNext()) return true; |
| 131 |
| 132 // If there are no more of their ranges, none of the rest of our ranges |
| 133 // need to be subtracted so we can add them as-is. |
| 134 newRanges.add(current); |
| 135 while (ourRanges.moveNext()) { |
| 136 newRanges.add(ourRanges.current); |
| 137 } |
| 138 return false; |
| 139 } |
| 140 |
| 141 ourNextRange({bool includeCurrent: true}) { |
| 142 if (includeCurrent) newRanges.add(current); |
| 143 if (!ourRanges.moveNext()) return false; |
| 144 current = ourRanges.current; |
| 145 return true; |
| 146 } |
| 147 |
| 148 while (true) { |
| 149 // If the current ranges are disjoint, move the lowest one forward. |
| 150 if (strictlyLower(theirRanges.current, current)) { |
| 151 if (!theirNextRange()) break; |
| 152 continue; |
| 153 } |
| 154 |
| 155 if (strictlyHigher(theirRanges.current, current)) { |
| 156 if (!ourNextRange()) break; |
| 157 continue; |
| 158 } |
| 159 |
| 160 // If we're here, we know [theirRanges.current] overlaps [current]. |
| 161 var difference = current.difference(theirRanges.current); |
| 162 if (difference is VersionUnion) { |
| 163 // If their range split [current] in half, we only need to continue |
| 164 // checking future ranges against the latter half. |
| 165 assert(difference.ranges.length == 2); |
| 166 newRanges.add(difference.ranges.first); |
| 167 current = difference.ranges.last; |
| 168 |
| 169 // Since their range split [current], it definitely doesn't allow higher |
| 170 // versions, so we should move their ranges forward. |
| 171 if (!theirNextRange()) break; |
| 172 } else if (difference.isEmpty) { |
| 173 if (!ourNextRange(includeCurrent: false)) break; |
| 174 } else { |
| 175 current = difference as VersionRange; |
| 176 |
| 177 // Move the constraint with the lower max value forward. This ensures |
| 178 // that we keep both lists in sync as much as possible, and that large |
| 179 // ranges have a chance to subtract or be subtracted by multiple small |
| 180 // ranges that they contain. |
| 181 if (allowsHigher(current, theirRanges.current)) { |
| 182 if (!theirNextRange()) break; |
| 183 } else { |
| 184 if (!ourNextRange()) break; |
| 185 } |
| 186 } |
| 187 } |
| 188 |
| 189 if (newRanges.isEmpty) return VersionConstraint.empty; |
| 190 if (newRanges.length == 1) return newRanges.single; |
| 191 return new VersionUnion.fromRanges(newRanges); |
| 192 } |
| 193 |
120 /// Returns [constraint] as a list of ranges. | 194 /// Returns [constraint] as a list of ranges. |
121 /// | 195 /// |
122 /// This is used to normalize ranges of various types. | 196 /// This is used to normalize ranges of various types. |
123 List<VersionRange> _rangesFor(VersionConstraint constraint) { | 197 List<VersionRange> _rangesFor(VersionConstraint constraint) { |
124 if (constraint.isEmpty) return []; | 198 if (constraint.isEmpty) return []; |
125 if (constraint is VersionUnion) return constraint.ranges; | 199 if (constraint is VersionUnion) return constraint.ranges; |
126 if (constraint is VersionRange) return [constraint]; | 200 if (constraint is VersionRange) return [constraint]; |
127 throw new ArgumentError('Unknown VersionConstraint type $constraint.'); | 201 throw new ArgumentError('Unknown VersionConstraint type $constraint.'); |
128 } | 202 } |
129 | 203 |
130 VersionConstraint union(VersionConstraint other) => | 204 VersionConstraint union(VersionConstraint other) => |
131 new VersionConstraint.unionOf([this, other]); | 205 new VersionConstraint.unionOf([this, other]); |
132 | 206 |
133 bool operator ==(other) { | 207 bool operator ==(other) { |
134 if (other is! VersionUnion) return false; | 208 if (other is! VersionUnion) return false; |
135 return const ListEquality().equals(ranges, other.ranges); | 209 return const ListEquality().equals(ranges, other.ranges); |
136 } | 210 } |
137 | 211 |
138 int get hashCode => const ListEquality().hash(ranges); | 212 int get hashCode => const ListEquality().hash(ranges); |
139 | 213 |
140 String toString() => ranges.join(" or "); | 214 String toString() => ranges.join(" or "); |
141 } | 215 } |
OLD | NEW |