mirror of
https://github.com/dart-lang/sdk
synced 2024-11-05 18:22:09 +00:00
2bb2a12720
The original code _parts = [ str ]; allocated a _GrowableList backed by a single element _List. Subsequent calls to _parts.add() grows the backing list to 2, then 4, etc. On a dart2js workload, allocating with a reasonable initial capacity reduces the number of _List objects allocated by 8%, with 4% reduction in _List bytes allocated. R=lrn@google.com Review URL: https://codereview.chromium.org/1888453011 .
185 lines
5.6 KiB
Dart
185 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.
|
|
|
|
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";
|
|
}
|