One more simple optimization in isWithin.

This makes Konstantine's use case about 11% faster.

R=nweiz@google.com

Review URL: https://codereview.chromium.org//1509803002 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 44090f6..a404f70 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 1.3.10
+
+* Further improve the performance of `isWithin()`.
+
 ## 1.3.9
 
 * Further improve the performance of `isWithin()` when paths contain `/.`
diff --git a/lib/src/context.dart b/lib/src/context.dart
index d10a29f..a6a1cb2 100644
--- a/lib/src/context.dart
+++ b/lib/src/context.dart
@@ -558,16 +558,13 @@
     //     isWithin("http://example.com/", "http://google.com/bar") //=> false
     if (parentRootLength != childRootLength) return false;
 
-    var parentCodeUnits = parent.codeUnits;
-    var childCodeUnits = child.codeUnits;
-
     // Make sure that the roots are textually the same as well.
     //
     //     isWithin("C:/bar", "D:/bar/baz") //=> false
     //     isWithin("http://example.com/", "http://example.org/bar") //=> false
     for (var i = 0; i < parentRootLength; i++) {
-      var parentCodeUnit = parentCodeUnits[i];
-      var childCodeUnit = childCodeUnits[i];
+      var parentCodeUnit = parent.codeUnitAt(i);
+      var childCodeUnit = child.codeUnitAt(i);
       if (parentCodeUnit == childCodeUnit) continue;
 
       // If both code units are separators, that's fine too.
@@ -588,8 +585,8 @@
     var parentIndex = parentRootLength;
     var childIndex = childRootLength;
     while (parentIndex < parent.length && childIndex < child.length) {
-      var parentCodeUnit = parentCodeUnits[parentIndex];
-      var childCodeUnit = childCodeUnits[childIndex];
+      var parentCodeUnit = parent.codeUnitAt(parentIndex);
+      var childCodeUnit = child.codeUnitAt(childIndex);
       if (parentCodeUnit == childCodeUnit) {
         lastCodeUnit = parentCodeUnit;
         parentIndex++;
@@ -629,7 +626,7 @@
           // 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];
+          parentCodeUnit = parent.codeUnitAt(parentIndex);
 
           // We've hit "/./", which we can ignore.
           if (style.isSeparator(parentCodeUnit)) {
@@ -642,7 +639,7 @@
           if (parentCodeUnit == chars.PERIOD) {
             parentIndex++;
             if (parentIndex == parent.length ||
-                style.isSeparator(parentCodeUnits[parentIndex])) {
+                style.isSeparator(parent.codeUnitAt(parentIndex))) {
               return null;
             }
           }
@@ -658,7 +655,7 @@
         if (style.isSeparator(lastCodeUnit)) {
           childIndex++;
           if (childIndex == child.length) break;
-          childCodeUnit = childCodeUnits[childIndex];
+          childCodeUnit = child.codeUnitAt(childIndex);
 
           if (style.isSeparator(childCodeUnit)) {
             childIndex++;
@@ -668,7 +665,7 @@
           if (childCodeUnit == chars.PERIOD) {
             childIndex++;
             if (childIndex == child.length ||
-                style.isSeparator(childCodeUnits[childIndex])) {
+                style.isSeparator(child.codeUnitAt(childIndex))) {
               return null;
             }
           }
@@ -679,9 +676,9 @@
       // As long as the remainders of the two paths don't have any unresolved
       // ".." components, we can be confident that [child] is not within
       // [parent].
-      var childDirection = _pathDirection(childCodeUnits, childIndex);
+      var childDirection = _pathDirection(child, childIndex);
       if (childDirection != _PathDirection.belowRoot) return null;
-      var parentDirection = _pathDirection(parentCodeUnits, parentIndex);
+      var parentDirection = _pathDirection(parent, parentIndex);
       if (parentDirection != _PathDirection.belowRoot) return null;
 
       return false;
@@ -694,14 +691,14 @@
     //     isWithin("foo/bar/baz", "foo/bar") //=> false
     //     isWithin("foo/bar/baz/../..", "foo/bar") //=> true
     if (childIndex == child.length) {
-      var direction = _pathDirection(parentCodeUnits, parentIndex);
+      var direction = _pathDirection(parent, parentIndex);
       return direction == _PathDirection.aboveRoot ? null : false;
     }
 
     // We've reached the end of the parent path, which means it's time to make a
     // decision. Before we do, though, we'll check the rest of the child to see
     // what that tells us.
-    var direction = _pathDirection(childCodeUnits, childIndex);
+    var direction = _pathDirection(child, childIndex);
 
     // If there are no more components in the child, then it's the same as
     // the parent, not within it.
@@ -724,7 +721,7 @@
     //     isWithin("foo/bar", "foo/bar/baz") //=> true
     //     isWithin("foo/bar/", "foo/bar/baz") //=> true
     //     isWithin("foo/bar", "foo/barbaz") //=> false
-    return style.isSeparator(childCodeUnits[childIndex]) ||
+    return style.isSeparator(child.codeUnitAt(childIndex)) ||
         style.isSeparator(lastCodeUnit);
   }
 
@@ -741,31 +738,31 @@
   //     pathDirection("foo/../baz") //=> reaches root
   //     pathDirection("foo/../..") //=> above root
   //     pathDirection("foo/../../foo/bar/baz") //=> above root
-  _PathDirection _pathDirection(List<int> codeUnits, int index) {
+  _PathDirection _pathDirection(String path, int index) {
     var depth = 0;
     var reachedRoot = false;
     var i = index;
-    while (i < codeUnits.length) {
+    while (i < path.length) {
       // Ignore initial separators or doubled separators.
-      while (i < codeUnits.length && style.isSeparator(codeUnits[i])) {
+      while (i < path.length && style.isSeparator(path.codeUnitAt(i))) {
         i++;
       }
 
       // If we're at the end, stop.
-      if (i == codeUnits.length) break;
+      if (i == path.length) break;
 
       // Move through the path component to the next separator.
       var start = i;
-      while (i < codeUnits.length && !style.isSeparator(codeUnits[i])) {
+      while (i < path.length && !style.isSeparator(path.codeUnitAt(i))) {
         i++;
       }
 
       // See if the path component is ".", "..", or a name.
-      if (i - start == 1 && codeUnits[start] == chars.PERIOD) {
+      if (i - start == 1 && path.codeUnitAt(start) == chars.PERIOD) {
         // Don't change the depth.
       } else if (i - start == 2 &&
-          codeUnits[start] == chars.PERIOD &&
-          codeUnits[start + 1] == chars.PERIOD) {
+          path.codeUnitAt(start) == chars.PERIOD &&
+          path.codeUnitAt(start + 1) == chars.PERIOD) {
         // ".." backs out a directory.
         depth--;
 
@@ -781,7 +778,7 @@
       }
 
       // If we're at the end, stop.
-      if (i == codeUnits.length) break;
+      if (i == path.length) break;
 
       // Move past the separator.
       i++;
diff --git a/pubspec.yaml b/pubspec.yaml
index fb21d20..31bf492 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: path
-version: 1.3.9
+version: 1.3.10-dev
 author: Dart Team <misc@dartlang.org>
 description: >
  A string-based path manipulation library. All of the path operations you know