Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(530)

Side by Side Diff: lib/src/version_union.dart

Issue 2029263003: Make the VersionUnion class public. (Closed) Base URL: git@github.com:dart-lang/pub_semver@master
Patch Set: Created 4 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « lib/src/version_range.dart ('k') | pubspec.yaml » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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';
11 11
12 /// A (package-private) version constraint representing a union of multiple 12 /// A version constraint representing a union of multiple disjoint version
13 /// disjoint version constraints. 13 /// ranges.
14 /// 14 ///
15 /// An instance of this will only be created if the version can't be represented 15 /// An instance of this will only be created if the version can't be represented
16 /// as a non-compound value. 16 /// as a non-compound value.
17 class VersionUnion implements VersionConstraint { 17 class VersionUnion implements VersionConstraint {
18 /// The constraints that compose this union. 18 /// The constraints that compose this union.
19 /// 19 ///
20 /// This list has two invariants: 20 /// This list has two invariants:
21 /// 21 ///
22 /// * Its contents are sorted from lowest to highest matched versions. 22 /// * Its contents are sorted from lowest to highest matched versions.
23 /// * Its contents are disjoint and non-adjacent. In other words, for any two 23 /// * Its contents are disjoint and non-adjacent. In other words, for any two
24 /// constraints next to each other in the list, there's some version between 24 /// constraints next to each other in the list, there's some version between
25 /// those constraints that they don't match. 25 /// those constraints that they don't match.
26 final List<VersionRange> constraints; 26 final List<VersionRange> ranges;
27 27
28 bool get isEmpty => false; 28 bool get isEmpty => false;
29 29
30 bool get isAny => false; 30 bool get isAny => false;
31 31
32 /// Returns the union of [constraints]. 32 /// Creates a union from a list of ranges with no pre-processing.
33 /// 33 ///
34 /// This ensures that an actual [VersionUnion] is only returned if necessary. 34 /// It's up to the caller to ensure that the invariants described in [ranges]
35 /// It also takes care of sorting and merging the constraints to ensure that 35 /// are maintained. They are not verified by this constructor. To
36 /// they're disjoint. 36 /// automatically ensure that they're maintained, use [new
37 static VersionConstraint create(Iterable<VersionConstraint> constraints) { 37 /// VersionConstraint.unionOf] instead.
38 var flattened = constraints.expand((constraint) { 38 VersionUnion.fromRanges(this.ranges);
39 if (constraint.isEmpty) return [];
40 if (constraint is VersionUnion) return constraint.constraints;
41 return [constraint];
42 }).toList();
43 39
44 if (flattened.isEmpty) return VersionConstraint.empty; 40 bool allows(Version version) =>
41 ranges.any((constraint) => constraint.allows(version));
45 42
46 if (flattened.any((constraint) => constraint.isAny)) { 43 bool allowsAll(VersionConstraint other) {
47 return VersionConstraint.any; 44 var ourRanges = ranges.iterator;
48 } 45 var theirRanges = _rangesFor(other).iterator;
49 46
50 // Only allow Versions and VersionRanges here so we can more easily reason 47 // Because both lists of ranges are ordered by minimum version, we can
51 // about everything in [flattened]. _EmptyVersions and VersionUnions are 48 // safely move through them linearly here.
52 // filtered out above. 49 ourRanges.moveNext();
53 for (var constraint in flattened) { 50 theirRanges.moveNext();
54 if (constraint is VersionRange) continue; 51 while (ourRanges.current != null && theirRanges.current != null) {
55 throw new ArgumentError('Unknown VersionConstraint type $constraint.'); 52 if (ourRanges.current.allowsAll(theirRanges.current)) {
56 } 53 theirRanges.moveNext();
57
58 flattened.sort(compareMax);
59
60 var merged = <VersionRange>[];
61 for (var constraint in flattened) {
62 // Merge this constraint with the previous one, but only if they touch.
63 if (merged.isEmpty ||
64 (!merged.last.allowsAny(constraint) &&
65 !areAdjacent(merged.last, constraint))) {
66 merged.add(constraint);
67 } else { 54 } else {
68 merged[merged.length - 1] = merged.last.union(constraint); 55 ourRanges.moveNext();
69 } 56 }
70 } 57 }
71 58
72 if (merged.length == 1) return merged.single; 59 // If our ranges have allowed all of their ranges, we'll have consumed all
73 return new VersionUnion._(merged); 60 // of them.
74 } 61 return theirRanges.current == null;
75
76 VersionUnion._(this.constraints);
77
78 bool allows(Version version) =>
79 constraints.any((constraint) => constraint.allows(version));
80
81 bool allowsAll(VersionConstraint other) {
82 var ourConstraints = constraints.iterator;
83 var theirConstraints = _constraintsFor(other).iterator;
84
85 // Because both lists of constraints are ordered by minimum version, we can
86 // safely move through them linearly here.
87 ourConstraints.moveNext();
88 theirConstraints.moveNext();
89 while (ourConstraints.current != null && theirConstraints.current != null) {
90 if (ourConstraints.current.allowsAll(theirConstraints.current)) {
91 theirConstraints.moveNext();
92 } else {
93 ourConstraints.moveNext();
94 }
95 }
96
97 // If our constraints have allowed all of their constraints, we'll have
98 // consumed all of them.
99 return theirConstraints.current == null;
100 } 62 }
101 63
102 bool allowsAny(VersionConstraint other) { 64 bool allowsAny(VersionConstraint other) {
103 var ourConstraints = constraints.iterator; 65 var ourRanges = ranges.iterator;
104 var theirConstraints = _constraintsFor(other).iterator; 66 var theirRanges = _rangesFor(other).iterator;
105 67
106 // Because both lists of constraints are ordered by minimum version, we can 68 // Because both lists of ranges are ordered by minimum version, we can
107 // safely move through them linearly here. 69 // safely move through them linearly here.
108 ourConstraints.moveNext(); 70 ourRanges.moveNext();
109 theirConstraints.moveNext(); 71 theirRanges.moveNext();
110 while (ourConstraints.current != null && theirConstraints.current != null) { 72 while (ourRanges.current != null && theirRanges.current != null) {
111 if (ourConstraints.current.allowsAny(theirConstraints.current)) { 73 if (ourRanges.current.allowsAny(theirRanges.current)) {
112 return true; 74 return true;
113 } 75 }
114 76
115 // Move the constraint with the higher max value forward. This ensures 77 // Move the constraint with the higher max value forward. This ensures
116 // that we keep both lists in sync as much as possible. 78 // that we keep both lists in sync as much as possible.
117 if (compareMax(ourConstraints.current, theirConstraints.current) < 0) { 79 if (compareMax(ourRanges.current, theirRanges.current) < 0) {
118 ourConstraints.moveNext(); 80 ourRanges.moveNext();
119 } else { 81 } else {
120 theirConstraints.moveNext(); 82 theirRanges.moveNext();
121 } 83 }
122 } 84 }
123 85
124 return false; 86 return false;
125 } 87 }
126 88
127 VersionConstraint intersect(VersionConstraint other) { 89 VersionConstraint intersect(VersionConstraint other) {
128 var ourConstraints = constraints.iterator; 90 var ourRanges = ranges.iterator;
129 var theirConstraints = _constraintsFor(other).iterator; 91 var theirRanges = _rangesFor(other).iterator;
130 92
131 // Because both lists of constraints are ordered by minimum version, we can 93 // Because both lists of ranges are ordered by minimum version, we can
132 // safely move through them linearly here. 94 // safely move through them linearly here.
133 var newConstraints = <VersionRange>[]; 95 var newRanges = <VersionRange>[];
134 ourConstraints.moveNext(); 96 ourRanges.moveNext();
135 theirConstraints.moveNext(); 97 theirRanges.moveNext();
136 while (ourConstraints.current != null && theirConstraints.current != null) { 98 while (ourRanges.current != null && theirRanges.current != null) {
137 var intersection = ourConstraints.current 99 var intersection = ourRanges.current
138 .intersect(theirConstraints.current); 100 .intersect(theirRanges.current);
139 101
140 if (!intersection.isEmpty) newConstraints.add(intersection); 102 if (!intersection.isEmpty) newRanges.add(intersection);
141 103
142 // Move the constraint with the higher max value forward. This ensures 104 // Move the constraint with the higher max value forward. This ensures
143 // that we keep both lists in sync as much as possible, and that large 105 // that we keep both lists in sync as much as possible, and that large
144 // constraints have a chance to match multiple small constraints that they 106 // ranges have a chance to match multiple small ranges that they contain.
145 // contain. 107 if (compareMax(ourRanges.current, theirRanges.current) < 0) {
146 if (compareMax(ourConstraints.current, theirConstraints.current) < 0) { 108 ourRanges.moveNext();
147 ourConstraints.moveNext();
148 } else { 109 } else {
149 theirConstraints.moveNext(); 110 theirRanges.moveNext();
150 } 111 }
151 } 112 }
152 113
153 if (newConstraints.isEmpty) return VersionConstraint.empty; 114 if (newRanges.isEmpty) return VersionConstraint.empty;
154 if (newConstraints.length == 1) return newConstraints.single; 115 if (newRanges.length == 1) return newRanges.single;
155 116
156 return new VersionUnion._(newConstraints); 117 return new VersionUnion.fromRanges(newRanges);
157 } 118 }
158 119
159 /// Returns [constraint] as a list of constraints. 120 /// Returns [constraint] as a list of ranges.
160 /// 121 ///
161 /// This is used to normalize constraints of various types. 122 /// This is used to normalize ranges of various types.
162 List<VersionRange> _constraintsFor(VersionConstraint constraint) { 123 List<VersionRange> _rangesFor(VersionConstraint constraint) {
163 if (constraint.isEmpty) return []; 124 if (constraint.isEmpty) return [];
164 if (constraint is VersionUnion) return constraint.constraints; 125 if (constraint is VersionUnion) return constraint.ranges;
165 if (constraint is VersionRange) return [constraint]; 126 if (constraint is VersionRange) return [constraint];
166 throw new ArgumentError('Unknown VersionConstraint type $constraint.'); 127 throw new ArgumentError('Unknown VersionConstraint type $constraint.');
167 } 128 }
168 129
169 VersionConstraint union(VersionConstraint other) => 130 VersionConstraint union(VersionConstraint other) =>
170 new VersionConstraint.unionOf([this, other]); 131 new VersionConstraint.unionOf([this, other]);
171 132
172 bool operator ==(other) { 133 bool operator ==(other) {
173 if (other is! VersionUnion) return false; 134 if (other is! VersionUnion) return false;
174 return const ListEquality().equals(constraints, other.constraints); 135 return const ListEquality().equals(ranges, other.ranges);
175 } 136 }
176 137
177 int get hashCode => const ListEquality().hash(constraints); 138 int get hashCode => const ListEquality().hash(ranges);
178 139
179 String toString() => constraints.join(" or "); 140 String toString() => ranges.join(" or ");
180 } 141 }
OLDNEW
« no previous file with comments | « lib/src/version_range.dart ('k') | pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698