Index: lib/src/version_union.dart |
diff --git a/lib/src/version_union.dart b/lib/src/version_union.dart |
index d0e1e2bf46fa95000916bf7cf6f49e4c40c187fc..a26cb528d899acfa73070cd1c097b5b95b143a67 100644 |
--- a/lib/src/version_union.dart |
+++ b/lib/src/version_union.dart |
@@ -76,7 +76,7 @@ class VersionUnion implements VersionConstraint { |
// Move the constraint with the lower max value forward. This ensures that |
// we keep both lists in sync as much as possible. |
- if (compareMax(ourRanges.current, theirRanges.current) < 0) { |
+ if (allowsHigher(theirRanges.current, ourRanges.current)) { |
ourRanges.moveNext(); |
} else { |
theirRanges.moveNext(); |
@@ -104,7 +104,7 @@ class VersionUnion implements VersionConstraint { |
// Move the constraint with the lower max value forward. This ensures that |
// we keep both lists in sync as much as possible, and that large ranges |
// have a chance to match multiple small ranges that they contain. |
- if (compareMax(ourRanges.current, theirRanges.current) < 0) { |
+ if (allowsHigher(theirRanges.current, ourRanges.current)) { |
ourRanges.moveNext(); |
} else { |
theirRanges.moveNext(); |
@@ -117,6 +117,80 @@ class VersionUnion implements VersionConstraint { |
return new VersionUnion.fromRanges(newRanges); |
} |
+ VersionConstraint difference(VersionConstraint other) { |
+ var ourRanges = ranges.iterator; |
+ var theirRanges = _rangesFor(other).iterator; |
+ |
+ var newRanges = <VersionRange>[]; |
+ ourRanges.moveNext(); |
+ theirRanges.moveNext(); |
+ var current = ourRanges.current; |
+ |
+ theirNextRange() { |
+ if (theirRanges.moveNext()) return true; |
+ |
+ // If there are no more of their ranges, none of the rest of our ranges |
+ // need to be subtracted so we can add them as-is. |
+ newRanges.add(current); |
+ while (ourRanges.moveNext()) { |
+ newRanges.add(ourRanges.current); |
+ } |
+ return false; |
+ } |
+ |
+ ourNextRange({bool includeCurrent: true}) { |
+ if (includeCurrent) newRanges.add(current); |
+ if (!ourRanges.moveNext()) return false; |
+ current = ourRanges.current; |
+ return true; |
+ } |
+ |
+ while (true) { |
+ // If the current ranges are disjoint, move the lowest one forward. |
+ if (strictlyLower(theirRanges.current, current)) { |
+ if (!theirNextRange()) break; |
+ continue; |
+ } |
+ |
+ if (strictlyHigher(theirRanges.current, current)) { |
+ if (!ourNextRange()) break; |
+ continue; |
+ } |
+ |
+ // If we're here, we know [theirRanges.current] overlaps [current]. |
+ var difference = current.difference(theirRanges.current); |
+ if (difference is VersionUnion) { |
+ // If their range split [current] in half, we only need to continue |
+ // checking future ranges against the latter half. |
+ assert(difference.ranges.length == 2); |
+ newRanges.add(difference.ranges.first); |
+ current = difference.ranges.last; |
+ |
+ // Since their range split [current], it definitely doesn't allow higher |
+ // versions, so we should move their ranges forward. |
+ if (!theirNextRange()) break; |
+ } else if (difference.isEmpty) { |
+ if (!ourNextRange(includeCurrent: false)) break; |
+ } else { |
+ current = difference as VersionRange; |
+ |
+ // Move the constraint with the lower max value forward. This ensures |
+ // that we keep both lists in sync as much as possible, and that large |
+ // ranges have a chance to subtract or be subtracted by multiple small |
+ // ranges that they contain. |
+ if (allowsHigher(current, theirRanges.current)) { |
+ if (!theirNextRange()) break; |
+ } else { |
+ if (!ourNextRange()) break; |
+ } |
+ } |
+ } |
+ |
+ if (newRanges.isEmpty) return VersionConstraint.empty; |
+ if (newRanges.length == 1) return newRanges.single; |
+ return new VersionUnion.fromRanges(newRanges); |
+ } |
+ |
/// Returns [constraint] as a list of ranges. |
/// |
/// This is used to normalize ranges of various types. |