OLD | NEW |
---|---|
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 Loading... | |
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 Loading... | |
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 Loading... | |
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 } |
OLD | NEW |