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.
|
||||
///
|
||||
/// 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);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user