mirror of
https://github.com/google/flatbuffers.git
synced 2026-07-01 17:23:57 +00:00
Dart - unpack() must use eager list reader (#6723)
This commit is contained in:
@@ -907,20 +907,34 @@ class Int8Reader extends Reader<int> {
|
|||||||
int read(BufferContext bc, int offset) => bc._getInt8(offset);
|
int read(BufferContext bc, int offset) => bc._getInt8(offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The reader of lists of objects.
|
/// The reader of lists of objects. Lazy by default - see [lazy].
|
||||||
///
|
|
||||||
/// The returned unmodifiable lists lazily read objects on access.
|
|
||||||
class ListReader<E> extends Reader<List<E>> {
|
class ListReader<E> extends Reader<List<E>> {
|
||||||
final Reader<E> _elementReader;
|
final Reader<E> _elementReader;
|
||||||
|
|
||||||
const ListReader(this._elementReader);
|
/// Enables lazy reading of the list
|
||||||
|
///
|
||||||
|
/// If true, the returned unmodifiable list lazily reads objects on access.
|
||||||
|
/// Therefore, the underlying buffer must not change while accessing the list.
|
||||||
|
///
|
||||||
|
/// If false, reads the whole list immediately on access.
|
||||||
|
final bool lazy;
|
||||||
|
|
||||||
|
const ListReader(this._elementReader, {this.lazy = true});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
int get size => _sizeofUint32;
|
int get size => _sizeofUint32;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
List<E> read(BufferContext bc, int offset) =>
|
List<E> read(BufferContext bc, int offset) {
|
||||||
new _FbGenericList<E>(_elementReader, bc, bc.derefObject(offset));
|
final listOffset = bc.derefObject(offset);
|
||||||
|
return lazy
|
||||||
|
? _FbGenericList<E>(_elementReader, bc, listOffset)
|
||||||
|
: List<E>.generate(
|
||||||
|
bc.buffer.getUint32(listOffset, Endian.little),
|
||||||
|
(int index) => _elementReader.read(
|
||||||
|
bc, listOffset + size + _elementReader.size * index),
|
||||||
|
growable: true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Object that can read a value at a [BufferContext].
|
/// Object that can read a value at a [BufferContext].
|
||||||
|
|||||||
@@ -763,6 +763,28 @@ class ObjectAPITest {
|
|||||||
// final monster3 = monster2.unpack(); // MonsterT
|
// final monster3 = monster2.unpack(); // MonsterT
|
||||||
// expect(monster3.toString(), monster.toString());
|
// expect(monster3.toString(), monster.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void test_Lists() {
|
||||||
|
// Ensure unpack() reads lists eagerly by reusing the same builder and
|
||||||
|
// overwriting data. Why: because standard reader reads lists lazily...
|
||||||
|
final fbb = Builder();
|
||||||
|
|
||||||
|
final object1 = example.TypeAliasesT(v8: [1, 2, 3], vf64: [5, 6]);
|
||||||
|
final data1 = fbb.finish(object1.pack(fbb));
|
||||||
|
final object1Read = example.TypeAliases(data1).unpack();
|
||||||
|
|
||||||
|
// overwrite the original buffer by writing to the same builder
|
||||||
|
fbb.reset();
|
||||||
|
final object2 = example.TypeAliasesT(v8: [7, 8, 9], vf64: [10, 11]);
|
||||||
|
final data2 = fbb.finish(object2.pack(fbb));
|
||||||
|
final object2Read = example.TypeAliases(data2).unpack();
|
||||||
|
|
||||||
|
// this is fine even with lazy lists:
|
||||||
|
expect(object2.toString(), object2Read.toString());
|
||||||
|
|
||||||
|
// this fails with lazy lists:
|
||||||
|
expect(object1.toString(), object1Read.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class StringListWrapperImpl {
|
class StringListWrapperImpl {
|
||||||
|
|||||||
@@ -1117,15 +1117,15 @@ class Monster {
|
|||||||
mana: mana,
|
mana: mana,
|
||||||
hp: hp,
|
hp: hp,
|
||||||
name: name,
|
name: name,
|
||||||
inventory: inventory,
|
inventory: const fb.ListReader<int>(const fb.Uint8Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 14),
|
||||||
color: color,
|
color: color,
|
||||||
testType: testType,
|
testType: testType,
|
||||||
test: test,
|
test: test,
|
||||||
test4: test4?.map((e) => e.unpack()).toList(),
|
test4: test4?.map((e) => e.unpack()).toList(),
|
||||||
testarrayofstring: testarrayofstring,
|
testarrayofstring: const fb.ListReader<String>(const fb.StringReader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 24),
|
||||||
testarrayoftables: testarrayoftables?.map((e) => e.unpack()).toList(),
|
testarrayoftables: testarrayoftables?.map((e) => e.unpack()).toList(),
|
||||||
enemy: enemy?.unpack(),
|
enemy: enemy?.unpack(),
|
||||||
testnestedflatbuffer: testnestedflatbuffer,
|
testnestedflatbuffer: const fb.ListReader<int>(const fb.Uint8Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 30),
|
||||||
testempty: testempty?.unpack(),
|
testempty: testempty?.unpack(),
|
||||||
testbool: testbool,
|
testbool: testbool,
|
||||||
testhashs32Fnv1: testhashs32Fnv1,
|
testhashs32Fnv1: testhashs32Fnv1,
|
||||||
@@ -1136,32 +1136,32 @@ class Monster {
|
|||||||
testhashu32Fnv1a: testhashu32Fnv1a,
|
testhashu32Fnv1a: testhashu32Fnv1a,
|
||||||
testhashs64Fnv1a: testhashs64Fnv1a,
|
testhashs64Fnv1a: testhashs64Fnv1a,
|
||||||
testhashu64Fnv1a: testhashu64Fnv1a,
|
testhashu64Fnv1a: testhashu64Fnv1a,
|
||||||
testarrayofbools: testarrayofbools,
|
testarrayofbools: const fb.ListReader<bool>(const fb.BoolReader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 52),
|
||||||
testf: testf,
|
testf: testf,
|
||||||
testf2: testf2,
|
testf2: testf2,
|
||||||
testf3: testf3,
|
testf3: testf3,
|
||||||
testarrayofstring2: testarrayofstring2,
|
testarrayofstring2: const fb.ListReader<String>(const fb.StringReader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 60),
|
||||||
testarrayofsortedstruct: testarrayofsortedstruct?.map((e) => e.unpack()).toList(),
|
testarrayofsortedstruct: testarrayofsortedstruct?.map((e) => e.unpack()).toList(),
|
||||||
flex: flex,
|
flex: const fb.ListReader<int>(const fb.Uint8Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 64),
|
||||||
test5: test5?.map((e) => e.unpack()).toList(),
|
test5: test5?.map((e) => e.unpack()).toList(),
|
||||||
vectorOfLongs: vectorOfLongs,
|
vectorOfLongs: const fb.ListReader<int>(const fb.Int64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 68),
|
||||||
vectorOfDoubles: vectorOfDoubles,
|
vectorOfDoubles: const fb.ListReader<double>(const fb.Float64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 70),
|
||||||
parentNamespaceTest: parentNamespaceTest?.unpack(),
|
parentNamespaceTest: parentNamespaceTest?.unpack(),
|
||||||
vectorOfReferrables: vectorOfReferrables?.map((e) => e.unpack()).toList(),
|
vectorOfReferrables: vectorOfReferrables?.map((e) => e.unpack()).toList(),
|
||||||
singleWeakReference: singleWeakReference,
|
singleWeakReference: singleWeakReference,
|
||||||
vectorOfWeakReferences: vectorOfWeakReferences,
|
vectorOfWeakReferences: const fb.ListReader<int>(const fb.Uint64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 78),
|
||||||
vectorOfStrongReferrables: vectorOfStrongReferrables?.map((e) => e.unpack()).toList(),
|
vectorOfStrongReferrables: vectorOfStrongReferrables?.map((e) => e.unpack()).toList(),
|
||||||
coOwningReference: coOwningReference,
|
coOwningReference: coOwningReference,
|
||||||
vectorOfCoOwningReferences: vectorOfCoOwningReferences,
|
vectorOfCoOwningReferences: const fb.ListReader<int>(const fb.Uint64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 84),
|
||||||
nonOwningReference: nonOwningReference,
|
nonOwningReference: nonOwningReference,
|
||||||
vectorOfNonOwningReferences: vectorOfNonOwningReferences,
|
vectorOfNonOwningReferences: const fb.ListReader<int>(const fb.Uint64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 88),
|
||||||
anyUniqueType: anyUniqueType,
|
anyUniqueType: anyUniqueType,
|
||||||
anyUnique: anyUnique,
|
anyUnique: anyUnique,
|
||||||
anyAmbiguousType: anyAmbiguousType,
|
anyAmbiguousType: anyAmbiguousType,
|
||||||
anyAmbiguous: anyAmbiguous,
|
anyAmbiguous: anyAmbiguous,
|
||||||
vectorOfEnums: vectorOfEnums,
|
vectorOfEnums: const fb.ListReader<Color>(Color.reader, lazy: false).vTableGetNullable(_bc, _bcOffset, 98),
|
||||||
signedEnum: signedEnum,
|
signedEnum: signedEnum,
|
||||||
testrequirednestedflatbuffer: testrequirednestedflatbuffer,
|
testrequirednestedflatbuffer: const fb.ListReader<int>(const fb.Uint8Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 102),
|
||||||
scalarKeySortedTables: scalarKeySortedTables?.map((e) => e.unpack()).toList());
|
scalarKeySortedTables: scalarKeySortedTables?.map((e) => e.unpack()).toList());
|
||||||
|
|
||||||
static int pack(fb.Builder fbBuilder, MonsterT? object) {
|
static int pack(fb.Builder fbBuilder, MonsterT? object) {
|
||||||
@@ -1966,8 +1966,8 @@ class TypeAliases {
|
|||||||
u64: u64,
|
u64: u64,
|
||||||
f32: f32,
|
f32: f32,
|
||||||
f64: f64,
|
f64: f64,
|
||||||
v8: v8,
|
v8: const fb.ListReader<int>(const fb.Int8Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 24),
|
||||||
vf64: vf64);
|
vf64: const fb.ListReader<double>(const fb.Float64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 26));
|
||||||
|
|
||||||
static int pack(fb.Builder fbBuilder, TypeAliasesT? object) {
|
static int pack(fb.Builder fbBuilder, TypeAliasesT? object) {
|
||||||
if (object == null) return 0;
|
if (object == null) return 0;
|
||||||
|
|||||||
@@ -330,7 +330,8 @@ class DartGenerator : public BaseGenerator {
|
|||||||
|
|
||||||
std::string GenReaderTypeName(const Type &type, Namespace *current_namespace,
|
std::string GenReaderTypeName(const Type &type, Namespace *current_namespace,
|
||||||
const FieldDef &def,
|
const FieldDef &def,
|
||||||
bool parent_is_vector = false) {
|
bool parent_is_vector = false,
|
||||||
|
bool lazy = true) {
|
||||||
if (type.base_type == BASE_TYPE_BOOL) {
|
if (type.base_type == BASE_TYPE_BOOL) {
|
||||||
return "const " + _kFb + ".BoolReader()";
|
return "const " + _kFb + ".BoolReader()";
|
||||||
} else if (IsVector(type)) {
|
} else if (IsVector(type)) {
|
||||||
@@ -338,7 +339,7 @@ class DartGenerator : public BaseGenerator {
|
|||||||
GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" +
|
GenDartTypeName(type.VectorType(), current_namespace, def) + ">(" +
|
||||||
GenReaderTypeName(type.VectorType(), current_namespace, def,
|
GenReaderTypeName(type.VectorType(), current_namespace, def,
|
||||||
true) +
|
true) +
|
||||||
")";
|
(lazy ? ")" : ", lazy: false)");
|
||||||
} else if (IsString(type)) {
|
} else if (IsString(type)) {
|
||||||
return "const " + _kFb + ".StringReader()";
|
return "const " + _kFb + ".StringReader()";
|
||||||
}
|
}
|
||||||
@@ -556,18 +557,32 @@ class DartGenerator : public BaseGenerator {
|
|||||||
|
|
||||||
std::string field_name = MakeCamel(field.name, false);
|
std::string field_name = MakeCamel(field.name, false);
|
||||||
if (!constructor_args.empty()) constructor_args += ",\n";
|
if (!constructor_args.empty()) constructor_args += ",\n";
|
||||||
constructor_args += " " + field_name + ": " + field_name;
|
constructor_args += " " + field_name + ": ";
|
||||||
|
|
||||||
const Type &type = field.value.type;
|
const Type &type = field.value.type;
|
||||||
bool isNullable =
|
std::string defaultValue = getDefaultValue(field.value);
|
||||||
getDefaultValue(field.value).empty() && !struct_def.fixed;
|
bool isNullable = defaultValue.empty() && !struct_def.fixed;
|
||||||
std::string nullableValueAccessOperator = isNullable ? "?" : "";
|
std::string nullableValueAccessOperator = isNullable ? "?" : "";
|
||||||
if (type.base_type == BASE_TYPE_STRUCT) {
|
if (type.base_type == BASE_TYPE_STRUCT) {
|
||||||
constructor_args += nullableValueAccessOperator + ".unpack()";
|
|
||||||
} else if (type.base_type == BASE_TYPE_VECTOR &&
|
|
||||||
type.VectorType().base_type == BASE_TYPE_STRUCT) {
|
|
||||||
constructor_args +=
|
constructor_args +=
|
||||||
nullableValueAccessOperator + ".map((e) => e.unpack()).toList()";
|
field_name + nullableValueAccessOperator + ".unpack()";
|
||||||
|
} else if (type.base_type == BASE_TYPE_VECTOR) {
|
||||||
|
if (type.VectorType().base_type == BASE_TYPE_STRUCT) {
|
||||||
|
constructor_args += field_name + nullableValueAccessOperator +
|
||||||
|
".map((e) => e.unpack()).toList()";
|
||||||
|
} else {
|
||||||
|
constructor_args +=
|
||||||
|
GenReaderTypeName(field.value.type, struct_def.defined_namespace,
|
||||||
|
field, false, false);
|
||||||
|
constructor_args += ".vTableGet";
|
||||||
|
std::string offset = NumToString(field.value.offset);
|
||||||
|
constructor_args +=
|
||||||
|
isNullable
|
||||||
|
? "Nullable(_bc, _bcOffset, " + offset + ")"
|
||||||
|
: "(_bc, _bcOffset, " + offset + ", " + defaultValue + ")";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
constructor_args += field_name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ class MonsterExtra {
|
|||||||
f1: f1,
|
f1: f1,
|
||||||
f2: f2,
|
f2: f2,
|
||||||
f3: f3,
|
f3: f3,
|
||||||
dvec: dvec,
|
dvec: const fb.ListReader<double>(const fb.Float64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 20),
|
||||||
fvec: fvec);
|
fvec: const fb.ListReader<double>(const fb.Float32Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 22));
|
||||||
|
|
||||||
static int pack(fb.Builder fbBuilder, MonsterExtraT? object) {
|
static int pack(fb.Builder fbBuilder, MonsterExtraT? object) {
|
||||||
if (object == null) return 0;
|
if (object == null) return 0;
|
||||||
|
|||||||
@@ -1117,15 +1117,15 @@ class Monster {
|
|||||||
mana: mana,
|
mana: mana,
|
||||||
hp: hp,
|
hp: hp,
|
||||||
name: name,
|
name: name,
|
||||||
inventory: inventory,
|
inventory: const fb.ListReader<int>(const fb.Uint8Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 14),
|
||||||
color: color,
|
color: color,
|
||||||
testType: testType,
|
testType: testType,
|
||||||
test: test,
|
test: test,
|
||||||
test4: test4?.map((e) => e.unpack()).toList(),
|
test4: test4?.map((e) => e.unpack()).toList(),
|
||||||
testarrayofstring: testarrayofstring,
|
testarrayofstring: const fb.ListReader<String>(const fb.StringReader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 24),
|
||||||
testarrayoftables: testarrayoftables?.map((e) => e.unpack()).toList(),
|
testarrayoftables: testarrayoftables?.map((e) => e.unpack()).toList(),
|
||||||
enemy: enemy?.unpack(),
|
enemy: enemy?.unpack(),
|
||||||
testnestedflatbuffer: testnestedflatbuffer,
|
testnestedflatbuffer: const fb.ListReader<int>(const fb.Uint8Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 30),
|
||||||
testempty: testempty?.unpack(),
|
testempty: testempty?.unpack(),
|
||||||
testbool: testbool,
|
testbool: testbool,
|
||||||
testhashs32Fnv1: testhashs32Fnv1,
|
testhashs32Fnv1: testhashs32Fnv1,
|
||||||
@@ -1136,32 +1136,32 @@ class Monster {
|
|||||||
testhashu32Fnv1a: testhashu32Fnv1a,
|
testhashu32Fnv1a: testhashu32Fnv1a,
|
||||||
testhashs64Fnv1a: testhashs64Fnv1a,
|
testhashs64Fnv1a: testhashs64Fnv1a,
|
||||||
testhashu64Fnv1a: testhashu64Fnv1a,
|
testhashu64Fnv1a: testhashu64Fnv1a,
|
||||||
testarrayofbools: testarrayofbools,
|
testarrayofbools: const fb.ListReader<bool>(const fb.BoolReader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 52),
|
||||||
testf: testf,
|
testf: testf,
|
||||||
testf2: testf2,
|
testf2: testf2,
|
||||||
testf3: testf3,
|
testf3: testf3,
|
||||||
testarrayofstring2: testarrayofstring2,
|
testarrayofstring2: const fb.ListReader<String>(const fb.StringReader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 60),
|
||||||
testarrayofsortedstruct: testarrayofsortedstruct?.map((e) => e.unpack()).toList(),
|
testarrayofsortedstruct: testarrayofsortedstruct?.map((e) => e.unpack()).toList(),
|
||||||
flex: flex,
|
flex: const fb.ListReader<int>(const fb.Uint8Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 64),
|
||||||
test5: test5?.map((e) => e.unpack()).toList(),
|
test5: test5?.map((e) => e.unpack()).toList(),
|
||||||
vectorOfLongs: vectorOfLongs,
|
vectorOfLongs: const fb.ListReader<int>(const fb.Int64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 68),
|
||||||
vectorOfDoubles: vectorOfDoubles,
|
vectorOfDoubles: const fb.ListReader<double>(const fb.Float64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 70),
|
||||||
parentNamespaceTest: parentNamespaceTest?.unpack(),
|
parentNamespaceTest: parentNamespaceTest?.unpack(),
|
||||||
vectorOfReferrables: vectorOfReferrables?.map((e) => e.unpack()).toList(),
|
vectorOfReferrables: vectorOfReferrables?.map((e) => e.unpack()).toList(),
|
||||||
singleWeakReference: singleWeakReference,
|
singleWeakReference: singleWeakReference,
|
||||||
vectorOfWeakReferences: vectorOfWeakReferences,
|
vectorOfWeakReferences: const fb.ListReader<int>(const fb.Uint64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 78),
|
||||||
vectorOfStrongReferrables: vectorOfStrongReferrables?.map((e) => e.unpack()).toList(),
|
vectorOfStrongReferrables: vectorOfStrongReferrables?.map((e) => e.unpack()).toList(),
|
||||||
coOwningReference: coOwningReference,
|
coOwningReference: coOwningReference,
|
||||||
vectorOfCoOwningReferences: vectorOfCoOwningReferences,
|
vectorOfCoOwningReferences: const fb.ListReader<int>(const fb.Uint64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 84),
|
||||||
nonOwningReference: nonOwningReference,
|
nonOwningReference: nonOwningReference,
|
||||||
vectorOfNonOwningReferences: vectorOfNonOwningReferences,
|
vectorOfNonOwningReferences: const fb.ListReader<int>(const fb.Uint64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 88),
|
||||||
anyUniqueType: anyUniqueType,
|
anyUniqueType: anyUniqueType,
|
||||||
anyUnique: anyUnique,
|
anyUnique: anyUnique,
|
||||||
anyAmbiguousType: anyAmbiguousType,
|
anyAmbiguousType: anyAmbiguousType,
|
||||||
anyAmbiguous: anyAmbiguous,
|
anyAmbiguous: anyAmbiguous,
|
||||||
vectorOfEnums: vectorOfEnums,
|
vectorOfEnums: const fb.ListReader<Color>(Color.reader, lazy: false).vTableGetNullable(_bc, _bcOffset, 98),
|
||||||
signedEnum: signedEnum,
|
signedEnum: signedEnum,
|
||||||
testrequirednestedflatbuffer: testrequirednestedflatbuffer,
|
testrequirednestedflatbuffer: const fb.ListReader<int>(const fb.Uint8Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 102),
|
||||||
scalarKeySortedTables: scalarKeySortedTables?.map((e) => e.unpack()).toList());
|
scalarKeySortedTables: scalarKeySortedTables?.map((e) => e.unpack()).toList());
|
||||||
|
|
||||||
static int pack(fb.Builder fbBuilder, MonsterT? object) {
|
static int pack(fb.Builder fbBuilder, MonsterT? object) {
|
||||||
@@ -1966,8 +1966,8 @@ class TypeAliases {
|
|||||||
u64: u64,
|
u64: u64,
|
||||||
f32: f32,
|
f32: f32,
|
||||||
f64: f64,
|
f64: f64,
|
||||||
v8: v8,
|
v8: const fb.ListReader<int>(const fb.Int8Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 24),
|
||||||
vf64: vf64);
|
vf64: const fb.ListReader<double>(const fb.Float64Reader(), lazy: false).vTableGetNullable(_bc, _bcOffset, 26));
|
||||||
|
|
||||||
static int pack(fb.Builder fbBuilder, TypeAliasesT? object) {
|
static int pack(fb.Builder fbBuilder, TypeAliasesT? object) {
|
||||||
if (object == null) return 0;
|
if (object == null) return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user