Further improve isWithin() performance.
On @scheglov's benchmark data, which include many path containing `.pub`
or `.pub-cache`, this results in a further ~8x improvement over the
improvements in e6b55472da7bfcfcc20db163abadfbd7689dd23c.
On the repo benchmark, this results in a further ~1.2x improvement.
Closes #7
R=rnystrom@google.com
Review URL: https://codereview.chromium.org//1498613002 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index aee2424..44090f6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.3.9
+
+* Further improve the performance of `isWithin()` when paths contain `/.`
+ sequences that aren't `/../`.
+
## 1.3.8
* Improve the performance of `isWithin()` when the paths don't contain
diff --git a/lib/src/context.dart b/lib/src/context.dart
index b19aa71..d10a29f 100644
--- a/lib/src/context.dart
+++ b/lib/src/context.dart
@@ -616,18 +616,63 @@
continue;
}
- // If a dot comes after a separator or another dot, it may be a
- // directory traversal operator. Otherwise, it's just a normal
- // non-matching character.
- //
- // isWithin("foo/./bar", "foo/bar/baz") //=> true
- // isWithin("foo/bar/../baz", "foo/bar/.foo") //=> false
- //
- // We could stay on the fast path for "/./", but that adds a lot of
- // complexity and isn't likely to come up much in practice.
- if ((parentCodeUnit == chars.PERIOD || childCodeUnit == chars.PERIOD) &&
- (style.isSeparator(lastCodeUnit) || lastCodeUnit == chars.PERIOD)) {
- return null;
+ if (parentCodeUnit == chars.PERIOD) {
+ // If a dot comes after a separator, it may be a directory traversal
+ // operator. To check that, we need to know if it's followed by either
+ // "/" or "./". Otherwise, it's just a normal non-matching character.
+ //
+ // isWithin("foo/./bar", "foo/bar/baz") //=> true
+ // isWithin("foo/bar/../baz", "foo/bar/.foo") //=> false
+ if (style.isSeparator(lastCodeUnit)) {
+ parentIndex++;
+
+ // We've hit "/." at the end of the parent path, which we can ignore,
+ // since the paths were equivalent up to this point.
+ if (parentIndex == parent.length) break;
+ parentCodeUnit = parentCodeUnits[parentIndex];
+
+ // We've hit "/./", which we can ignore.
+ if (style.isSeparator(parentCodeUnit)) {
+ parentIndex++;
+ continue;
+ }
+
+ // We've hit "/..", which may be a directory traversal operator that
+ // we can't handle on the fast track.
+ if (parentCodeUnit == chars.PERIOD) {
+ parentIndex++;
+ if (parentIndex == parent.length ||
+ style.isSeparator(parentCodeUnits[parentIndex])) {
+ return null;
+ }
+ }
+ }
+
+ // If this isn't a directory traversal, fall through so we hit the
+ // normal handling for mismatched paths.
+ }
+
+ // This is the same logic as above, but for the child path instead of the
+ // parent.
+ if (childCodeUnit == chars.PERIOD) {
+ if (style.isSeparator(lastCodeUnit)) {
+ childIndex++;
+ if (childIndex == child.length) break;
+ childCodeUnit = childCodeUnits[childIndex];
+
+ if (style.isSeparator(childCodeUnit)) {
+ childIndex++;
+ continue;
+ }
+
+ if (childCodeUnit == chars.PERIOD) {
+ childIndex++;
+ if (childIndex == child.length ||
+ style.isSeparator(childCodeUnits[childIndex])) {
+ return null;
+ }
+ }
+ }
}
// If we're here, we've hit two non-matching, non-significant characters.
diff --git a/pubspec.yaml b/pubspec.yaml
index 69359bb..fb21d20 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: path
-version: 1.3.8
+version: 1.3.9
author: Dart Team <misc@dartlang.org>
description: >
A string-based path manipulation library. All of the path operations you know