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"; |
} |