// 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 _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) { _parts = [ 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"; }