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

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

Issue 1455003002: Optimize absolute() and normalize(). (Closed) Base URL: git@github.com:dart-lang/path@master
Patch Set: Code review changes 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 | « benchmark/benchmark.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) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, 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 path.context; 5 library path.context;
6 6
7 import 'characters.dart' as chars;
7 import 'internal_style.dart'; 8 import 'internal_style.dart';
8 import 'style.dart'; 9 import 'style.dart';
9 import 'parsed_path.dart'; 10 import 'parsed_path.dart';
10 import 'path_exception.dart'; 11 import 'path_exception.dart';
11 import '../path.dart' as p; 12 import '../path.dart' as p;
12 13
13 Context createInternal() => new Context._internal(); 14 Context createInternal() => new Context._internal();
14 15
15 /// An instantiable class for manipulating paths. Unlike the top-level 16 /// An instantiable class for manipulating paths. Unlike the top-level
16 /// functions, this lets you explicitly select what platform the paths will use. 17 /// functions, this lets you explicitly select what platform the paths will use.
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
66 67
67 /// Creates a new path by appending the given path parts to [current]. 68 /// Creates a new path by appending the given path parts to [current].
68 /// Equivalent to [join()] with [current] as the first argument. Example: 69 /// Equivalent to [join()] with [current] as the first argument. Example:
69 /// 70 ///
70 /// var context = new Context(current: '/root'); 71 /// var context = new Context(current: '/root');
71 /// context.absolute('path', 'to', 'foo'); // -> '/root/path/to/foo' 72 /// context.absolute('path', 'to', 'foo'); // -> '/root/path/to/foo'
72 /// 73 ///
73 /// If [current] isn't absolute, this won't return an absolute path. 74 /// If [current] isn't absolute, this won't return an absolute path.
74 String absolute(String part1, [String part2, String part3, String part4, 75 String absolute(String part1, [String part2, String part3, String part4,
75 String part5, String part6, String part7]) { 76 String part5, String part6, String part7]) {
77 _validateArgList(
78 "absolute", [part1, part2, part3, part4, part5, part6, part7]);
79
80 // If there's a single absolute path, just return it. This is a lot faster
81 // for the common case of `p.absolute(path)`.
82 if (part2 == null && isAbsolute(part1) && !isRootRelative(part1)) {
83 return part1;
84 }
85
76 return join(current, part1, part2, part3, part4, part5, part6, part7); 86 return join(current, part1, part2, part3, part4, part5, part6, part7);
77 } 87 }
78 88
79 /// Gets the part of [path] after the last separator on the context's 89 /// Gets the part of [path] after the last separator on the context's
80 /// platform. 90 /// platform.
81 /// 91 ///
82 /// context.basename('path/to/foo.dart'); // -> 'foo.dart' 92 /// context.basename('path/to/foo.dart'); // -> 'foo.dart'
83 /// context.basename('path/to'); // -> 'to' 93 /// context.basename('path/to'); // -> 'to'
84 /// 94 ///
85 /// Trailing separators are ignored. 95 /// Trailing separators are ignored.
(...skipping 202 matching lines...) Expand 10 before | Expand all | Expand 10 after
288 parsed.parts = parsed.parts.where((part) => !part.isEmpty).toList(); 298 parsed.parts = parsed.parts.where((part) => !part.isEmpty).toList();
289 if (parsed.root != null) parsed.parts.insert(0, parsed.root); 299 if (parsed.root != null) parsed.parts.insert(0, parsed.root);
290 return parsed.parts; 300 return parsed.parts;
291 } 301 }
292 302
293 /// Normalizes [path], simplifying it by handling `..`, and `.`, and 303 /// Normalizes [path], simplifying it by handling `..`, and `.`, and
294 /// removing redundant path separators whenever possible. 304 /// removing redundant path separators whenever possible.
295 /// 305 ///
296 /// context.normalize('path/./to/..//file.text'); // -> 'path/file.txt' 306 /// context.normalize('path/./to/..//file.text'); // -> 'path/file.txt'
297 String normalize(String path) { 307 String normalize(String path) {
308 if (!_needsNormalization(path)) return path;
309
298 var parsed = _parse(path); 310 var parsed = _parse(path);
299 parsed.normalize(); 311 parsed.normalize();
300 return parsed.toString(); 312 return parsed.toString();
301 } 313 }
302 314
315 /// Returns whether [path] needs to be normalized.
316 bool _needsNormalization(String path) {
317 var start = 0;
318 var codeUnits = path.codeUnits;
319 var previousPrevious;
320 var previous;
321
322 // Skip past the root before we start looking for snippets that need
323 // normalization. We want to normalize "//", but not when it's part of
324 // "http://".
325 var root = style.rootLength(path);
326 if (root != 0) {
327 start = root;
328 previous = chars.SLASH;
329
330 // On Windows, the root still needs to be normalized if it contains a
331 // forward slash.
332 if (style == Style.windows) {
333 for (var i = 0; i < root; i++) {
334 if (codeUnits[i] == chars.SLASH) return true;
335 }
336 }
337 }
338
339 for (var i = start; i < codeUnits.length; i++) {
340 var codeUnit = codeUnits[i];
341 if (style.isSeparator(codeUnit)) {
342 // Forward slashes in Windows paths are normalized to backslashes.
343 if (style == Style.windows && codeUnit == chars.SLASH) return true;
344
345 // Multiple separators are normalized to single separators.
346 if (previous != null && style.isSeparator(previous)) return true;
347
348 // Single dots and double dots are normalized to directory traversals.
349 //
350 // This can return false positives for ".../", but that's unlikely
351 // enough that it's probably not going to cause performance issues.
352 if (previous == chars.PERIOD &&
353 (previousPrevious == null ||
354 previousPrevious == chars.PERIOD ||
355 style.isSeparator(previousPrevious))) {
356 return true;
357 }
358 }
359
360 previousPrevious = previous;
361 previous = codeUnit;
362 }
363
364 // Empty paths are normalized to ".".
365 if (previous == null) return true;
366
367 // Trailing separators are removed.
368 if (style.isSeparator(previous)) return true;
369
370 // Single dots and double dots are normalized to directory traversals.
371 if (previous == chars.PERIOD &&
372 (previousPrevious == null ||
373 previousPrevious == chars.SLASH ||
374 previousPrevious == chars.PERIOD)) {
375 return true;
376 }
377
378 return false;
379 }
380
303 /// Attempts to convert [path] to an equivalent relative path relative to 381 /// Attempts to convert [path] to an equivalent relative path relative to
304 /// [root]. 382 /// [root].
305 /// 383 ///
306 /// var context = new Context(current: '/root/path'); 384 /// var context = new Context(current: '/root/path');
307 /// context.relative('/root/path/a/b.dart'); // -> 'a/b.dart' 385 /// context.relative('/root/path/a/b.dart'); // -> 'a/b.dart'
308 /// context.relative('/root/other.dart'); // -> '../other.dart' 386 /// context.relative('/root/other.dart'); // -> '../other.dart'
309 /// 387 ///
310 /// If the [from] argument is passed, [path] is made relative to that instead. 388 /// If the [from] argument is passed, [path] is made relative to that instead.
311 /// 389 ///
312 /// context.relative('/root/path/a/b.dart', 390 /// context.relative('/root/path/a/b.dart',
(...skipping 252 matching lines...) Expand 10 before | Expand all | Expand 10 after
565 var message = new StringBuffer(); 643 var message = new StringBuffer();
566 message.write("$method("); 644 message.write("$method(");
567 message.write(args 645 message.write(args
568 .take(numArgs) 646 .take(numArgs)
569 .map((arg) => arg == null ? "null" : '"$arg"') 647 .map((arg) => arg == null ? "null" : '"$arg"')
570 .join(", ")); 648 .join(", "));
571 message.write("): part ${i - 1} was null, but part $i was not."); 649 message.write("): part ${i - 1} was null, but part $i was not.");
572 throw new ArgumentError(message.toString()); 650 throw new ArgumentError(message.toString());
573 } 651 }
574 } 652 }
OLDNEW
« no previous file with comments | « benchmark/benchmark.dart ('k') | pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698