Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dart: Return dart:typed_data equivalent where possible #8289

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
107 changes: 74 additions & 33 deletions dart/lib/flat_buffers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,34 @@ class BufferContext {
@pragma('vm:prefer-inline')
Uint8List _asUint8List(int offset, int length) =>
_buffer.buffer.asUint8List(_buffer.offsetInBytes + offset, length);

@pragma('vm:prefer-inline')
Int8List _asInt8List(int offset, int length) =>
_buffer.buffer.asInt8List(_buffer.offsetInBytes + offset, length);

@pragma('vm:prefer-inline')
Uint16List _asUint16List(int offset, int length) {
assert(Endian.host == Endian.little);
return _buffer.buffer.asUint16List(_buffer.offsetInBytes + offset, length);
}

@pragma('vm:prefer-inline')
Uint32List _asUint32List(int offset, int length) {
assert(Endian.host == Endian.little);
return _buffer.buffer.asUint32List(_buffer.offsetInBytes + offset, length);
}

@pragma('vm:prefer-inline')
Float32List _asFloat32List(int offset, int length) {
assert(Endian.host == Endian.little);
return _buffer.buffer.asFloat32List(_buffer.offsetInBytes + offset, length);
}

@pragma('vm:prefer-inline')
Float64List _asFloat64List(int offset, int length) {
assert(Endian.host == Endian.little);
return _buffer.buffer.asFloat64List(_buffer.offsetInBytes + offset, length);
}

@pragma('vm:prefer-inline')
double _getFloat64(int offset) => _buffer.getFloat64(offset, Endian.little);
Expand Down Expand Up @@ -729,7 +757,7 @@ class Builder {

@pragma('vm:prefer-inline')
void _writeUTFString(String value) {
final bytes = utf8.encode(value) as Uint8List;
final bytes = utf8.encode(value);
final length = bytes.length;
_prepare(4, 1, additionalBytes: length + 1);
_setUint32AtTail(_tail, length);
Expand Down Expand Up @@ -887,8 +915,15 @@ class Float64ListReader extends Reader<List<double>> {

@override
@pragma('vm:prefer-inline')
List<double> read(BufferContext bc, int offset) =>
_FbFloat64List(bc, bc.derefObject(offset));
List<double> read(BufferContext bc, int offset) {
if (Endian.host == Endian.little) {
final listOffset = bc.derefObject(offset);
final length = bc._getUint32(listOffset);
return bc._asFloat64List(listOffset + _sizeofUint32, length);
} else {
return _FbFloat64List(bc, bc.derefObject(offset));
}
}
Comment on lines +918 to +926
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With this change, test_writeList_ofFloat64 is failing as the offset must be a multiple of BYTES_PER_ELEMENT (8). I'm absolutely missing something simple here, need to wrap my head around what it is (or grab another coffee, maybe).

}

class Float32ListReader extends Reader<List<double>> {
Expand All @@ -900,8 +935,15 @@ class Float32ListReader extends Reader<List<double>> {

@override
@pragma('vm:prefer-inline')
List<double> read(BufferContext bc, int offset) =>
_FbFloat32List(bc, bc.derefObject(offset));
List<double> read(BufferContext bc, int offset) {
if (Endian.host == Endian.little) {
final listOffset = bc.derefObject(offset);
final length = bc._getUint32(listOffset);
return bc._asFloat32List(listOffset + _sizeofUint32, length);
} else {
return _FbFloat32List(bc, bc.derefObject(offset));
}
}
}

class Float64Reader extends Reader<double> {
Expand Down Expand Up @@ -953,7 +995,7 @@ class Int32Reader extends Reader<int> {
int read(BufferContext bc, int offset) => bc._getInt32(offset);
}

/// The reader of signed 32-bit integers.
/// The reader of signed 16-bit integers.
NotTsunami marked this conversation as resolved.
Show resolved Hide resolved
class Int16Reader extends Reader<int> {
const Int16Reader() : super();

Expand All @@ -966,7 +1008,7 @@ class Int16Reader extends Reader<int> {
int read(BufferContext bc, int offset) => bc._getInt16(offset);
}

/// The reader of 8-bit signed integers.
/// The reader of signed 8-bit integers.
class Int8Reader extends Reader<int> {
const Int8Reader() : super();

Expand Down Expand Up @@ -1121,8 +1163,16 @@ class Uint32ListReader extends Reader<List<int>> {

@override
@pragma('vm:prefer-inline')
List<int> read(BufferContext bc, int offset) =>
_FbUint32List(bc, bc.derefObject(offset));
List<int> read(BufferContext bc, int offset) {
if (Endian.host == Endian.little) {
final listOffset = bc.derefObject(offset);
final length = bc._getUint32(listOffset);
return bc._asUint32List(listOffset + _sizeofUint32, length);
} else {
return _FbUint32List(bc, bc.derefObject(offset));
}
}

}

/// The reader of unsigned 64-bit integers.
Expand Down Expand Up @@ -1165,8 +1215,15 @@ class Uint16ListReader extends Reader<List<int>> {

@override
@pragma('vm:prefer-inline')
List<int> read(BufferContext bc, int offset) =>
_FbUint16List(bc, bc.derefObject(offset));
List<int> read(BufferContext bc, int offset) {
if (Endian.host == Endian.little) {
final listOffset = bc.derefObject(offset);
final length = bc._getUint32(listOffset);
return bc._asUint16List(listOffset + _sizeofUint32, length);
} else {
return _FbUint16List(bc, bc.derefObject(offset));
}
}
}

/// The reader of unsigned 32-bit integers.
Expand Down Expand Up @@ -1202,9 +1259,10 @@ class Uint8ListReader extends Reader<List<int>> {
@pragma('vm:prefer-inline')
List<int> read(BufferContext bc, int offset) {
final listOffset = bc.derefObject(offset);
if (lazy) return _FbUint8List(bc, listOffset);

final length = bc._getUint32(listOffset);

if (lazy) return bc._asUint8List(listOffset + _sizeofUint32, length);

final result = Uint8List(length);
var pos = listOffset + _sizeofUint32;
for (var i = 0; i < length; i++, pos++) {
Expand Down Expand Up @@ -1247,9 +1305,10 @@ class Int8ListReader extends Reader<List<int>> {
@pragma('vm:prefer-inline')
List<int> read(BufferContext bc, int offset) {
final listOffset = bc.derefObject(offset);
if (lazy) return _FbUint8List(bc, listOffset);

final length = bc._getUint32(listOffset);

if (lazy) return bc._asInt8List(listOffset + _sizeofUint32, length);

final result = Int8List(length);
var pos = listOffset + _sizeofUint32;
for (var i = 0; i < length; i++, pos++) {
Expand Down Expand Up @@ -1337,24 +1396,6 @@ class _FbUint16List extends _FbList<int> {
int operator [](int i) => bc._getUint16(offset + 4 + 2 * i);
}

/// List backed by 8-bit unsigned integers.
class _FbUint8List extends _FbList<int> {
_FbUint8List(BufferContext bc, int offset) : super(bc, offset);

@override
@pragma('vm:prefer-inline')
int operator [](int i) => bc._getUint8(offset + 4 + i);
}

/// List backed by 8-bit signed integers.
class _FbInt8List extends _FbList<int> {
_FbInt8List(BufferContext bc, int offset) : super(bc, offset);

@override
@pragma('vm:prefer-inline')
int operator [](int i) => bc._getInt8(offset + 4 + i);
}

/// List backed by 8-bit unsigned integers.
class _FbBoolList extends _FbList<bool> {
_FbBoolList(BufferContext bc, int offset) : super(bc, offset);
Expand Down
40 changes: 36 additions & 4 deletions dart/test/flat_buffers_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// ignore_for_file: non_constant_identifier_names

import 'dart:typed_data';
import 'dart:io' as io;

Expand Down Expand Up @@ -543,7 +545,7 @@ class BuilderTest {
// read and verify
BufferContext buf = BufferContext.fromBytes(byteList);
List<double> items = const Float64ListReader().read(buf, 0);

expect(items is Float64List, Endian.host == Endian.little);
expect(items, hasLength(values.length));
for (int i = 0; i < values.length; i++) {
expect(values[i], closeTo(items[i], .001));
Expand All @@ -563,6 +565,7 @@ class BuilderTest {
// read and verify
BufferContext buf = BufferContext.fromBytes(byteList);
List<double> items = const Float32ListReader().read(buf, 0);
expect(items is Float32List, Endian.host == Endian.little);
expect(items, hasLength(5));
for (int i = 0; i < values.length; i++) {
expect(values[i], closeTo(items[i], .001));
Expand Down Expand Up @@ -655,6 +658,7 @@ class BuilderTest {
// read and verify
BufferContext buf = BufferContext.fromBytes(byteList);
List<int> items = const Uint32ListReader().read(buf, 0);
expect(items is Uint32List, Endian.host == Endian.little);
expect(items, hasLength(3));
expect(items, orderedEquals(<int>[1, 2, 0x9ABCDEF0]));
}
Expand All @@ -670,6 +674,7 @@ class BuilderTest {
// read and verify
BufferContext buf = BufferContext.fromBytes(byteList);
List<int> items = const Uint16ListReader().read(buf, 0);
expect(items is Uint16List, Endian.host == Endian.little);
expect(items, hasLength(3));
expect(items, orderedEquals(<int>[1, 2, 60000]));
}
Expand All @@ -687,18 +692,45 @@ class BuilderTest {
const buffOffset = 8; // 32-bit offset to the list, + 32-bit length
for (final lazy in [true, false]) {
List<int> items = Uint8ListReader(lazy: lazy).read(buf, 0);
expect(items is Uint8List, true);
expect(items, hasLength(6));
expect(items, orderedEquals(<int>[1, 2, 3, 4, 0x9A, 0xFA]));
expect(items, orderedEquals(<int>[1, 2, 3, 4, 154, 250]));

// overwrite the buffer to verify the laziness
buf.buffer.setUint8(buffOffset + 1, 99);
expect(items, orderedEquals(<int>[1, lazy ? 99 : 2, 3, 4, 0x9A, 0xFA]));
expect(items, orderedEquals(<int>[1, lazy ? 99 : 2, 3, 4, 154, 250]));

// restore the previous value for the next loop
buf.buffer.setUint8(buffOffset + 1, 2);
}
}

void test_writeList_ofInt8() {
List<int> byteList;
{
Builder builder = Builder(initialSize: 0);
int offset = builder.writeListInt8(<int>[1, 2, 3, 4, 0x9A, 0xFA]);
builder.finish(offset);
byteList = builder.buffer;
}
// read and verify
BufferContext buf = BufferContext.fromBytes(byteList);
const buffOffset = 8; // 32-bit offset to the list, + 32-bit length
for (final lazy in [true, false]) {
List<int> items = Int8ListReader(lazy: lazy).read(buf, 0);
expect(items is Int8List, true);
expect(items, hasLength(6));
expect(items, orderedEquals(<int>[1, 2, 3, 4, -102, -6]));

// overwrite the buffer to verify the laziness
buf.buffer.setInt8(buffOffset + 1, 99);
expect(items, orderedEquals(<int>[1, lazy ? 99 : 2, 3, 4, -102, -6]));

// restore the previous value for the next loop
buf.buffer.setInt8(buffOffset + 1, 2);
}
}

void test_reset() {
// We'll run a selection of tests , reusing the builder between them.
final testCases = <void Function(Builder?)>[
Expand Down Expand Up @@ -817,9 +849,9 @@ class ObjectAPITest {
final offset = monster.pack(fbBuilder);
expect(offset, isNonZero);
fbBuilder.finish(offset);
final data = fbBuilder.buffer;

// TODO currently broken because of struct builder issue, see #6688
// final data = fbBuilder.buffer;
// final monster2 = example.Monster(data); // Monster (reader)
// expect(
// // map Monster => MonsterT, Vec3 => Vec3T, ...
Expand Down