From 32c021bd33f8c6d1be30d19315e4a6a269f8e808 Mon Sep 17 00:00:00 2001 From: Jonah Williams Date: Tue, 22 Mar 2022 15:00:13 -0700 Subject: [PATCH] [framework] use Uint8List for SMC (#100582) --- .../lib/src/foundation/serialization.dart | 58 ++++++++++++++----- .../test/foundation/serialization_test.dart | 6 ++ 2 files changed, 50 insertions(+), 14 deletions(-) diff --git a/packages/flutter/lib/src/foundation/serialization.dart b/packages/flutter/lib/src/foundation/serialization.dart index bf8f777f3556..7fccb62cbee9 100644 --- a/packages/flutter/lib/src/foundation/serialization.dart +++ b/packages/flutter/lib/src/foundation/serialization.dart @@ -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. @@ -13,30 +14,59 @@ import 'dart:typed_data'; class WriteBuffer { /// Creates an interface for incrementally building a [ByteData] instance. factory WriteBuffer() { - final List buffer = []; 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 _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. @@ -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); } @@ -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 = []; + final ByteData result = _buffer.buffer.asByteData(0, _currentSize); + _buffer = Uint8List(0); _isDone = true; return result; } diff --git a/packages/flutter/test/foundation/serialization_test.dart b/packages/flutter/test/foundation/serialization_test.dart index 5c857fbd5b6e..e86b0ad20253 100644 --- a/packages/flutter/test/foundation/serialization_test.dart +++ b/packages/flutter/test/foundation/serialization_test.dart @@ -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);