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

Side by Side Diff: packages/analyzer/lib/src/util/fast_uri.dart

Issue 2990843002: Removed fixed dependencies (Closed)
Patch Set: Created 3 years, 4 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 | « packages/analyzer/lib/src/util/asserts.dart ('k') | packages/analyzer/lib/src/util/glob.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
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.
4
5 import 'dart:collection';
6
7 /**
8 * Implementation of [Uri] that understands only a limited set of valid
9 * URI formats, but works fast. In practice Dart code almost always uses such
10 * limited URI format, so almost always can be processed fast.
11 */
12 class FastUri implements Uri {
13 /***
14 * The maximum [_cache] length before we flush it and start a new generation.
15 */
16 static const int _MAX_CACHE_LENGTH_BEFORE_FLUSH = 50000;
17
18 static HashMap<String, Uri> _cache = new HashMap<String, Uri>();
19 static int _currentCacheLength = 0;
20 static int _currentCacheGeneration = 0;
21
22 static bool _hashUsingText = _shouldComputeHashCodeUsingText();
23
24 final int _cacheGeneration;
25 final String _text;
26 final String _scheme;
27 final bool _hasEmptyAuthority;
28 final String _path;
29
30 /**
31 * The offset of the last `/` in [_text], or `null` if there isn't any.
32 */
33 final int _lastSlashIndex;
34
35 /**
36 * The cached hash code.
37 */
38 int _hashCode;
39
40 Uri _cachedFallbackUri;
41
42 FastUri._(this._cacheGeneration, this._text, this._scheme,
43 this._hasEmptyAuthority, this._path, this._lastSlashIndex);
44
45 @override
46 String get authority => '';
47
48 @override
49 UriData get data => null;
50
51 @override
52 String get fragment => '';
53
54 @override
55 bool get hasAbsolutePath => path.startsWith('/');
56
57 @override
58 bool get hasAuthority => _hasEmptyAuthority;
59
60 @override
61 bool get hasEmptyPath => _path.isEmpty;
62
63 @override
64 bool get hasFragment => false;
65
66 @override
67 int get hashCode {
68 return _hashCode ??= _hashUsingText
69 ? _computeHashUsingText(this)
70 : _computeHashUsingCombine(this);
71 }
72
73 @override
74 bool get hasPort => false;
75
76 @override
77 bool get hasQuery => false;
78
79 @override
80 bool get hasScheme => _scheme.isNotEmpty;
81
82 @override
83 String get host => '';
84
85 @override
86 bool get isAbsolute => hasScheme;
87
88 @override
89 String get origin => _fallbackUri.origin;
90
91 @override
92 String get path => _path;
93
94 @override
95 List<String> get pathSegments => _fallbackUri.pathSegments;
96
97 @override
98 int get port => 0;
99
100 @override
101 String get query => '';
102
103 @override
104 Map<String, String> get queryParameters => const <String, String>{};
105
106 @override
107 Map<String, List<String>> get queryParametersAll =>
108 const <String, List<String>>{};
109
110 @override
111 String get scheme => _scheme;
112
113 @override
114 String get userInfo => '';
115
116 /**
117 * Full [Uri] object computed on demand; we fall back to this for some of the
118 * more complex methods of [Uri] that are less in need of a fast
119 * implementation.
120 */
121 Uri get _fallbackUri => _cachedFallbackUri ??= Uri.parse(_text);
122
123 @override
124 bool operator ==(other) {
125 if (other is FastUri) {
126 if (other._cacheGeneration == _cacheGeneration) {
127 return identical(other, this);
128 }
129 return _text == other._text;
130 } else if (other is Uri) {
131 return _fallbackUri == other;
132 }
133 return false;
134 }
135
136 @override
137 Uri normalizePath() {
138 return this;
139 }
140
141 @override
142 Uri removeFragment() {
143 return this;
144 }
145
146 @override
147 Uri replace(
148 {String scheme,
149 String userInfo,
150 String host,
151 int port,
152 String path,
153 Iterable<String> pathSegments,
154 String query,
155 Map<String, dynamic> queryParameters,
156 String fragment}) {
157 return _fallbackUri.replace(
158 scheme: scheme,
159 userInfo: userInfo,
160 host: host,
161 port: port,
162 path: path,
163 pathSegments: pathSegments,
164 query: query,
165 queryParameters: queryParameters,
166 fragment: fragment);
167 }
168
169 @override
170 Uri resolve(String reference) {
171 // TODO: maybe implement faster
172 return _fallbackUri.resolve(reference);
173 }
174
175 @override
176 Uri resolveUri(Uri reference) {
177 if (reference.hasScheme) {
178 return reference;
179 }
180 String refPath = reference.path;
181 if (refPath.startsWith('./')) {
182 refPath = refPath.substring(2);
183 }
184 if (refPath.startsWith('../') ||
185 refPath.contains('/../') ||
186 refPath.contains('/./')) {
187 Uri slowResult = _fallbackUri.resolveUri(reference);
188 return FastUri.parse(slowResult.toString());
189 }
190 String newText;
191 if (_lastSlashIndex != null) {
192 newText = _text.substring(0, _lastSlashIndex + 1) + refPath;
193 } else {
194 newText = _text + '/' + refPath;
195 }
196 return FastUri.parse(newText);
197 }
198
199 @override
200 String toFilePath({bool windows}) {
201 return _fallbackUri.toFilePath(windows: windows);
202 }
203
204 @override
205 String toString() => _text;
206
207 /**
208 * Parse the given URI [text] and return the corresponding [Uri] instance. If
209 * the [text] can be represented as a [FastUri], then it is returned. If the
210 * [text] is more complex, then `dart:core` [Uri] is created and returned.
211 * This method also performs memoization, so that usually the same instance
212 * of [FastUri] or [Uri] is returned for the same [text].
213 */
214 static Uri parse(String text) {
215 Uri uri = _cache[text];
216 if (uri == null) {
217 uri = _parse(text);
218 uri ??= Uri.parse(text);
219 _cache[text] = uri;
220 _currentCacheLength++;
221 // If the cache is too big, start a new generation.
222 if (_currentCacheLength > _MAX_CACHE_LENGTH_BEFORE_FLUSH) {
223 _cache.clear();
224 _currentCacheLength = 0;
225 _currentCacheGeneration++;
226 }
227 }
228 return uri;
229 }
230
231 /**
232 * This implementation was used before 'fast-URI' in Dart VM.
233 */
234 static int _computeHashUsingCombine(FastUri uri) {
235 // This code is copied from the standard Uri implementation.
236 // It is important that Uri and FastUri generate compatible hashCodes
237 // because Uri and FastUri may be used as keys in the same map.
238 int combine(part, current) {
239 // The sum is truncated to 30 bits to make sure it fits into a Smi.
240 return (current * 31 + part.hashCode) & 0x3FFFFFFF;
241 }
242
243 return combine(
244 uri.scheme,
245 combine(
246 uri.userInfo,
247 combine(
248 uri.host,
249 combine(
250 uri.port,
251 combine(uri.path,
252 combine(uri.query, combine(uri.fragment, 1)))))));
253 }
254
255 /**
256 * This implementation should be used with 'fast-URI' in Dart VM.
257 * https://github.com/dart-lang/sdk/commit/afbbbb97cfcd86a64d0ba5dcfe1ab758954 adaf4
258 */
259 static int _computeHashUsingText(FastUri uri) {
260 return uri._text.hashCode;
261 }
262
263 static bool _isAlphabetic(int char) {
264 return char >= 'A'.codeUnitAt(0) && char <= 'Z'.codeUnitAt(0) ||
265 char >= 'a'.codeUnitAt(0) && char <= 'z'.codeUnitAt(0);
266 }
267
268 static bool _isDigit(int char) {
269 return char >= '0'.codeUnitAt(0) && char <= '9'.codeUnitAt(0);
270 }
271
272 /**
273 * Parse the given [text] into a new [FastUri]. If the [text] uses URI
274 * features that are not supported by [FastUri], return `null`.
275 */
276 static FastUri _parse(String text) {
277 int schemeEnd = null;
278 int pathStart = 0;
279 int lastSlashIndex = null;
280 for (int i = 0; i < text.length; i++) {
281 int char = text.codeUnitAt(i);
282 if (_isAlphabetic(char) ||
283 _isDigit(char) ||
284 char == '.'.codeUnitAt(0) ||
285 char == '-'.codeUnitAt(0) ||
286 char == '_'.codeUnitAt(0)) {
287 // Valid characters.
288 } else if (char == '/'.codeUnitAt(0)) {
289 lastSlashIndex = i;
290 } else if (char == ':'.codeUnitAt(0)) {
291 if (schemeEnd != null) {
292 return null;
293 }
294 schemeEnd = i;
295 pathStart = i + 1;
296 } else {
297 return null;
298 }
299 }
300 String scheme = schemeEnd != null ? text.substring(0, schemeEnd) : '';
301 bool hasEmptyAuthority = false;
302 String path = text.substring(pathStart);
303 if (path.startsWith('//')) {
304 hasEmptyAuthority = true;
305 path = path.substring(2);
306 if (!path.startsWith('/')) {
307 return null;
308 }
309 }
310 return new FastUri._(_currentCacheGeneration, text, scheme,
311 hasEmptyAuthority, path, lastSlashIndex);
312 }
313
314 /**
315 * Determine whether VM has the text based hash code computation in [Uri],
316 * or the old combine style.
317 *
318 * See https://github.com/dart-lang/sdk/issues/27159 for details.
319 */
320 static bool _shouldComputeHashCodeUsingText() {
321 String text = 'package:foo/foo.dart';
322 return Uri.parse(text).hashCode == text.hashCode;
323 }
324 }
OLDNEW
« no previous file with comments | « packages/analyzer/lib/src/util/asserts.dart ('k') | packages/analyzer/lib/src/util/glob.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698