From: erik.corry@gmail.com Date: Mon, 8 Dec 2008 09:22:24 +0000 (+0000) Subject: Improve speed of String.replace by around 33% by not constructing X-Git-Tag: upstream/4.7.83~24895 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=bf9d096326368c18b9fae4845b1dd73ae2870dbc;p=platform%2Fupstream%2Fv8.git 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 --- diff --git a/src/string.js b/src/string.js index 984d969..78606a6 100644 --- a/src/string.js +++ b/src/string.js @@ -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