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
This commit is contained in:
erik.corry@gmail.com 2008-12-08 09:22:24 +00:00
parent ba09ec5e89
commit bf9d096326

View File

@ -198,9 +198,9 @@ function StringReplace(search, replace) {
if (start < 0) return subject;
var end = start + search.length;
var builder = new StringBuilder();
var builder = new ReplaceResultBuilder(subject);
// prefix
builder.add(SubString(subject, 0, start));
builder.addSpecialSlice(0, start);
// Compute the string to replace with.
if (IS_FUNCTION(replace)) {
@ -210,7 +210,7 @@ function StringReplace(search, replace) {
}
// suffix
builder.add(SubString(subject, end, subject.length));
builder.addSpecialSlice(end, subject.length);
return builder.generate();
}
@ -234,18 +234,27 @@ function StringReplaceRegExp(subject, regexp, replace) {
var length = matches.length;
// Build the resulting string of subject slices and replacements.
var result = new StringBuilder();
var result = new ReplaceResultBuilder(subject);
var previous = 0;
// The caller of StringReplaceRegExp must ensure that replace is not a
// function.
replace = ToString(replace);
for (var i = 0; i < length; i++) {
var captures = matches[i];
result.add(SubString(subject, previous, captures[0]));
ExpandReplacement(replace, subject, captures, result);
previous = captures[1]; // continue after match
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++) {
var captures = matches[i];
result.addSpecialSlice(previous, captures[0]);
ExpandReplacement(replace, subject, captures, result);
previous = captures[1]; // continue after match
}
}
result.add(SubString(subject, previous, subject.length));
result.addSpecialSlice(previous, subject.length);
return result.generate();
};
@ -272,15 +281,16 @@ function ExpandReplacement(string, subject, captures, builder) {
var peek = %StringCharCodeAt(string, position);
if (peek == 36) { // $$
++position;
builder.add('$');
} else if (peek == 38) { // $& - match
++position;
expansion = SubString(subject, captures[0], captures[1]);
builder.addSpecialSlice(captures[0], captures[1]);
} else if (peek == 96) { // $` - prefix
++position;
expansion = SubString(subject, 0, captures[0]);
builder.addSpecialSlice(0, captures[0]);
} else if (peek == 39) { // $' - suffix
++position;
expansion = SubString(subject, captures[1], subject.length);
builder.addSpecialSlice(captures[1], subject.length);
} else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9
++position;
var n = peek - 48;
@ -301,20 +311,21 @@ function ExpandReplacement(string, subject, captures, builder) {
}
}
if (0 < n && n < m) {
expansion = CaptureString(subject, captures, n);
if (IS_UNDEFINED(expansion)) expansion = "";
addCaptureString(builder, captures, n);
} else {
// Because of the captures range check in the parsing of two
// digit capture references, we can only enter here when a
// single digit capture reference is outside the range of
// captures.
builder.add('$');
--position;
}
}
} else {
builder.add('$');
}
// Append the $ expansion and go the the next $ in the string.
builder.add(expansion);
// Go the the next $ in the string.
next = %StringIndexOf(string, '$', position);
// Return if there are no more $ characters in the string. If we
@ -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
// function application in String.prototype.replace. The function application
// must be interleaved with the regexp matching (contrary to ECMA-262