Speed up WriteBuffer by removing some runtime checks in release builds and removing a loop (#80588)
This commit is contained in:
parent
eaa2cfdd3a
commit
50ea741b4c
@ -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() {
|
|||||||
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);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user