Cache the current working directory.
Recomputing this isn't terribly expensive, but it happens a lot so it's
nice to avoid.
Also avoid calling it in relative() when the path is already relative.
This brings current from about 0.070 iterations/us to about 0.097, and relative from about 0.080 to about 1.589.
R=rnystrom@google.com
Review URL: https://codereview.chromium.org//1473563003 .
diff --git a/benchmark/benchmark.dart b/benchmark/benchmark.dart
index 03871d0..8dc2690 100644
--- a/benchmark/benchmark.dart
+++ b/benchmark/benchmark.dart
@@ -47,6 +47,10 @@
benchmark('toUri', context.toUri);
benchmark('prettyUri', context.prettyUri);
}
+
+ if (args.isEmpty || args.any((arg) => arg == 'current')) {
+ runBenchmark('current', (_) => path.current, [null]);
+ }
}
const COMMON_PATHS = const ['.', '..', 'out/ReleaseIA32/packages'];
diff --git a/lib/path.dart b/lib/path.dart
index af9efe5..93fe67e 100644
--- a/lib/path.dart
+++ b/lib/path.dart
@@ -79,17 +79,36 @@
/// In the browser, this means the current URL, without the last file segment.
String get current {
var uri = Uri.base;
+
+ // Converting the base URI to a file path is pretty slow, and the base URI
+ // rarely changes in practice, so we cache the result here.
+ if (uri == _currentUriBase) return _current;
+ _currentUriBase = uri;
+
if (Style.platform == Style.url) {
- return uri.resolve('.').toString();
+ _current = uri.resolve('.').toString();
+ return _current;
} else {
var path = uri.toFilePath();
// Remove trailing '/' or '\'.
- int lastIndex = path.length - 1;
+ var lastIndex = path.length - 1;
assert(path[lastIndex] == '/' || path[lastIndex] == '\\');
- return path.substring(0, lastIndex);
+ _current = path.substring(0, lastIndex);
+ return _current;
}
}
+/// The last value returned by [Uri.base].
+///
+/// This is used to cache the current working directory.
+Uri _currentUriBase;
+
+/// The last known value of the current working directory.
+///
+/// This is cached because [current] is called frequently but rarely actually
+/// changes.
+String _current;
+
/// Gets the path separator for the current platform. This is `\` on Windows
/// and `/` on other platforms (including the browser).
String get separator => context.separator;
diff --git a/lib/src/context.dart b/lib/src/context.dart
index 44bdde9..a05ffda 100644
--- a/lib/src/context.dart
+++ b/lib/src/context.dart
@@ -411,6 +411,9 @@
/// "/", no path can be determined. In this case, a [PathException] will be
/// thrown.
String relative(String path, {String from}) {
+ // Avoid expensive computation if the path is already relative.
+ if (from == null && this.isRelative(path)) return path;
+
// Avoid calling [current] since it is slow and calling join() when
// [from] is absolute does nothing.
if (from == null) {