Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(271)

Side by Side Diff: src/string.js

Issue 10134057: Use simple concat of substrings instead of ReplaceStringBuilder for non-global replacements. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: Removing dead code Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 the V8 project authors. All rights reserved. 1 // Copyright 2012 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
(...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 %StringIndexOf(replace, '$', 0) < 0) { 270 %StringIndexOf(replace, '$', 0) < 0) {
271 // Searching by traversing a cons string tree and replace with cons of 271 // Searching by traversing a cons string tree and replace with cons of
272 // slices works only when the replaced string is a single character, being 272 // slices works only when the replaced string is a single character, being
273 // replaced by a simple string and only pays off for long strings. 273 // replaced by a simple string and only pays off for long strings.
274 return %StringReplaceOneCharWithString(subject, search, replace); 274 return %StringReplaceOneCharWithString(subject, search, replace);
275 } 275 }
276 var start = %StringIndexOf(subject, search, 0); 276 var start = %StringIndexOf(subject, search, 0);
277 if (start < 0) return subject; 277 if (start < 0) return subject;
278 var end = start + search.length; 278 var end = start + search.length;
279 279
280 var builder = new ReplaceResultBuilder(subject); 280 var result = SubString(subject, 0, start);
281 // prefix
282 builder.addSpecialSlice(0, start);
283 281
284 // Compute the string to replace with. 282 // Compute the string to replace with.
285 if (IS_SPEC_FUNCTION(replace)) { 283 if (IS_SPEC_FUNCTION(replace)) {
286 var receiver = %GetDefaultReceiver(replace); 284 var receiver = %GetDefaultReceiver(replace);
287 builder.add(%_CallFunction(receiver, 285 result += %_CallFunction(receiver, search, start, subject, replace);
288 search,
289 start,
290 subject,
291 replace));
292 } else { 286 } else {
293 reusableMatchInfo[CAPTURE0] = start; 287 reusableMatchInfo[CAPTURE0] = start;
294 reusableMatchInfo[CAPTURE1] = end; 288 reusableMatchInfo[CAPTURE1] = end;
295 replace = TO_STRING_INLINE(replace); 289 replace = TO_STRING_INLINE(replace);
296 ExpandReplacement(replace, subject, reusableMatchInfo, builder); 290 result = ExpandReplacement(replace, subject, reusableMatchInfo, result);
297 } 291 }
298 292
299 // suffix 293 return result + SubString(subject, end, subject.length);
300 builder.addSpecialSlice(end, subject.length);
301
302 return builder.generate();
303 } 294 }
304 295
305 296
306 // Expand the $-expressions in the string and return a new string with 297 // Expand the $-expressions in the string and return a new string with
307 // the result. 298 // the result.
308 function ExpandReplacement(string, subject, matchInfo, builder) { 299 function ExpandReplacement(string, subject, matchInfo, result) {
309 var length = string.length; 300 var length = string.length;
310 var builder_elements = builder.elements;
311 var next = %StringIndexOf(string, '$', 0); 301 var next = %StringIndexOf(string, '$', 0);
312 if (next < 0) { 302 if (next < 0) {
313 if (length > 0) builder_elements.push(string); 303 if (length > 0) result += string;
314 return; 304 return result;
315 } 305 }
316 306
317 // Compute the number of captures; see ECMA-262, 15.5.4.11, p. 102. 307 if (next > 0) result += SubString(string, 0, next);
318 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; // Includes the match.
319
320 if (next > 0) builder_elements.push(SubString(string, 0, next));
321 308
322 while (true) { 309 while (true) {
323 var expansion = '$'; 310 var expansion = '$';
324 var position = next + 1; 311 var position = next + 1;
325 if (position < length) { 312 if (position < length) {
326 var peek = %_StringCharCodeAt(string, position); 313 var peek = %_StringCharCodeAt(string, position);
327 if (peek == 36) { // $$ 314 if (peek == 36) { // $$
328 ++position; 315 ++position;
329 builder_elements.push('$'); 316 result += '$';
330 } else if (peek == 38) { // $& - match 317 } else if (peek == 38) { // $& - match
331 ++position; 318 ++position;
332 builder.addSpecialSlice(matchInfo[CAPTURE0], 319 result += SubString(subject, matchInfo[CAPTURE0], matchInfo[CAPTURE1]);
333 matchInfo[CAPTURE1]);
334 } else if (peek == 96) { // $` - prefix 320 } else if (peek == 96) { // $` - prefix
335 ++position; 321 ++position;
336 builder.addSpecialSlice(0, matchInfo[CAPTURE0]); 322 result += SubString(subject, 0, matchInfo[CAPTURE0]);
337 } else if (peek == 39) { // $' - suffix 323 } else if (peek == 39) { // $' - suffix
338 ++position; 324 ++position;
339 builder.addSpecialSlice(matchInfo[CAPTURE1], subject.length); 325 result += SubString(subject, matchInfo[CAPTURE1], subject.length);
340 } else if (peek >= 48 && peek <= 57) { // $n, 0 <= n <= 9
341 ++position;
342 var n = peek - 48;
343 if (position < length) {
344 peek = %_StringCharCodeAt(string, position);
345 // $nn, 01 <= nn <= 99
346 if (n != 0 && peek == 48 || peek >= 49 && peek <= 57) {
347 var nn = n * 10 + (peek - 48);
348 if (nn < m) {
349 // If the two digit capture reference is within range of
350 // the captures, we use it instead of the single digit
351 // one. Otherwise, we fall back to using the single
352 // digit reference. This matches the behavior of
353 // SpiderMonkey.
354 ++position;
355 n = nn;
356 }
357 }
358 }
359 if (0 < n && n < m) {
360 addCaptureString(builder, matchInfo, n);
361 } else {
362 // Because of the captures range check in the parsing of two
363 // digit capture references, we can only enter here when a
364 // single digit capture reference is outside the range of
365 // captures.
366 builder_elements.push('$');
367 --position;
368 }
369 } else { 326 } else {
370 builder_elements.push('$'); 327 result += '$';
371 } 328 }
372 } else { 329 } else {
373 builder_elements.push('$'); 330 result += '$';
374 } 331 }
375 332
376 // Go the the next $ in the string. 333 // Go the the next $ in the string.
377 next = %StringIndexOf(string, '$', position); 334 next = %StringIndexOf(string, '$', position);
378 335
379 // Return if there are no more $ characters in the string. If we 336 // Return if there are no more $ characters in the string. If we
380 // haven't reached the end, we need to append the suffix. 337 // haven't reached the end, we need to append the suffix.
381 if (next < 0) { 338 if (next < 0) {
382 if (position < length) { 339 if (position < length) {
383 builder_elements.push(SubString(string, position, length)); 340 result += SubString(string, position, length);
384 } 341 }
385 return; 342 return result;
386 } 343 }
387 344
388 // Append substring between the previous and the next $ character. 345 // Append substring between the previous and the next $ character.
389 if (next > position) { 346 if (next > position) {
390 builder_elements.push(SubString(string, position, next)); 347 result += SubString(string, position, next);
391 } 348 }
392 } 349 }
350 return result;
393 } 351 }
394 352
395 353
396 // Compute the string of a given regular expression capture. 354 // Compute the string of a given regular expression capture.
397 function CaptureString(string, lastCaptureInfo, index) { 355 function CaptureString(string, lastCaptureInfo, index) {
398 // Scale the index. 356 // Scale the index.
399 var scaled = index << 1; 357 var scaled = index << 1;
400 // Compute start and end. 358 // Compute start and end.
401 var start = lastCaptureInfo[CAPTURE(scaled)]; 359 var start = lastCaptureInfo[CAPTURE(scaled)];
402 // If start isn't valid, return undefined. 360 // If start isn't valid, return undefined.
403 if (start < 0) return; 361 if (start < 0) return;
404 var end = lastCaptureInfo[CAPTURE(scaled + 1)]; 362 var end = lastCaptureInfo[CAPTURE(scaled + 1)];
405 return SubString(string, start, end); 363 return SubString(string, start, end);
406 } 364 }
407 365
408 366
409 // Add the string of a given regular expression capture to the
410 // ReplaceResultBuilder
411 function addCaptureString(builder, matchInfo, index) {
412 // Scale the index.
413 var scaled = index << 1;
414 // Compute start and end.
415 var start = matchInfo[CAPTURE(scaled)];
416 if (start < 0) return;
417 var end = matchInfo[CAPTURE(scaled + 1)];
418 builder.addSpecialSlice(start, end);
419 }
420
421 // TODO(lrn): This array will survive indefinitely if replace is never 367 // TODO(lrn): This array will survive indefinitely if replace is never
422 // called again. However, it will be empty, since the contents are cleared 368 // called again. However, it will be empty, since the contents are cleared
423 // in the finally block. 369 // in the finally block.
424 var reusableReplaceArray = new InternalArray(16); 370 var reusableReplaceArray = new InternalArray(16);
425 371
426 // Helper function for replacing regular expressions with the result of a 372 // Helper function for replacing regular expressions with the result of a
427 // function application in String.prototype.replace. 373 // function application in String.prototype.replace.
428 function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) { 374 function StringReplaceGlobalRegExpWithFunction(subject, regexp, replace) {
429 var resultArray = reusableReplaceArray; 375 var resultArray = reusableReplaceArray;
430 if (resultArray) { 376 if (resultArray) {
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
499 var result = resultBuilder.generate(); 445 var result = resultBuilder.generate();
500 resultArray.length = 0; 446 resultArray.length = 0;
501 reusableReplaceArray = resultArray; 447 reusableReplaceArray = resultArray;
502 return result; 448 return result;
503 } 449 }
504 450
505 451
506 function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) { 452 function StringReplaceNonGlobalRegExpWithFunction(subject, regexp, replace) {
507 var matchInfo = DoRegExpExec(regexp, subject, 0); 453 var matchInfo = DoRegExpExec(regexp, subject, 0);
508 if (IS_NULL(matchInfo)) return subject; 454 if (IS_NULL(matchInfo)) return subject;
509 var result = new ReplaceResultBuilder(subject);
510 var index = matchInfo[CAPTURE0]; 455 var index = matchInfo[CAPTURE0];
511 result.addSpecialSlice(0, index); 456 var result = SubString(subject, 0, index);
512 var endOfMatch = matchInfo[CAPTURE1]; 457 var endOfMatch = matchInfo[CAPTURE1];
513 // Compute the parameter list consisting of the match, captures, index, 458 // Compute the parameter list consisting of the match, captures, index,
514 // and subject for the replace function invocation. 459 // and subject for the replace function invocation.
515 // The number of captures plus one for the match. 460 // The number of captures plus one for the match.
516 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1; 461 var m = NUMBER_OF_CAPTURES(matchInfo) >> 1;
517 var replacement; 462 var replacement;
518 var receiver = %GetDefaultReceiver(replace); 463 var receiver = %GetDefaultReceiver(replace);
519 if (m == 1) { 464 if (m == 1) {
520 // No captures, only the match, which is always valid. 465 // No captures, only the match, which is always valid.
521 var s = SubString(subject, index, endOfMatch); 466 var s = SubString(subject, index, endOfMatch);
522 // Don't call directly to avoid exposing the built-in global object. 467 // Don't call directly to avoid exposing the built-in global object.
523 replacement = %_CallFunction(receiver, s, index, subject, replace); 468 replacement = %_CallFunction(receiver, s, index, subject, replace);
524 } else { 469 } else {
525 var parameters = new InternalArray(m + 2); 470 var parameters = new InternalArray(m + 2);
526 for (var j = 0; j < m; j++) { 471 for (var j = 0; j < m; j++) {
527 parameters[j] = CaptureString(subject, matchInfo, j); 472 parameters[j] = CaptureString(subject, matchInfo, j);
528 } 473 }
529 parameters[j] = index; 474 parameters[j] = index;
530 parameters[j + 1] = subject; 475 parameters[j + 1] = subject;
531 476
532 replacement = %Apply(replace, receiver, parameters, 0, j + 2); 477 replacement = %Apply(replace, receiver, parameters, 0, j + 2);
533 } 478 }
534 479
535 result.add(replacement); // The add method converts to string if necessary. 480 result += replacement; // The add method converts to string if necessary.
536 // Can't use matchInfo any more from here, since the function could 481 // Can't use matchInfo any more from here, since the function could
537 // overwrite it. 482 // overwrite it.
538 result.addSpecialSlice(endOfMatch, subject.length); 483 return result + SubString(subject, endOfMatch, subject.length);
539 return result.generate();
540 } 484 }
541 485
542 486
543 // ECMA-262 section 15.5.4.12 487 // ECMA-262 section 15.5.4.12
544 function StringSearch(re) { 488 function StringSearch(re) {
545 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) { 489 if (IS_NULL_OR_UNDEFINED(this) && !IS_UNDETECTABLE(this)) {
546 throw MakeTypeError("called_on_null_or_undefined", 490 throw MakeTypeError("called_on_null_or_undefined",
547 ["String.prototype.search"]); 491 ["String.prototype.search"]);
548 } 492 }
549 var regexp; 493 var regexp;
(...skipping 489 matching lines...) Expand 10 before | Expand all | Expand 10 after
1039 "fixed", StringFixed, 983 "fixed", StringFixed,
1040 "italics", StringItalics, 984 "italics", StringItalics,
1041 "small", StringSmall, 985 "small", StringSmall,
1042 "strike", StringStrike, 986 "strike", StringStrike,
1043 "sub", StringSub, 987 "sub", StringSub,
1044 "sup", StringSup 988 "sup", StringSup
1045 )); 989 ));
1046 } 990 }
1047 991
1048 SetUpString(); 992 SetUpString();
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698