| Index: lib/src/version_union.dart
|
| diff --git a/lib/src/version_union.dart b/lib/src/version_union.dart
|
| index 5d525647efac2a404c4c1c055ab11be6bc4edd45..dbdadcf0d6e667ed9b9b4d379371fb9edee506c0 100644
|
| --- a/lib/src/version_union.dart
|
| +++ b/lib/src/version_union.dart
|
| @@ -9,8 +9,8 @@ import 'version.dart';
|
| import 'version_constraint.dart';
|
| import 'version_range.dart';
|
|
|
| -/// A (package-private) version constraint representing a union of multiple
|
| -/// disjoint version constraints.
|
| +/// A version constraint representing a union of multiple disjoint version
|
| +/// ranges.
|
| ///
|
| /// An instance of this will only be created if the version can't be represented
|
| /// as a non-compound value.
|
| @@ -23,101 +23,63 @@ class VersionUnion implements VersionConstraint {
|
| /// * Its contents are disjoint and non-adjacent. In other words, for any two
|
| /// constraints next to each other in the list, there's some version between
|
| /// those constraints that they don't match.
|
| - final List<VersionRange> constraints;
|
| + final List<VersionRange> ranges;
|
|
|
| bool get isEmpty => false;
|
|
|
| bool get isAny => false;
|
|
|
| - /// Returns the union of [constraints].
|
| + /// Creates a union from a list of ranges with no pre-processing.
|
| ///
|
| - /// This ensures that an actual [VersionUnion] is only returned if necessary.
|
| - /// It also takes care of sorting and merging the constraints to ensure that
|
| - /// they're disjoint.
|
| - static VersionConstraint create(Iterable<VersionConstraint> constraints) {
|
| - var flattened = constraints.expand((constraint) {
|
| - if (constraint.isEmpty) return [];
|
| - if (constraint is VersionUnion) return constraint.constraints;
|
| - return [constraint];
|
| - }).toList();
|
| -
|
| - if (flattened.isEmpty) return VersionConstraint.empty;
|
| -
|
| - if (flattened.any((constraint) => constraint.isAny)) {
|
| - return VersionConstraint.any;
|
| - }
|
| -
|
| - // Only allow Versions and VersionRanges here so we can more easily reason
|
| - // about everything in [flattened]. _EmptyVersions and VersionUnions are
|
| - // filtered out above.
|
| - for (var constraint in flattened) {
|
| - if (constraint is VersionRange) continue;
|
| - throw new ArgumentError('Unknown VersionConstraint type $constraint.');
|
| - }
|
| -
|
| - flattened.sort(compareMax);
|
| -
|
| - var merged = <VersionRange>[];
|
| - for (var constraint in flattened) {
|
| - // Merge this constraint with the previous one, but only if they touch.
|
| - if (merged.isEmpty ||
|
| - (!merged.last.allowsAny(constraint) &&
|
| - !areAdjacent(merged.last, constraint))) {
|
| - merged.add(constraint);
|
| - } else {
|
| - merged[merged.length - 1] = merged.last.union(constraint);
|
| - }
|
| - }
|
| -
|
| - if (merged.length == 1) return merged.single;
|
| - return new VersionUnion._(merged);
|
| - }
|
| -
|
| - VersionUnion._(this.constraints);
|
| + /// It's up to the caller to ensure that the invariants described in [ranges]
|
| + /// are maintained. They are not verified by this constructor. To
|
| + /// automatically ensure that they're maintained, use [new
|
| + /// VersionConstraint.unionOf] instead.
|
| + VersionUnion.fromRanges(this.ranges);
|
|
|
| bool allows(Version version) =>
|
| - constraints.any((constraint) => constraint.allows(version));
|
| + ranges.any((constraint) => constraint.allows(version));
|
|
|
| bool allowsAll(VersionConstraint other) {
|
| - var ourConstraints = constraints.iterator;
|
| - var theirConstraints = _constraintsFor(other).iterator;
|
| + var ourRanges = ranges.iterator;
|
| + var theirRanges = _rangesFor(other).iterator;
|
|
|
| - // Because both lists of constraints are ordered by minimum version, we can
|
| + // Because both lists of ranges are ordered by minimum version, we can
|
| // safely move through them linearly here.
|
| - ourConstraints.moveNext();
|
| - theirConstraints.moveNext();
|
| - while (ourConstraints.current != null && theirConstraints.current != null) {
|
| - if (ourConstraints.current.allowsAll(theirConstraints.current)) {
|
| - theirConstraints.moveNext();
|
| + ourRanges.moveNext();
|
| + theirRanges.moveNext();
|
| + while (ourRanges.current != null && theirRanges.current != null) {
|
| + if (ourRanges.current.allowsAll(theirRanges.current)) {
|
| + theirRanges.moveNext();
|
| } else {
|
| - ourConstraints.moveNext();
|
| + ourRanges.moveNext();
|
| }
|
| }
|
|
|
| - // If our constraints have allowed all of their constraints, we'll have
|
| - // consumed all of them.
|
| - return theirConstraints.current == null;
|
| + // If our ranges have allowed all of their ranges, we'll have consumed all
|
| + // of them.
|
| + return theirRanges.current == null;
|
| }
|
|
|
| bool allowsAny(VersionConstraint other) {
|
| - var ourConstraints = constraints.iterator;
|
| - var theirConstraints = _constraintsFor(other).iterator;
|
| + var ourRanges = ranges.iterator;
|
| + var theirRanges = _rangesFor(other).iterator;
|
|
|
| - // Because both lists of constraints are ordered by minimum version, we can
|
| + // Because both lists of ranges are ordered by minimum version, we can
|
| // safely move through them linearly here.
|
| - ourConstraints.moveNext();
|
| - theirConstraints.moveNext();
|
| - while (ourConstraints.current != null && theirConstraints.current != null) {
|
| - if (ourConstraints.current.allowsAny(theirConstraints.current)) {
|
| + ourRanges.moveNext();
|
| + theirRanges.moveNext();
|
| + while (ourRanges.current != null && theirRanges.current != null) {
|
| + if (ourRanges.current.allowsAny(theirRanges.current)) {
|
| return true;
|
| }
|
|
|
| // Move the constraint with the higher max value forward. This ensures
|
| // that we keep both lists in sync as much as possible.
|
| - if (compareMax(ourConstraints.current, theirConstraints.current) < 0) {
|
| - ourConstraints.moveNext();
|
| + if (compareMax(ourRanges.current, theirRanges.current) < 0) {
|
| + ourRanges.moveNext();
|
| } else {
|
| - theirConstraints.moveNext();
|
| + theirRanges.moveNext();
|
| }
|
| }
|
|
|
| @@ -125,43 +87,42 @@ class VersionUnion implements VersionConstraint {
|
| }
|
|
|
| VersionConstraint intersect(VersionConstraint other) {
|
| - var ourConstraints = constraints.iterator;
|
| - var theirConstraints = _constraintsFor(other).iterator;
|
| + var ourRanges = ranges.iterator;
|
| + var theirRanges = _rangesFor(other).iterator;
|
|
|
| - // Because both lists of constraints are ordered by minimum version, we can
|
| + // Because both lists of ranges are ordered by minimum version, we can
|
| // safely move through them linearly here.
|
| - var newConstraints = <VersionRange>[];
|
| - ourConstraints.moveNext();
|
| - theirConstraints.moveNext();
|
| - while (ourConstraints.current != null && theirConstraints.current != null) {
|
| - var intersection = ourConstraints.current
|
| - .intersect(theirConstraints.current);
|
| + var newRanges = <VersionRange>[];
|
| + ourRanges.moveNext();
|
| + theirRanges.moveNext();
|
| + while (ourRanges.current != null && theirRanges.current != null) {
|
| + var intersection = ourRanges.current
|
| + .intersect(theirRanges.current);
|
|
|
| - if (!intersection.isEmpty) newConstraints.add(intersection);
|
| + if (!intersection.isEmpty) newRanges.add(intersection);
|
|
|
| // Move the constraint with the higher max value forward. This ensures
|
| // that we keep both lists in sync as much as possible, and that large
|
| - // constraints have a chance to match multiple small constraints that they
|
| - // contain.
|
| - if (compareMax(ourConstraints.current, theirConstraints.current) < 0) {
|
| - ourConstraints.moveNext();
|
| + // ranges have a chance to match multiple small ranges that they contain.
|
| + if (compareMax(ourRanges.current, theirRanges.current) < 0) {
|
| + ourRanges.moveNext();
|
| } else {
|
| - theirConstraints.moveNext();
|
| + theirRanges.moveNext();
|
| }
|
| }
|
|
|
| - if (newConstraints.isEmpty) return VersionConstraint.empty;
|
| - if (newConstraints.length == 1) return newConstraints.single;
|
| + if (newRanges.isEmpty) return VersionConstraint.empty;
|
| + if (newRanges.length == 1) return newRanges.single;
|
|
|
| - return new VersionUnion._(newConstraints);
|
| + return new VersionUnion.fromRanges(newRanges);
|
| }
|
|
|
| - /// Returns [constraint] as a list of constraints.
|
| + /// Returns [constraint] as a list of ranges.
|
| ///
|
| - /// This is used to normalize constraints of various types.
|
| - List<VersionRange> _constraintsFor(VersionConstraint constraint) {
|
| + /// This is used to normalize ranges of various types.
|
| + List<VersionRange> _rangesFor(VersionConstraint constraint) {
|
| if (constraint.isEmpty) return [];
|
| - if (constraint is VersionUnion) return constraint.constraints;
|
| + if (constraint is VersionUnion) return constraint.ranges;
|
| if (constraint is VersionRange) return [constraint];
|
| throw new ArgumentError('Unknown VersionConstraint type $constraint.');
|
| }
|
| @@ -171,10 +132,10 @@ class VersionUnion implements VersionConstraint {
|
|
|
| bool operator ==(other) {
|
| if (other is! VersionUnion) return false;
|
| - return const ListEquality().equals(constraints, other.constraints);
|
| + return const ListEquality().equals(ranges, other.ranges);
|
| }
|
|
|
| - int get hashCode => const ListEquality().hash(constraints);
|
| + int get hashCode => const ListEquality().hash(ranges);
|
|
|
| - String toString() => constraints.join(" or ");
|
| + String toString() => ranges.join(" or ");
|
| }
|
|
|