Unverified Commit 50ea741b authored by gaaclarke's avatar gaaclarke Committed by GitHub

Speed up WriteBuffer by removing some runtime checks in release builds and removing a loop (#80588)

parent eaa2cfdd
...@@ -9,92 +9,109 @@ import 'package:typed_data/typed_buffers.dart' show Uint8Buffer; ...@@ -9,92 +9,109 @@ import 'package:typed_data/typed_buffers.dart' show Uint8Buffer;
/// Write-only buffer for incrementally building a [ByteData] instance. /// Write-only buffer for incrementally building a [ByteData] instance.
/// ///
/// A WriteBuffer instance can be used only once. Attempts to reuse will result /// A WriteBuffer instance can be used only once. Attempts to reuse will result
/// in [NoSuchMethodError]s being thrown. /// in [StateError]s being thrown.
/// ///
/// The byte order used is [Endian.host] throughout. /// The byte order used is [Endian.host] throughout.
class WriteBuffer { class WriteBuffer {
/// Creates an interface for incrementally building a [ByteData] instance. /// Creates an interface for incrementally building a [ByteData] instance.
WriteBuffer() WriteBuffer()
: _buffer = Uint8Buffer(), : _buffer = Uint8Buffer(),
_isDone = false,
_eightBytes = ByteData(8) { _eightBytes = ByteData(8) {
_eightBytesAsList = _eightBytes.buffer.asUint8List(); _eightBytesAsList = _eightBytes.buffer.asUint8List();
} }
Uint8Buffer? _buffer; Uint8Buffer _buffer;
bool _isDone;
final ByteData _eightBytes; final ByteData _eightBytes;
late Uint8List _eightBytesAsList; late Uint8List _eightBytesAsList;
static final Uint8List _zeroBuffer = Uint8List.fromList(<int>[0, 0, 0, 0, 0, 0, 0, 0]);
/// Write a Uint8 into the buffer. /// Write a Uint8 into the buffer.
void putUint8(int byte) { void putUint8(int byte) {
_buffer!.add(byte); assert(!_isDone);
_buffer.add(byte);
} }
/// Write a Uint16 into the buffer. /// Write a Uint16 into the buffer.
void putUint16(int value, {Endian? endian}) { void putUint16(int value, {Endian? endian}) {
assert(!_isDone);
_eightBytes.setUint16(0, value, endian ?? Endian.host); _eightBytes.setUint16(0, value, endian ?? Endian.host);
_buffer!.addAll(_eightBytesAsList, 0, 2); _buffer.addAll(_eightBytesAsList, 0, 2);
} }
/// Write a Uint32 into the buffer. /// Write a Uint32 into the buffer.
void putUint32(int value, {Endian? endian}) { void putUint32(int value, {Endian? endian}) {
assert(!_isDone);
_eightBytes.setUint32(0, value, endian ?? Endian.host); _eightBytes.setUint32(0, value, endian ?? Endian.host);
_buffer!.addAll(_eightBytesAsList, 0, 4); _buffer.addAll(_eightBytesAsList, 0, 4);
} }
/// Write an Int32 into the buffer. /// Write an Int32 into the buffer.
void putInt32(int value, {Endian? endian}) { void putInt32(int value, {Endian? endian}) {
assert(!_isDone);
_eightBytes.setInt32(0, value, endian ?? Endian.host); _eightBytes.setInt32(0, value, endian ?? Endian.host);
_buffer!.addAll(_eightBytesAsList, 0, 4); _buffer.addAll(_eightBytesAsList, 0, 4);
} }
/// Write an Int64 into the buffer. /// Write an Int64 into the buffer.
void putInt64(int value, {Endian? endian}) { void putInt64(int value, {Endian? endian}) {
assert(!_isDone);
_eightBytes.setInt64(0, value, endian ?? Endian.host); _eightBytes.setInt64(0, value, endian ?? Endian.host);
_buffer!.addAll(_eightBytesAsList, 0, 8); _buffer.addAll(_eightBytesAsList, 0, 8);
} }
/// Write an Float64 into the buffer. /// Write an Float64 into the buffer.
void putFloat64(double value, {Endian? endian}) { void putFloat64(double value, {Endian? endian}) {
assert(!_isDone);
_alignTo(8); _alignTo(8);
_eightBytes.setFloat64(0, value, endian ?? Endian.host); _eightBytes.setFloat64(0, value, endian ?? Endian.host);
_buffer!.addAll(_eightBytesAsList); _buffer.addAll(_eightBytesAsList);
} }
/// Write all the values from a [Uint8List] into the buffer. /// Write all the values from a [Uint8List] into the buffer.
void putUint8List(Uint8List list) { void putUint8List(Uint8List list) {
_buffer!.addAll(list); assert(!_isDone);
_buffer.addAll(list);
} }
/// Write all the values from an [Int32List] into the buffer. /// Write all the values from an [Int32List] into the buffer.
void putInt32List(Int32List list) { void putInt32List(Int32List list) {
assert(!_isDone);
_alignTo(4); _alignTo(4);
_buffer!.addAll(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length)); _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length));
} }
/// Write all the values from an [Int64List] into the buffer. /// Write all the values from an [Int64List] into the buffer.
void putInt64List(Int64List list) { void putInt64List(Int64List list) {
assert(!_isDone);
_alignTo(8); _alignTo(8);
_buffer!.addAll(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length)); _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));
} }
/// Write all the values from a [Float64List] into the buffer. /// Write all the values from a [Float64List] into the buffer.
void putFloat64List(Float64List list) { void putFloat64List(Float64List list) {
assert(!_isDone);
_alignTo(8); _alignTo(8);
_buffer!.addAll(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length)); _buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));
} }
void _alignTo(int alignment) { void _alignTo(int alignment) {
final int mod = _buffer!.length % alignment; assert(!_isDone);
final int mod = _buffer.length % alignment;
if (mod != 0) { if (mod != 0) {
for (int i = 0; i < alignment - mod; i++) _buffer.addAll(_zeroBuffer, 0, alignment - mod);
_buffer!.add(0);
} }
} }
/// Finalize and return the written [ByteData]. /// Finalize and return the written [ByteData].
ByteData done() { ByteData done() {
final ByteData result = _buffer!.buffer.asByteData(0, _buffer!.lengthInBytes); if (_isDone) {
_buffer = null; throw StateError('done() must not be called more than once on the same $runtimeType.');
}
final ByteData result = _buffer.buffer.asByteData(0, _buffer.lengthInBytes);
_buffer = Uint8Buffer();
_isDone = true;
return result; return result;
} }
} }
......
...@@ -100,5 +100,10 @@ void main() { ...@@ -100,5 +100,10 @@ void main() {
expect(readDoubles[0], equals(3.14)); expect(readDoubles[0], equals(3.14));
expect(readDoubles[1], isNaN); expect(readDoubles[1], isNaN);
}); });
test('done twice', () {
final WriteBuffer write = WriteBuffer();
write.done();
expect(() => write.done(), throwsStateError);
});
}); });
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment