Tweak some VM String operations. Mainly the `contains` which had some out-dated assumptions and should just default to `indexOf` all the time. Tested: No new test, only refactoring of existing API. Change-Id: Ifcbec2bcd909a9e63f3bd14590b58518b2219d9a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/413761 Reviewed-by: Daco Harkes <dacoharkes@google.com> Commit-Queue: Lasse Nielsen <lrn@google.com>
diff --git a/sdk/lib/_internal/vm/lib/string_patch.dart b/sdk/lib/_internal/vm/lib/string_patch.dart index 7c72c64..cf8291b 100644 --- a/sdk/lib/_internal/vm/lib/string_patch.dart +++ b/sdk/lib/_internal/vm/lib/string_patch.dart
@@ -385,12 +385,21 @@ int indexOf(Pattern pattern, [int start = 0]) { if ((start < 0) || (start > this.length)) { - throw new RangeError.range(start, 0, this.length, "start"); + throw RangeError.range(start, 0, this.length, "start"); } if (pattern is String) { String other = pattern; - int maxIndex = this.length - other.length; - // TODO: Use an efficient string search (e.g. BMH). + var otherLength = other.length; + if (otherLength == 0) return start; + if (otherLength == 1) { + int codeUnit = other.codeUnitAt(0); + for (var index = start; index < this.length; index++) { + if (codeUnit == this.codeUnitAt(index)) return index; + } + return -1; + } + int maxIndex = this.length - otherLength; + // TODO: Use an efficient string search (e.g., BMH). for (int index = start; index <= maxIndex; index++) { if (_substringMatches(index, other)) { return index; @@ -399,8 +408,6 @@ return -1; } for (int i = start; i <= this.length; i++) { - // TODO(11276); This has quadratic behavior because matchAsPrefix tries - // to find a later match too. Optimize matchAsPrefix to avoid this. if (pattern.matchAsPrefix(this, i) != null) return i; } return -1; @@ -424,8 +431,6 @@ return -1; } for (int i = start; i >= 0; i--) { - // TODO(11276); This has quadratic behavior because matchAsPrefix tries - // to find a later match too. Optimize matchAsPrefix to avoid this. if (pattern.matchAsPrefix(this, i) != null) return i; } return -1; @@ -604,13 +609,10 @@ } bool contains(Pattern pattern, [int startIndex = 0]) { - if (pattern is String) { - if (startIndex < 0 || startIndex > this.length) { - throw new RangeError.range(startIndex, 0, this.length); - } + if (startIndex >= 0 && startIndex <= this.length) { return indexOf(pattern, startIndex) >= 0; } - return pattern.allMatches(this.substring(startIndex)).isNotEmpty; + throw RangeError.range(startIndex, 0, this.length, "startIndex"); } String replaceFirst( @@ -618,16 +620,6 @@ String replacement, [ int startIndex = 0, ]) { - // TODO: Remove these null checks once all code is opted into strong nonnullable mode. - if (pattern == null) { - throw new ArgumentError.notNull("pattern"); - } - if (replacement == null) { - throw new ArgumentError.notNull("replacement"); - } - if (startIndex == null) { - throw new ArgumentError.notNull("startIndex"); - } RangeError.checkValueInInterval(startIndex, 0, this.length, "startIndex"); Iterator iterator = startIndex == 0 @@ -708,7 +700,7 @@ if (replacementIsOneByte && length < _maxJoinReplaceOneByteStringLength && this._isOneByte) { - // TODO(lrn): Is there a cut-off point, or is runtime always faster? + // TODO: Is there a cut-off point, or is runtime always faster? return _joinReplaceAllOneByteResult(this, matches, length); } return _joinReplaceAllResult(this, matches, length, replacementIsOneByte);