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;
/// Write-only buffer for incrementally building a [ByteData] instance.
///
/// 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.
class WriteBuffer {
/// Creates an interface for incrementally building a [ByteData] instance.
WriteBuffer()
: _buffer = Uint8Buffer(),
_isDone = false,
_eightBytes = ByteData(8) {
_eightBytesAsList = _eightBytes.buffer.asUint8List();
}
Uint8Buffer? _buffer;
Uint8Buffer _buffer;
bool _isDone;
final ByteData _eightBytes;
late Uint8List _eightBytesAsList;
static final Uint8List _zeroBuffer = Uint8List.fromList(<int>[0, 0, 0, 0, 0, 0, 0, 0]);
/// Write a Uint8 into the buffer.
void putUint8(int byte) {
_buffer!.add(byte);
assert(!_isDone);
_buffer.add(byte);
}
/// Write a Uint16 into the buffer.
void putUint16(int value, {Endian? endian}) {
assert(!_isDone);
_eightBytes.setUint16(0, value, endian ?? Endian.host);
_buffer!.addAll(_eightBytesAsList, 0, 2);
_buffer.addAll(_eightBytesAsList, 0, 2);
}
/// Write a Uint32 into the buffer.
void putUint32(int value, {Endian? endian}) {
assert(!_isDone);
_eightBytes.setUint32(0, value, endian ?? Endian.host);
_buffer!.addAll(_eightBytesAsList, 0, 4);
_buffer.addAll(_eightBytesAsList, 0, 4);
}
/// Write an Int32 into the buffer.
void putInt32(int value, {Endian? endian}) {
assert(!_isDone);
_eightBytes.setInt32(0, value, endian ?? Endian.host);
_buffer!.addAll(_eightBytesAsList, 0, 4);
_buffer.addAll(_eightBytesAsList, 0, 4);
}
/// Write an Int64 into the buffer.
void putInt64(int value, {Endian? endian}) {
assert(!_isDone);
_eightBytes.setInt64(0, value, endian ?? Endian.host);
_buffer!.addAll(_eightBytesAsList, 0, 8);
_buffer.addAll(_eightBytesAsList, 0, 8);
}
/// Write an Float64 into the buffer.
void putFloat64(double value, {Endian? endian}) {
assert(!_isDone);
_alignTo(8);
_eightBytes.setFloat64(0, value, endian ?? Endian.host);
_buffer!.addAll(_eightBytesAsList);
_buffer.addAll(_eightBytesAsList);
}
/// Write all the values from a [Uint8List] into the buffer.
void putUint8List(Uint8List list) {
_buffer!.addAll(list);
assert(!_isDone);
_buffer.addAll(list);
}
/// Write all the values from an [Int32List] into the buffer.
void putInt32List(Int32List list) {
assert(!_isDone);
_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.
void putInt64List(Int64List list) {
assert(!_isDone);
_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.
void putFloat64List(Float64List list) {
assert(!_isDone);
_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) {
final int mod = _buffer!.length % alignment;
assert(!_isDone);
final int mod = _buffer.length % alignment;
if (mod != 0) {
for (int i = 0; i < alignment - mod; i++)
_buffer!.add(0);
_buffer.addAll(_zeroBuffer, 0, alignment - mod);
}
}
/// Finalize and return the written [ByteData].
ByteData done() {
final ByteData result = _buffer!.buffer.asByteData(0, _buffer!.lengthInBytes);
_buffer = null;
if (_isDone) {
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;
}
}
......
......@@ -100,5 +100,10 @@ void main() {
expect(readDoubles[0], equals(3.14));
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