Chromium Code Reviews| 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..8c5b525d2a9940f4fb70adfd61fdf094a673d247 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 _code_magnitude = 0; |
|
srdjan
2013/03/07 17:58:34
s/_code_magnitude/_codeMagnitude/
Lasse Reichstein Nielsen
2013/03/08 07:18:44
On 2013/03/07 17:58:34, srdjan wrote:
> s/_code_ma
Lasse Reichstein Nielsen
2013/03/08 07:18:44
_codeUnitMagnitude even.
|
| /// 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,75 @@ 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; |
| + _code_magnitude |= 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; |
| + _code_magnitude |= 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); |
| + _code_magnitude |= 0xFFFF; |
| + } |
| + } |
| + |
| + /** Makes the buffer empty. */ |
| /* patch */ void clear() { |
| - _buffer = new List<String>(); |
| _length = 0; |
| + _code_magnitude = 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 ""; |
| + return _create(_buffer, _length, _code_magnitude <= 0xFF); |
|
Vyacheslav Egorov (Google)
2013/03/07 13:50:52
consider:
final isLatin1 = _code_magnitude <= 0x
Lasse Reichstein Nielsen
2013/03/08 07:18:44
Done.
|
| } |
| + |
| + /** Ensures that the buffer has enough capacity to contain n code units. */ |
|
srdjan
2013/03/07 17:58:34
s/contain/add/
Lasse Reichstein Nielsen
2013/03/08 07:18:44
Done.
|
| + void _ensureCapacity(int n) { |
| + int requiredCapacity = _length + n; |
| + if (requiredCapacity <= _buffer.length) return; |
|
Vyacheslav Egorov (Google)
2013/03/07 13:50:52
consider
{
return;
}
and more vertical white s
srdjan
2013/03/07 17:58:34
I would split the rare case out:
if (requiredCapac
Lasse Reichstein Nielsen
2013/03/08 07:18:44
Done.
|
| + int newCapacity = _buffer.length; |
| + do { |
| + newCapacity *= 2; |
|
srdjan
2013/03/07 17:58:34
Optional: This growth may be too aggressive. Opini
Lasse Reichstein Nielsen
2013/03/08 07:18:44
I was wondering if it was too small, and consideri
|
| + } 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(List<int> buffer, int length, bool isLatin1) |
|
srdjan
2013/03/07 17:58:34
s/List<int>/Uint16List/
Lasse Reichstein Nielsen
2013/03/08 07:18:44
Done.
|
| + native "StringBuffer_createStringFromUint16Array"; |
| } |