Skip to content

Commit

Permalink
[framework] use Uint8List for SMC (#100582)
Browse files Browse the repository at this point in the history
  • Loading branch information
jonahwilliams authored Mar 22, 2022
1 parent 015732c commit 32c021b
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 14 deletions.
58 changes: 44 additions & 14 deletions packages/flutter/lib/src/foundation/serialization.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'dart:math' as math;
import 'dart:typed_data';

/// Write-only buffer for incrementally building a [ByteData] instance.
Expand All @@ -13,30 +14,59 @@ import 'dart:typed_data';
class WriteBuffer {
/// Creates an interface for incrementally building a [ByteData] instance.
factory WriteBuffer() {
final List<int> buffer = <int>[];
final ByteData eightBytes = ByteData(8);
final Uint8List eightBytesAsList = eightBytes.buffer.asUint8List();
return WriteBuffer._(buffer, eightBytes, eightBytesAsList);
return WriteBuffer._(Uint8List(8), eightBytes, eightBytesAsList);
}

WriteBuffer._(this._buffer, this._eightBytes, this._eightBytesAsList);

List<int> _buffer;
Uint8List _buffer;
int _currentSize = 0;
bool _isDone = false;
final ByteData _eightBytes;
final Uint8List _eightBytesAsList;
static final Uint8List _zeroBuffer = Uint8List(8);

void _add(int byte) {
if (_currentSize == _buffer.length) {
_resize();
}
_buffer[_currentSize] = byte;
_currentSize += 1;
}

void _append(Uint8List other) {
final int newSize = _currentSize + other.length;
if (newSize >= _buffer.length) {
_resize(newSize);
}
_buffer.setRange(_currentSize, newSize, other);
_currentSize += other.length;
}

void _addAll(Uint8List data, [int start = 0, int? end]) {
for (int i = start; i < (end ?? _eightBytesAsList.length); i++) {
_buffer.add(data[i]);
final int newEnd = end ?? _eightBytesAsList.length;
final int newSize = _currentSize + (newEnd - start);
if (newSize >= _buffer.length) {
_resize(newSize);
}
_buffer.setRange(_currentSize, newSize, data);
_currentSize = newSize;
}

void _resize([int? requiredLength]) {
final int doubleLength = _buffer.length * 2;
final int newLength = math.max(requiredLength ?? 0, doubleLength);
final Uint8List newBuffer = Uint8List(newLength);
newBuffer.setRange(0, _buffer.length, _buffer);
_buffer = newBuffer;
}

/// Write a Uint8 into the buffer.
void putUint8(int byte) {
assert(!_isDone);
_buffer.add(byte);
_add(byte);
}

/// Write a Uint16 into the buffer.
Expand Down Expand Up @@ -78,40 +108,40 @@ class WriteBuffer {
/// Write all the values from a [Uint8List] into the buffer.
void putUint8List(Uint8List list) {
assert(!_isDone);
_buffer.addAll(list);
_append(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));
_append(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));
_append(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));
}

/// Write all the values from a [Float32List] into the buffer.
void putFloat32List(Float32List list) {
assert(!_isDone);
_alignTo(4);
_buffer.addAll(list.buffer.asUint8List(list.offsetInBytes, 4 * list.length));
_append(list.buffer.asUint8List(list.offsetInBytes, 4 * 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));
_append(list.buffer.asUint8List(list.offsetInBytes, 8 * list.length));
}

void _alignTo(int alignment) {
assert(!_isDone);
final int mod = _buffer.length % alignment;
final int mod = _currentSize % alignment;
if (mod != 0) {
_addAll(_zeroBuffer, 0, alignment - mod);
}
Expand All @@ -122,8 +152,8 @@ class WriteBuffer {
if (_isDone) {
throw StateError('done() must not be called more than once on the same $runtimeType.');
}
final ByteData result = Uint8List.fromList(_buffer).buffer.asByteData();
_buffer = <int>[];
final ByteData result = _buffer.buffer.asByteData(0, _currentSize);
_buffer = Uint8List(0);
_isDone = true;
return result;
}
Expand Down
6 changes: 6 additions & 0 deletions packages/flutter/test/foundation/serialization_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ import 'package:flutter_test/flutter_test.dart';

void main() {
group('Write and read buffer round-trip', () {
test('of empty buffer', () {
final WriteBuffer write = WriteBuffer();
final ByteData written = write.done();

expect(written.lengthInBytes, 0);
});
test('of single byte', () {
final WriteBuffer write = WriteBuffer();
write.putUint8(201);
Expand Down

0 comments on commit 32c021b

Please sign in to comment.