| Index: runtime/lib/string_buffer_patch.dart
|
| diff --git a/runtime/lib/string_buffer_patch.dart b/runtime/lib/string_buffer_patch.dart
|
| index 8fadafaa1259f867a224224f38a8a58969df5692..2d1eb500bbb96ab07d5115f32e778c428ec6f21a 100644
|
| --- a/runtime/lib/string_buffer_patch.dart
|
| +++ b/runtime/lib/string_buffer_patch.dart
|
| @@ -3,13 +3,22 @@
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| patch class StringBuffer {
|
| - List<String> _buffer;
|
| - int _length;
|
| + /** Backing store for collected UTF-16 code units. */
|
| + Uint16List _buffer;
|
| + /** Number of code units collected. */
|
| + int _length = 0;
|
| + /**
|
| + * Collects the approximate maximal magnitude of the added code units.
|
| + *
|
| + * The value of each added code unit is or'ed with this variable, so the
|
| + * most significant bit set in any code unit is also set in this value.
|
| + * If below 256, the string is a Latin-1 string.
|
| + */
|
| + int _codeUnitMagnitude = 0;
|
|
|
| /// Creates the string buffer with an initial content.
|
| - /* patch */ StringBuffer([Object content = ""]) {
|
| - _buffer = new List<String>();
|
| - _length = 0;
|
| + /* patch */ StringBuffer([Object content = ""])
|
| + : _buffer = new Uint16List(16) {
|
| write(content);
|
| }
|
|
|
| @@ -17,37 +26,82 @@ patch class StringBuffer {
|
|
|
| /// Adds [obj] to the buffer.
|
| /* patch */ void write(Object obj) {
|
| - // TODO(srdjan): The following four lines could be replaced by
|
| - // '$obj', but apparently this is too slow on the Dart VM.
|
| String str;
|
| if (obj is String) {
|
| str = obj;
|
| } else {
|
| + // TODO(srdjan): The following four lines could be replaced by
|
| + // '$obj', but apparently this is too slow on the Dart VM.
|
| str = obj.toString();
|
| if (str is! String) {
|
| throw new ArgumentError('toString() did not return a string');
|
| }
|
| }
|
| if (str.isEmpty) return;
|
| - _buffer.add(str);
|
| + _ensureCapacity(str.length);
|
| + for (int i = 0; i < str.length; i++) {
|
| + int unit = str.codeUnitAt(i);
|
| + _buffer[_length + i] = unit;
|
| + _codeUnitMagnitude |= unit;
|
| + }
|
| _length += str.length;
|
| }
|
|
|
| - /// Clears the string buffer.
|
| + /* patch */ writeCharCode(int charCode) {
|
| + if (charCode <= 0xFFFF) {
|
| + if (charCode < 0) {
|
| + throw new RangeError.range(charCode, 0, 0x10FFFF);
|
| + }
|
| + _ensureCapacity(1);
|
| + _buffer[_length++] = charCode;
|
| + _codeUnitMagnitude |= charCode;
|
| + } else {
|
| + if (charCode > 0x10FFFF) {
|
| + throw new RangeError.range(charCode, 0, 0x10FFFF);
|
| + }
|
| + _ensureCapacity(2);
|
| + int bits = charCode - 0x10000;
|
| + _buffer[_length++] = 0xD800 | (bits >> 10);
|
| + _buffer[_length++] = 0xDC00 | (bits & 0x3FF);
|
| + _codeUnitMagnitude |= 0xFFFF;
|
| + }
|
| + }
|
| +
|
| + /** Makes the buffer empty. */
|
| /* patch */ void clear() {
|
| - _buffer = new List<String>();
|
| _length = 0;
|
| + _codeUnitMagnitude = 0;
|
| }
|
|
|
| - /// Returns the contents of buffer as a concatenated string.
|
| + /** Returns the contents of buffer as a string. */
|
| /* patch */ String toString() {
|
| - if (_buffer.length == 0) return "";
|
| - if (_buffer.length == 1) return _buffer[0];
|
| - String result = _StringBase.concatAll(_buffer);
|
| - _buffer.clear();
|
| - _buffer.add(result);
|
| - // Since we track the length at each add operation, there is no
|
| - // need to update it in this function.
|
| - return result;
|
| + if (_length == 0) return "";
|
| + bool isLatin1 = _codeUnitMagnitude <= 0xFF;
|
| + return _create(_buffer, _length, isLatin1);
|
| + }
|
| +
|
| + /** Ensures that the buffer has enough capacity to add n code units. */
|
| + void _ensureCapacity(int n) {
|
| + int requiredCapacity = _length + n;
|
| + if (requiredCapacity > _buffer.length) {
|
| + _grow(requiredCapacity);
|
| + }
|
| }
|
| +
|
| + /** Grows the buffer until it can contain [requiredCapacity] entries. */
|
| + void _grow(int requiredCapacity) {
|
| + int newCapacity = _buffer.length;
|
| + do {
|
| + newCapacity *= 2;
|
| + } while (newCapacity < requiredCapacity);
|
| + List<int> newBuffer = new Uint16List(newCapacity);
|
| + newBuffer.setRange(0, _length, _buffer);
|
| + _buffer = newBuffer;
|
| + }
|
| +
|
| + /**
|
| + * Create a [String] from the UFT-16 code units in buffer.
|
| + */
|
| + static String _create(Uint16List buffer, int length, bool isLatin1)
|
| + native "StringBuffer_createStringFromUint16Array";
|
| }
|
|
|