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

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

Issue 2003633002: Use FastUri instead of Uri in analyzer. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Fixes for review comments. Created 4 years, 7 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
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 static HashMap<String, Uri> _cache = new HashMap<String, Uri>();
14
15 final String _text;
16 final String _scheme;
17 final String _path;
18
19 /**
20 * The offset of the last `/` in [_text], or `null` if there isn't any.
21 */
22 final int _lastSlashIndex;
23
24 /**
25 * The cached hashcode.
26 */
27 int _hashCode;
28
29 Uri _cachedFallbackUri;
30
31 FastUri(this._text, this._scheme, this._path, this._lastSlashIndex);
32
33 @override
34 String get authority => '';
35
36 @override
37 UriData get data => null;
38
39 @override
40 String get fragment => '';
41
42 @override
43 bool get hasAbsolutePath => path.startsWith('/');
44
45 @override
46 bool get hasAuthority => false;
47
48 @override
49 bool get hasEmptyPath => _path.isEmpty;
50
51 @override
52 bool get hasFragment => false;
53
54 @override
55 int get hashCode {
56 _hashCode ??= (scheme.hashCode * 31 + path.hashCode) & 0x3FFFFFFF;
57 return _hashCode;
58 }
59
60 @override
61 bool get hasPort => false;
62
63 @override
64 bool get hasQuery => false;
65
66 @override
67 bool get hasScheme => _scheme.isNotEmpty;
68
69 @override
70 String get host => '';
71
72 @override
73 bool get isAbsolute => hasScheme;
74
75 @override
76 String get origin => _fallbackUri.origin;
77
78 @override
79 String get path => _path;
80
81 @override
82 List<String> get pathSegments => _fallbackUri.pathSegments;
83
84 @override
85 int get port => 0;
86
87 @override
88 String get query => '';
89
90 @override
91 Map<String, String> get queryParameters => const <String, String>{};
92
93 @override
94 Map<String, List<String>> get queryParametersAll =>
95 const <String, List<String>>{};
96
97 @override
98 String get scheme => _scheme;
99
100 @override
101 String get userInfo => '';
102
103 /**
104 * Full [Uri] object computed on demand; we fall back to this for some of the
105 * more complex methods of [Uri] that are less in need of a fast
106 * implementation.
107 */
108 Uri get _fallbackUri => _cachedFallbackUri ??= Uri.parse(_text);
109
110 @override
111 bool operator ==(other) {
112 if (other is Uri) {
113 if (other is FastUri) {
Brian Wilkerson 2016/05/20 16:56:54 Won't this be the more common case? If so, it migh
114 return _text == other._text;
115 }
116 return _fallbackUri == other;
117 }
118 return false;
119 }
120
121 @override
122 Uri normalizePath() {
123 return this;
124 }
125
126 @override
127 Uri removeFragment() {
128 return this;
129 }
130
131 @override
132 Uri replace(
133 {String scheme,
134 String userInfo,
135 String host,
136 int port,
137 String path,
138 Iterable<String> pathSegments,
139 String query,
140 Map<String, dynamic> queryParameters,
141 String fragment}) {
142 return _fallbackUri.replace(
143 scheme: scheme,
144 userInfo: userInfo,
145 host: host,
146 port: port,
147 path: path,
148 pathSegments: pathSegments,
149 query: query,
150 queryParameters: queryParameters,
151 fragment: fragment);
152 }
153
154 @override
155 Uri resolve(String reference) {
156 // TODO: maybe implement faster
157 return _fallbackUri.resolve(reference);
158 }
159
160 @override
161 Uri resolveUri(Uri reference) {
162 if (reference.hasScheme) {
163 return reference;
164 }
165 String refPath = reference.path;
166 if (refPath.startsWith('./')) {
167 refPath = refPath.substring(2);
168 }
169 if (refPath.startsWith('../') ||
170 refPath.contains('/../') ||
171 refPath.contains('/./')) {
172 Uri slowResult = _fallbackUri.resolveUri(reference);
173 return FastUri.parse(slowResult.toString());
174 }
175 String newText;
176 if (_lastSlashIndex != null) {
177 newText = _text.substring(0, _lastSlashIndex + 1) + refPath;
178 } else {
179 newText = _text + '/' + refPath;
180 }
181 return FastUri.parse(newText);
182 }
183
184 @override
185 String toFilePath({bool windows}) {
186 return _fallbackUri.toFilePath(windows: windows);
187 }
188
189 @override
190 String toString() => _text;
191
192 /**
193 * Parse the given URI [text] and return the corresponding [Uri] instance. If
194 * the [text] can be represented as a [FastUri], then it is returned. If the
195 * [text] is more complex, then `dart:core` [Uri] is created and returned.
196 * This method also performs memoization, so that usually the same instance
Paul Berry 2016/05/20 16:50:39 Why "usually"? From the implementation it looks l
197 * of [FastUri] or [Uri] is returned for the same [text].
198 */
199 static Uri parse(String text) {
200 Uri uri = _cache[text];
201 if (uri == null) {
202 uri = _parse(text);
203 uri ??= Uri.parse(text);
204 _cache[text] = uri;
205 }
206 return uri;
207 }
208
209 static bool _isAlphabetic(int char) {
210 return char >= 'A'.codeUnitAt(0) && char <= 'Z'.codeUnitAt(0) ||
211 char >= 'a'.codeUnitAt(0) && char <= 'z'.codeUnitAt(0);
212 }
213
214 static bool _isDigit(int char) {
215 return char >= '0'.codeUnitAt(0) && char <= '9'.codeUnitAt(0);
216 }
217
218 /**
219 * Parse the given [text] into a new [FastUri]. If the [text] uses URI
220 * features that are not supported by [FastUri], return `null`.
221 */
222 static FastUri _parse(String text) {
223 int schemeEnd = null;
224 int pathStart = 0;
225 int lastSlashIndex = null;
226 for (int i = 0; i < text.length; i++) {
227 int char = text.codeUnitAt(i);
228 if (_isAlphabetic(char) ||
229 _isDigit(char) ||
230 char == '.'.codeUnitAt(0) ||
231 char == '-'.codeUnitAt(0) ||
232 char == '_'.codeUnitAt(0)) {
233 // Valid characters.
234 } else if (char == '/'.codeUnitAt(0)) {
235 lastSlashIndex = i;
236 } else if (char == ':'.codeUnitAt(0)) {
237 if (schemeEnd != null) {
238 return null;
239 }
240 schemeEnd = i;
241 pathStart = i + 1;
242 } else {
243 return null;
244 }
245 }
246 String scheme = schemeEnd != null ? text.substring(0, schemeEnd) : '';
247 String path = text.substring(pathStart);
248 if (path.startsWith('//')) {
249 path = path.substring(2);
250 }
251 return new FastUri(text, scheme, path, lastSlashIndex);
252 }
253 }
OLDNEW
« no previous file with comments | « pkg/analyzer/lib/src/generated/utilities_dart.dart ('k') | pkg/analyzer/test/generated/analysis_context_factory.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698