Commit bf9d0963 authored by erik.corry@gmail.com's avatar erik.corry@gmail.com

Improve speed of String.replace by around 33% by not constructing

sliced strings for the interstices of the matches.  This can be
speeded up further.
Review URL: http://codereview.chromium.org/13614

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@931 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent ba09ec5e
...@@ -198,9 +198,9 @@ function StringReplace(search, replace) { ...@@ -198,9 +198,9 @@ function StringReplace(search, replace) {
if (start < 0) return subject; if (start < 0) return subject;
var end = start + search.length; var end = start + search.length;
var builder = new StringBuilder(); var builder = new ReplaceResultBuilder(subject);
// prefix // prefix
builder.add(SubString(subject, 0, start)); builder.addSpecialSlice(0, start);
// Compute the string to replace with. // Compute the string to replace with.
if (IS_FUNCTION(replace)) { if (IS_FUNCTION(replace)) {
...@@ -210,7 +210,7 @@ function StringReplace(search, replace) { ...@@ -210,7 +210,7 @@ function StringReplace(search, replace) {
} }
// suffix // suffix
builder.add(SubString(subject, end, subject.length)); builder.addSpecialSlice(end, subject.length);
return builder.generate(); return builder.generate();
} }
...@@ -234,18 +234,27 @@ function StringReplaceRegExp(subject, regexp, replace) { ...@@ -234,18 +234,27 @@ function StringReplaceRegExp(subject, regexp, replace) {
var length = matches.length; var length = matches.length;
// Build the resulting string of subject slices and replacements. // Build the resulting string of subject slices and replacements.
var result = new StringBuilder(); var result = new ReplaceResultBuilder(subject);
var previous = 0; var previous = 0;
// The caller of StringReplaceRegExp must ensure that replace is not a // The caller of StringReplaceRegExp must ensure that replace is not a
// function. // function.
replace = ToString(replace); replace = ToString(replace);
if (%StringIndexOf(replace, "$", 0) < 0) {
for (var i = 0; i < length; i++) {
var captures = matches[i];
result.addSpecialSlice(previous, captures[0]);
result.add(replace);
previous = captures[1]; // continue after match
}
} else {
for (var i = 0; i < length; i++) { for (var i = 0; i < length; i++) {
var captures = matches[i]; var captures = matches[i];
result.add(SubString(subject, previous, captures[0])); result.addSpecialSlice(previous, captures[0]);
ExpandReplacement(replace, subject, captures, result); ExpandReplacement(replace, subject, captures, result);
previous = captures[1]; // continue after match previous = captures[1]; // continue after match
} }
result.add(SubString(subject, previous, subject.length)); }
result.addSpecialSlice(previous, subject.length);
return result.generate(); return result.generate();
}; };
...@@ -272,15 +281,16 @@ function ExpandReplacement(string, subject, captures, builder) { ...@@ -272,15 +281,16 @@ function ExpandReplacement(string, subject, captures, builder) {
var peek = %StringCharCodeAt(string, position); var peek = %StringCharCodeAt(string, position);
if (peek == 36) { // $$ if (peek == 36) { // $$
++position; ++position;
builder.add('$');
} else if (peek == 38) { // $& - match } else if (peek == 38) { // $& - match
++position; ++position;
expansion = SubString(subject, captures[0], captures[1]); builder.addSpecialSlice(captures[0], captures[1]);
} else if (peek == 96) { // $` - prefix } else if (peek == 96) { // $` - prefix
++position; ++position;
expansion = SubString(subject, 0, captures[0]); builder.addSpecialSlice(0, captures[0]);
} else if (peek == 39) { // $' - suffix } else if (peek == 39) { // $' - suffix
++position; ++position;
expansion = SubString(subject, captures[1], subject.length); builder.addSpecialSlice(captures[1], subject.length);
} else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9 } else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9
++position; ++position;
var n = peek - 48; var n = peek - 48;
...@@ -301,20 +311,21 @@ function ExpandReplacement(string, subject, captures, builder) { ...@@ -301,20 +311,21 @@ function ExpandReplacement(string, subject, captures, builder) {
} }
} }
if (0 < n && n < m) { if (0 < n && n < m) {
expansion = CaptureString(subject, captures, n); addCaptureString(builder, captures, n);
if (IS_UNDEFINED(expansion)) expansion = "";
} else { } else {
// Because of the captures range check in the parsing of two // Because of the captures range check in the parsing of two
// digit capture references, we can only enter here when a // digit capture references, we can only enter here when a
// single digit capture reference is outside the range of // single digit capture reference is outside the range of
// captures. // captures.
builder.add('$');
--position; --position;
} }
} }
} else {
builder.add('$');
} }
// Append the $ expansion and go the the next $ in the string. // Go the the next $ in the string.
builder.add(expansion);
next = %StringIndexOf(string, '$', position); next = %StringIndexOf(string, '$', position);
// Return if there are no more $ characters in the string. If we // Return if there are no more $ characters in the string. If we
...@@ -345,6 +356,19 @@ function CaptureString(string, captures, index) { ...@@ -345,6 +356,19 @@ function CaptureString(string, captures, index) {
}; };
// Add the string of a given PCRE capture to the ReplaceResultBuilder
function addCaptureString(builder, captures, index) {
// Scale the index.
var scaled = index << 1;
// Compute start and end.
var start = captures[scaled];
var end = captures[scaled + 1];
// If either start or end is missing return.
if (start < 0 || end < 0) return;
builder.addSpecialSlice(start, end);
};
// Helper function for replacing regular expressions with the result of a // Helper function for replacing regular expressions with the result of a
// function application in String.prototype.replace. The function application // function application in String.prototype.replace. The function application
// must be interleaved with the regexp matching (contrary to ECMA-262 // must be interleaved with the regexp matching (contrary to ECMA-262
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment