mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 01:45:06 +00:00
e8aef37eac
Change-Id: Ie436375c78496366accf0ba82938e54cbe30b143 Reviewed-on: https://dart-review.googlesource.com/3001 Commit-Queue: Peter von der Ahé <ahe@google.com> Reviewed-by: Lasse R.H. Nielsen <lrn@google.com> Reviewed-by: Vyacheslav Egorov <vegorov@google.com> Reviewed-by: Johnni Winther <johnniwinther@google.com>
197 lines
5.6 KiB
Dart
197 lines
5.6 KiB
Dart
// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
|
|
// for details. All rights reserved. Use of this source code is governed by a
|
|
// BSD-style license that can be found in the LICENSE file.
|
|
|
|
// part of "core_patch.dart";
|
|
|
|
@patch
|
|
class StringBuffer {
|
|
static const int _BUFFER_SIZE = 64;
|
|
static const int _PARTS_TO_COMPACT = 128;
|
|
static const int _PARTS_TO_COMPACT_SIZE_LIMIT = _PARTS_TO_COMPACT * 8;
|
|
|
|
/**
|
|
* When strings are written to the string buffer, we add them to a
|
|
* list of string parts.
|
|
*/
|
|
List<String> _parts;
|
|
|
|
/**
|
|
* Total number of code units in the string parts. Does not include
|
|
* the code units added to the buffer.
|
|
*/
|
|
int _partsCodeUnits = 0;
|
|
|
|
/**
|
|
* To preserve memory, we sometimes compact the parts. This combines
|
|
* several smaller parts into a single larger part to cut down on the
|
|
* cost that comes from the per-object memory overhead. We keep track
|
|
* of the last index where we ended our compaction and the number of
|
|
* code units added since the last compaction.
|
|
*/
|
|
int _partsCompactionIndex = 0;
|
|
int _partsCodeUnitsSinceCompaction = 0;
|
|
|
|
/**
|
|
* The buffer is used to build up a string from code units. It is
|
|
* used when writing short strings or individual char codes to the
|
|
* buffer. The buffer is allocated on demand.
|
|
*/
|
|
Uint16List _buffer;
|
|
int _bufferPosition = 0;
|
|
|
|
/**
|
|
* Collects the approximate maximal magnitude of the code units added
|
|
* to the buffer.
|
|
*
|
|
* 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 in the buffer is a Latin-1 string.
|
|
*/
|
|
int _bufferCodeUnitMagnitude = 0;
|
|
|
|
/// Creates the string buffer with an initial content.
|
|
@patch
|
|
StringBuffer([Object content = ""]) {
|
|
write(content);
|
|
}
|
|
|
|
@patch
|
|
int get length => _partsCodeUnits + _bufferPosition;
|
|
|
|
@patch
|
|
void write(Object obj) {
|
|
String str = '$obj';
|
|
if (str.isEmpty) return;
|
|
_consumeBuffer();
|
|
_addPart(str);
|
|
}
|
|
|
|
@patch
|
|
void writeCharCode(int charCode) {
|
|
if (charCode <= 0xFFFF) {
|
|
if (charCode < 0) {
|
|
throw new RangeError.range(charCode, 0, 0x10FFFF);
|
|
}
|
|
_ensureCapacity(1);
|
|
_buffer[_bufferPosition++] = charCode;
|
|
_bufferCodeUnitMagnitude |= charCode;
|
|
} else {
|
|
if (charCode > 0x10FFFF) {
|
|
throw new RangeError.range(charCode, 0, 0x10FFFF);
|
|
}
|
|
_ensureCapacity(2);
|
|
int bits = charCode - 0x10000;
|
|
_buffer[_bufferPosition++] = 0xD800 | (bits >> 10);
|
|
_buffer[_bufferPosition++] = 0xDC00 | (bits & 0x3FF);
|
|
_bufferCodeUnitMagnitude |= 0xFFFF;
|
|
}
|
|
}
|
|
|
|
@patch
|
|
void writeAll(Iterable objects, [String separator = ""]) {
|
|
Iterator iterator = objects.iterator;
|
|
if (!iterator.moveNext()) return;
|
|
if (separator.isEmpty) {
|
|
do {
|
|
write(iterator.current);
|
|
} while (iterator.moveNext());
|
|
} else {
|
|
write(iterator.current);
|
|
while (iterator.moveNext()) {
|
|
write(separator);
|
|
write(iterator.current);
|
|
}
|
|
}
|
|
}
|
|
|
|
@patch
|
|
void writeln([Object obj = ""]) {
|
|
write(obj);
|
|
write("\n");
|
|
}
|
|
|
|
/** Makes the buffer empty. */
|
|
@patch
|
|
void clear() {
|
|
_parts = null;
|
|
_partsCodeUnits = _bufferPosition = _bufferCodeUnitMagnitude = 0;
|
|
}
|
|
|
|
/** Returns the contents of buffer as a string. */
|
|
@patch
|
|
String toString() {
|
|
_consumeBuffer();
|
|
return (_partsCodeUnits == 0)
|
|
? ""
|
|
: _StringBase._concatRange(_parts, 0, _parts.length);
|
|
}
|
|
|
|
/** Ensures that the buffer has enough capacity to add n code units. */
|
|
void _ensureCapacity(int n) {
|
|
if (_buffer == null) {
|
|
_buffer = new Uint16List(_BUFFER_SIZE);
|
|
} else if (_bufferPosition + n > _buffer.length) {
|
|
_consumeBuffer();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Consumes the content of the buffer by turning it into a string
|
|
* and adding it as a part. After calling this the buffer position
|
|
* will be reset to zero.
|
|
*/
|
|
void _consumeBuffer() {
|
|
if (_bufferPosition == 0) return;
|
|
bool isLatin1 = _bufferCodeUnitMagnitude <= 0xFF;
|
|
String str = _create(_buffer, _bufferPosition, isLatin1);
|
|
_bufferPosition = _bufferCodeUnitMagnitude = 0;
|
|
_addPart(str);
|
|
}
|
|
|
|
/**
|
|
* Adds a new part to this string buffer and keeps track of how
|
|
* many code units are contained in the parts.
|
|
*/
|
|
void _addPart(String str) {
|
|
int length = str.length;
|
|
_partsCodeUnits += length;
|
|
_partsCodeUnitsSinceCompaction += length;
|
|
|
|
if (_parts == null) {
|
|
// Empirically this is a good capacity to minimize total bytes allocated.
|
|
_parts = new _GrowableList.withCapacity(10)..add(str);
|
|
} else {
|
|
_parts.add(str);
|
|
int partsSinceCompaction = _parts.length - _partsCompactionIndex;
|
|
if (partsSinceCompaction == _PARTS_TO_COMPACT) {
|
|
_compact();
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Compacts the last N parts if their average size allows us to save a
|
|
* lot of memory by turning them all into a single part.
|
|
*/
|
|
void _compact() {
|
|
if (_partsCodeUnitsSinceCompaction < _PARTS_TO_COMPACT_SIZE_LIMIT) {
|
|
String compacted = _StringBase._concatRange(
|
|
_parts,
|
|
_partsCompactionIndex, // Start
|
|
_partsCompactionIndex + _PARTS_TO_COMPACT // End
|
|
);
|
|
_parts.length = _parts.length - _PARTS_TO_COMPACT;
|
|
_parts.add(compacted);
|
|
}
|
|
_partsCodeUnitsSinceCompaction = 0;
|
|
_partsCompactionIndex = _parts.length;
|
|
}
|
|
|
|
/**
|
|
* Create a [String] from the UFT-16 code units in buffer.
|
|
*/
|
|
static String _create(Uint16List buffer, int length, bool isLatin1)
|
|
native "StringBuffer_createStringFromUint16Array";
|
|
}
|