| OLD | NEW |
| 1 // Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file | 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 | 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 'dart:collection'; | 5 import 'dart:collection'; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * Implementation of [Uri] that understands only a limited set of valid | 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 | 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. | 10 * limited URI format, so almost always can be processed fast. |
| 11 */ | 11 */ |
| 12 class FastUri implements Uri { | 12 class FastUri implements Uri { |
| 13 /*** | 13 /*** |
| 14 * The maximum [_cache] length before we flush it and start a new generation. | 14 * The maximum [_cache] length before we flush it and start a new generation. |
| 15 */ | 15 */ |
| 16 static const int _MAX_CACHE_LENGTH_BEFORE_FLUSH = 50000; | 16 static const int _MAX_CACHE_LENGTH_BEFORE_FLUSH = 50000; |
| 17 | 17 |
| 18 static HashMap<String, Uri> _cache = new HashMap<String, Uri>(); | 18 static HashMap<String, Uri> _cache = new HashMap<String, Uri>(); |
| 19 static int _currentCacheLength = 0; | 19 static int _currentCacheLength = 0; |
| 20 static int _currentCacheGeneration = 0; | 20 static int _currentCacheGeneration = 0; |
| 21 | 21 |
| 22 static bool _hashUsingText = _shouldComputeHashCodeUsingText(); |
| 23 |
| 22 final int _cacheGeneration; | 24 final int _cacheGeneration; |
| 23 final String _text; | 25 final String _text; |
| 24 final String _scheme; | 26 final String _scheme; |
| 25 final bool _hasEmptyAuthority; | 27 final bool _hasEmptyAuthority; |
| 26 final String _path; | 28 final String _path; |
| 27 | 29 |
| 28 /** | 30 /** |
| 29 * The offset of the last `/` in [_text], or `null` if there isn't any. | 31 * The offset of the last `/` in [_text], or `null` if there isn't any. |
| 30 */ | 32 */ |
| 31 final int _lastSlashIndex; | 33 final int _lastSlashIndex; |
| 32 | 34 |
| 35 /** |
| 36 * The cached hash code. |
| 37 */ |
| 38 int _hashCode; |
| 39 |
| 33 Uri _cachedFallbackUri; | 40 Uri _cachedFallbackUri; |
| 34 | 41 |
| 35 FastUri._(this._cacheGeneration, this._text, this._scheme, | 42 FastUri._(this._cacheGeneration, this._text, this._scheme, |
| 36 this._hasEmptyAuthority, this._path, this._lastSlashIndex); | 43 this._hasEmptyAuthority, this._path, this._lastSlashIndex); |
| 37 | 44 |
| 38 @override | 45 @override |
| 39 String get authority => ''; | 46 String get authority => ''; |
| 40 | 47 |
| 41 @override | 48 @override |
| 42 UriData get data => null; | 49 UriData get data => null; |
| 43 | 50 |
| 44 @override | 51 @override |
| 45 String get fragment => ''; | 52 String get fragment => ''; |
| 46 | 53 |
| 47 @override | 54 @override |
| 48 bool get hasAbsolutePath => path.startsWith('/'); | 55 bool get hasAbsolutePath => path.startsWith('/'); |
| 49 | 56 |
| 50 @override | 57 @override |
| 51 bool get hasAuthority => _hasEmptyAuthority; | 58 bool get hasAuthority => _hasEmptyAuthority; |
| 52 | 59 |
| 53 @override | 60 @override |
| 54 bool get hasEmptyPath => _path.isEmpty; | 61 bool get hasEmptyPath => _path.isEmpty; |
| 55 | 62 |
| 56 @override | 63 @override |
| 57 bool get hasFragment => false; | 64 bool get hasFragment => false; |
| 58 | 65 |
| 59 @override | 66 @override |
| 60 int get hashCode => _text.hashCode; | 67 int get hashCode { |
| 68 return _hashCode ??= _hashUsingText |
| 69 ? _computeHashUsingText(this) |
| 70 : _computeHashUsingCombine(this); |
| 71 } |
| 61 | 72 |
| 62 @override | 73 @override |
| 63 bool get hasPort => false; | 74 bool get hasPort => false; |
| 64 | 75 |
| 65 @override | 76 @override |
| 66 bool get hasQuery => false; | 77 bool get hasQuery => false; |
| 67 | 78 |
| 68 @override | 79 @override |
| 69 bool get hasScheme => _scheme.isNotEmpty; | 80 bool get hasScheme => _scheme.isNotEmpty; |
| 70 | 81 |
| (...skipping 139 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 210 // If the cache is too big, start a new generation. | 221 // If the cache is too big, start a new generation. |
| 211 if (_currentCacheLength > _MAX_CACHE_LENGTH_BEFORE_FLUSH) { | 222 if (_currentCacheLength > _MAX_CACHE_LENGTH_BEFORE_FLUSH) { |
| 212 _cache.clear(); | 223 _cache.clear(); |
| 213 _currentCacheLength = 0; | 224 _currentCacheLength = 0; |
| 214 _currentCacheGeneration++; | 225 _currentCacheGeneration++; |
| 215 } | 226 } |
| 216 } | 227 } |
| 217 return uri; | 228 return uri; |
| 218 } | 229 } |
| 219 | 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 |
| 220 static bool _isAlphabetic(int char) { | 263 static bool _isAlphabetic(int char) { |
| 221 return char >= 'A'.codeUnitAt(0) && char <= 'Z'.codeUnitAt(0) || | 264 return char >= 'A'.codeUnitAt(0) && char <= 'Z'.codeUnitAt(0) || |
| 222 char >= 'a'.codeUnitAt(0) && char <= 'z'.codeUnitAt(0); | 265 char >= 'a'.codeUnitAt(0) && char <= 'z'.codeUnitAt(0); |
| 223 } | 266 } |
| 224 | 267 |
| 225 static bool _isDigit(int char) { | 268 static bool _isDigit(int char) { |
| 226 return char >= '0'.codeUnitAt(0) && char <= '9'.codeUnitAt(0); | 269 return char >= '0'.codeUnitAt(0) && char <= '9'.codeUnitAt(0); |
| 227 } | 270 } |
| 228 | 271 |
| 229 /** | 272 /** |
| (...skipping 30 matching lines...) Expand all Loading... |
| 260 if (path.startsWith('//')) { | 303 if (path.startsWith('//')) { |
| 261 hasEmptyAuthority = true; | 304 hasEmptyAuthority = true; |
| 262 path = path.substring(2); | 305 path = path.substring(2); |
| 263 if (!path.startsWith('/')) { | 306 if (!path.startsWith('/')) { |
| 264 return null; | 307 return null; |
| 265 } | 308 } |
| 266 } | 309 } |
| 267 return new FastUri._(_currentCacheGeneration, text, scheme, | 310 return new FastUri._(_currentCacheGeneration, text, scheme, |
| 268 hasEmptyAuthority, path, lastSlashIndex); | 311 hasEmptyAuthority, path, lastSlashIndex); |
| 269 } | 312 } |
| 313 |
| 314 /** |
| 315 * Determine whether VM has the text based hash code computation in [Uri], |
| 316 * or the old combine style. |
| 317 */ |
| 318 static bool _shouldComputeHashCodeUsingText() { |
| 319 String text = 'package:foo/foo.dart'; |
| 320 return Uri.parse(text).hashCode == text.hashCode; |
| 321 } |
| 270 } | 322 } |
| OLD | NEW |