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

Side by Side Diff: runtime/lib/string_patch.dart

Issue 858543002: Avoid extra duplication of substrings during string.replaceAll. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Abstract add-slice code into separate function. Created 5 years, 11 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 | « runtime/lib/string.cc ('k') | runtime/vm/bootstrap_natives.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 patch class String { 5 patch class String {
6 /* patch */ factory String.fromCharCodes(Iterable<int> charCodes, 6 /* patch */ factory String.fromCharCodes(Iterable<int> charCodes,
7 [int start = 0, int end]) { 7 [int start = 0, int end]) {
8 return _StringBase.createFromCharCodes(charCodes, start, end); 8 return _StringBase.createFromCharCodes(charCodes, start, end);
9 } 9 }
10 10
(...skipping 22 matching lines...) Expand all
33 {String defaultValue}) 33 {String defaultValue})
34 native "String_fromEnvironment"; 34 native "String_fromEnvironment";
35 } 35 }
36 36
37 37
38 /** 38 /**
39 * [_StringBase] contains common methods used by concrete String 39 * [_StringBase] contains common methods used by concrete String
40 * implementations, e.g., _OneByteString. 40 * implementations, e.g., _OneByteString.
41 */ 41 */
42 class _StringBase { 42 class _StringBase {
43 // Constants used by replaceAll encoding of matches.
44 static const int _lengthSize = 11;
45 static const int _maxLengthValue = (1 << _lengthSize) - 1;
46 static const int _maxStartValue = (1 << (30 - _lengthSize)) - 1;
siva 2015/01/22 00:08:17 what are '11' and '30' here? can they be given des
Lasse Reichstein Nielsen 2015/01/22 08:25:38 11 is semi-arbitrarily chosen as the size of the l
47 static const int _lengthMask = _maxLengthValue;
43 48
44 factory _StringBase._uninstantiable() { 49 factory _StringBase._uninstantiable() {
45 throw new UnsupportedError( 50 throw new UnsupportedError(
46 "_StringBase can't be instaniated"); 51 "_StringBase can't be instaniated");
47 } 52 }
48 53
49 Type get runtimeType => String; 54 Type get runtimeType => String;
50 55
51 int get hashCode native "String_getHashCode"; 56 int get hashCode native "String_getHashCode";
52 57
(...skipping 427 matching lines...) Expand 10 before | Expand all | Expand 10 after
480 Iterator iterator = 485 Iterator iterator =
481 startIndex == 0 ? pattern.allMatches(this).iterator 486 startIndex == 0 ? pattern.allMatches(this).iterator
482 : pattern.allMatches(this, startIndex).iterator; 487 : pattern.allMatches(this, startIndex).iterator;
483 if (!iterator.moveNext()) return this; 488 if (!iterator.moveNext()) return this;
484 Match match = iterator.current; 489 Match match = iterator.current;
485 return "${this.substring(0, match.start)}" 490 return "${this.substring(0, match.start)}"
486 "$replacement" 491 "$replacement"
487 "${this.substring(match.end)}"; 492 "${this.substring(match.end)}";
488 } 493 }
489 494
495
496 static int _addReplaceSlice(List matches, int start, int end) {
497 int length = end - start;
498 if (length > 0) {
499 if (length <= _maxLengthValue && start <= _maxStartValue) {
500 matches.add(-((start << _lengthSize) | length));
501 } else {
502 matches.add(start);
503 matches.add(end);
504 }
505 }
506 return length;
507 }
508
490 String replaceAll(Pattern pattern, String replacement) { 509 String replaceAll(Pattern pattern, String replacement) {
491 if (pattern is! Pattern) { 510 if (pattern == null) throw new ArgumentError.notNull("pattern");
492 throw new ArgumentError("${pattern} is not a Pattern"); 511 if (replacement == null) throw new ArgumentError.notNull("replacement");
512 List matches = [];
513 int length = 0;
514 int replacementLength = replacement.length;
515 int startIndex = 0;
516 if (replacementLength == 0) {
517 int count = 0;
518 for (Match match in pattern.allMatches(this)) {
519 length += _addReplaceSlice(matches, startIndex, match.start);
520 startIndex = match.end;
521 }
522 } else {
523 for (Match match in pattern.allMatches(this)) {
524 length += _addReplaceSlice(matches, startIndex, match.start);
525 matches.add(replacement);
526 length += replacementLength;
527 startIndex = match.end;
528 }
493 } 529 }
494 if (replacement is! String) { 530 length += _addReplaceSlice(matches, startIndex, this.length);
495 throw new ArgumentError( 531 bool replacementIsOneByte = (replacement is _OneByteString) ||
496 "${replacement} is not a String or Match->String function"); 532 (replacement is _ExternalOneByteString);
533 if (replacementIsOneByte && length < 500) {
siva 2015/01/22 00:08:17 document this magic constant as static const int _
Lasse Reichstein Nielsen 2015/01/22 08:25:38 Done: static const int _maxJoinReplaceOneByteSt
534 // TODO(lrn): Is there a cut-off point, or is runtime always faster?
535 bool thisIsOneByte = (this is _OneByteString) ||
536 (this is _ExternalOneByteString);
537 if (replacementIsOneByte && thisIsOneByte) {
538 return _joinReplaceAllOneByteResult(this, matches, length);
539 }
497 } 540 }
498 StringBuffer buffer = new StringBuffer(); 541 return _joinReplaceAllResult(this, matches, length,
542 replacementIsOneByte);
543 }
544
545 /**
546 * As [_joinReplaceAllResult], but knowing that the result
547 * is always a [_OneByteString].
548 */
549 static String _joinReplaceAllOneByteResult(String base,
550 List matches,
551 int length) {
552 _OneByteString result = _OneByteString._allocate(length);
553 int writeIndex = 0;
554 for (int i = 0; i < matches.length; i++) {
555 var entry = matches[i];
556 if (entry is _Smi) {
557 int sliceStart = entry;
558 int sliceEnd;
559 if (sliceStart < 0) {
560 int bits = -sliceStart;
561 int sliceLength = bits & _lengthMask;
562 sliceStart = bits >> _lengthSize;
563 sliceEnd = sliceStart + sliceLength;
564 } else {
565 i++;
566 // This function should only be called with valid matches lists.
567 // If the list is short, or sliceEnd is not an integer, one of
568 // the next few lines will throw anyway.
569 assert(i < matches.length);
570 sliceEnd = matches[i];
571 }
572 for (int j = sliceStart; j < sliceEnd; j++) {
573 result._setAt(writeIndex++, base.codeUnitAt(j));
574 }
575 } else {
576 // Replacement is a one-byte string.
577 String replacement = entry;
578 for (int j = 0; j < replacement.length; j++) {
579 result._setAt(writeIndex++, replacement.codeUnitAt(j));
580 }
581 }
582 }
583 assert(writeIndex == length);
584 return result;
585 }
586
587 /**
588 * Combine the results of a [replaceAll] match into a new string.
589 *
590 * The [matches] lists contains Smi index pairs representing slices of
591 * [base] and [String]s to be put in between the slices.
592 *
593 * The total [length] of the resulting string is known, as is
594 * whether the replacement strings are one-byte strings.
595 * If they are, then we have to check the base string slices to know
596 * whether the result must be a one-byte string.
597 */
598 static String _joinReplaceAllResult(String base, List matches, int length,
599 bool replacementStringsAreOneByte)
600 native "StringBase_joinReplaceAllResult";
601
602 String replaceAllMapped(Pattern pattern, String replace(Match match)) {
603 if (pattern == null) throw new ArgumentError.notNull("pattern");
604 if (replace == null) throw new ArgumentError.notNull("replace");
605 List matches = [];
606 int length = 0;
499 int startIndex = 0; 607 int startIndex = 0;
608 bool replacementStringsAreOneByte = true;
500 for (Match match in pattern.allMatches(this)) { 609 for (Match match in pattern.allMatches(this)) {
501 buffer..write(this.substring(startIndex, match.start)) 610 length += _addReplaceSlice(matches, startIndex, match.start);
502 ..write(replacement); 611 String replacement = replace(match).toString();
612 matches.add(replacement);
613 length += replacement.length;
614 replacementStringsAreOneByte = replacementStringsAreOneByte &&
615 (replacement is _OneByteString ||
616 replacement is _ExternalOneByteString);
503 startIndex = match.end; 617 startIndex = match.end;
504 } 618 }
505 return (buffer..write(this.substring(startIndex))).toString(); 619 length += _addReplaceSlice(matches, startIndex, this.length);
506 } 620 if (replacementStringsAreOneByte && length < 500) {
507 621 bool thisIsOneByte = (this is _OneByteString) ||
508 String replaceAllMapped(Pattern pattern, String replace(Match match)) { 622 (this is _ExternalOneByteString);
509 return splitMapJoin(pattern, onMatch: replace); 623 if (thisIsOneByte) {
624 return _joinReplaceAllOneByteResult(this, matches, length);
625 }
626 }
627 return _joinReplaceAllResult(this, matches, length,
628 replacementStringsAreOneByte);
510 } 629 }
511 630
512 static String _matchString(Match match) => match[0]; 631 static String _matchString(Match match) => match[0];
513 static String _stringIdentity(String string) => string; 632 static String _stringIdentity(String string) => string;
514 633
515 String _splitMapJoinEmptyString(String onMatch(Match match), 634 String _splitMapJoinEmptyString(String onMatch(Match match),
516 String onNonMatch(String nonMatch)) { 635 String onNonMatch(String nonMatch)) {
517 // Pattern is the empty string. 636 // Pattern is the empty string.
518 StringBuffer buffer = new StringBuffer(); 637 StringBuffer buffer = new StringBuffer();
519 int length = this.length; 638 int length = this.length;
(...skipping 555 matching lines...) Expand 10 before | Expand all | Expand 10 after
1075 class _CodeUnits extends Object with ListMixin<int>, 1194 class _CodeUnits extends Object with ListMixin<int>,
1076 UnmodifiableListMixin<int> { 1195 UnmodifiableListMixin<int> {
1077 /** The string that this is the code units of. */ 1196 /** The string that this is the code units of. */
1078 String _string; 1197 String _string;
1079 1198
1080 _CodeUnits(this._string); 1199 _CodeUnits(this._string);
1081 1200
1082 int get length => _string.length; 1201 int get length => _string.length;
1083 int operator[](int i) => _string.codeUnitAt(i); 1202 int operator[](int i) => _string.codeUnitAt(i);
1084 } 1203 }
OLDNEW
« no previous file with comments | « runtime/lib/string.cc ('k') | runtime/vm/bootstrap_natives.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698