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

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

Issue 1448243002: Specialize Glob for the often case of suffix matching. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 1 month 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 | « no previous file | pkg/analyzer/test/src/util/glob_test.dart » ('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 library analyzer.src.util.glob; 5 library analyzer.src.util.glob;
6 6
7 /** 7 /**
8 * A pattern that matches against filesystem path-like strings with wildcards. 8 * A pattern that matches against filesystem path-like strings with wildcards.
9 * 9 *
10 * The pattern matches strings as follows: 10 * The pattern matches strings as follows:
(...skipping 10 matching lines...) Expand all
21 * as defined here: http://ecma-international.org/ecma-262/5.1/#sec-15.10 21 * as defined here: http://ecma-international.org/ecma-262/5.1/#sec-15.10
22 */ 22 */
23 static final RegExp _specialChars = 23 static final RegExp _specialChars =
24 new RegExp(r'([\\\^\$\.\|\+\[\]\(\)\{\}])'); 24 new RegExp(r'([\\\^\$\.\|\+\[\]\(\)\{\}])');
25 25
26 /** 26 /**
27 * The path separator used to separate components in file paths. 27 * The path separator used to separate components in file paths.
28 */ 28 */
29 final String _separator; 29 final String _separator;
30 30
31 final String pattern; 31 /**
32 final RegExp _regex; 32 * The pattern string.
33 */
34 final String _pattern;
33 35
34 Glob(this._separator, String pattern) 36 String _suffix;
35 : pattern = pattern, 37 RegExp _regex;
36 _regex = _regexpFromGlobPattern(pattern); 38
39 Glob(this._separator, this._pattern) {
40 if (_hasJustPrefix(_pattern, '**/*')) {
41 _suffix = _pattern.substring(4);
Brian Wilkerson 2015/11/17 14:54:07 Probably ought to use toLowerCase() for later matc
42 } else if (_hasJustPrefix(_pattern, '**')) {
43 _suffix = _pattern.substring(2);
44 } else {
45 _regex = _regexpFromGlobPattern(_pattern);
46 }
47 }
37 48
38 @override 49 @override
39 int get hashCode => pattern.hashCode; 50 int get hashCode => _pattern.hashCode;
40 51
41 bool operator ==(other) => other is Glob && pattern == other.pattern; 52 bool operator ==(other) => other is Glob && _pattern == other._pattern;
42 53
43 /** 54 /**
44 * Return `true` if the given [path] matches this glob. 55 * Return `true` if the given [path] matches this glob.
45 * The given [path] must use the same [_separator] as the glob. 56 * The given [path] must use the same [_separator] as the glob.
46 */ 57 */
47 bool matches(String path) { 58 bool matches(String path) {
48 String posixPath = _toPosixPath(path); 59 String posixPath = _toPosixPath(path);
60 if (_suffix != null) {
61 return posixPath.toLowerCase().endsWith(_suffix);
62 }
49 return _regex.matchAsPrefix(posixPath) != null; 63 return _regex.matchAsPrefix(posixPath) != null;
50 } 64 }
51 65
52 @override 66 @override
53 String toString() => pattern; 67 String toString() => _pattern;
54 68
55 /** 69 /**
56 * Return the Posix version of the given [path]. 70 * Return the Posix version of the given [path].
57 */ 71 */
58 String _toPosixPath(String path) { 72 String _toPosixPath(String path) {
59 if (_separator == '/') { 73 if (_separator == '/') {
60 return path; 74 return path;
61 } 75 }
62 return path.replaceAll(_separator, '/'); 76 return path.replaceAll(_separator, '/');
63 } 77 }
64 78
79 /**
80 * Return `true` if the [pattern] start with the given [prefix] and does
81 * not have `*` or `?` characters.
82 */
83 static bool _hasJustPrefix(String pattern, String prefix) {
84 if (pattern.startsWith(prefix)) {
85 int prefixLength = prefix.length;
86 return pattern.indexOf('*', prefixLength) == -1 &&
87 pattern.indexOf('?', prefixLength) == -1;
88 }
89 return false;
90 }
91
65 static RegExp _regexpFromGlobPattern(String pattern) { 92 static RegExp _regexpFromGlobPattern(String pattern) {
66 StringBuffer sb = new StringBuffer(); 93 StringBuffer sb = new StringBuffer();
67 sb.write('^'); 94 sb.write('^');
68 List<String> chars = pattern.split(''); 95 List<String> chars = pattern.split('');
69 for (int i = 0; i < chars.length; i++) { 96 for (int i = 0; i < chars.length; i++) {
70 String c = chars[i]; 97 String c = chars[i];
71 if (_specialChars.hasMatch(c)) { 98 if (_specialChars.hasMatch(c)) {
72 sb.write(r'\'); 99 sb.write(r'\');
73 sb.write(c); 100 sb.write(c);
74 } else if (c == '*') { 101 } else if (c == '*') {
75 if (i + 1 < chars.length && chars[i + 1] == '*') { 102 if (i + 1 < chars.length && chars[i + 1] == '*') {
76 sb.write('.*'); 103 sb.write('.*');
77 i++; 104 i++;
78 } else { 105 } else {
79 sb.write('[^/]*'); 106 sb.write('[^/]*');
80 } 107 }
81 } else if (c == '?') { 108 } else if (c == '?') {
82 sb.write('[^/]'); 109 sb.write('[^/]');
83 } else { 110 } else {
84 sb.write(c); 111 sb.write(c);
85 } 112 }
86 } 113 }
87 sb.write(r'$'); 114 sb.write(r'$');
88 return new RegExp(sb.toString(), caseSensitive: false); 115 return new RegExp(sb.toString(), caseSensitive: false);
89 } 116 }
90 } 117 }
OLDNEW
« no previous file with comments | « no previous file | pkg/analyzer/test/src/util/glob_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698