dart - change Builder.reset() to reuse an existing buffer (#6661)

This commit is contained in:
Ivan Dlugos 2021-06-13 17:07:08 +02:00 committed by GitHub
parent a9fb540884
commit d959e23208
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 17 deletions

View File

@ -118,11 +118,11 @@ class Builder {
/// The maximum alignment that has been seen so far. If [_buf] has to be
/// reallocated in the future (to insert room at its start for more bytes) the
/// reallocation will need to be a multiple of this many bytes.
int _maxAlign;
int _maxAlign = 1;
/// The number of bytes that have been written to the buffer so far. The
/// most recently written byte is this many bytes from the end of [_buf].
int _tail;
int _tail = 0;
/// The location of the end of the current table, measured in bytes from the
/// end of [_buf], or `null` if a table is not currently being built.
@ -142,11 +142,11 @@ class Builder {
/// automatically grow the array if/as needed. `internStrings`, if set to
/// true, will cause [writeString] to pool strings in the buffer so that
/// identical strings will always use the same offset in tables.
Builder({this.initialSize: 1024, bool internStrings = false}) {
Builder({this.initialSize: 1024, bool internStrings = false})
: _buf = ByteData(initialSize) {
if (internStrings == true) {
_strings = new Map<String, int>();
}
reset();
}
/// Calculate the finished buffer size (aligned).
@ -441,7 +441,6 @@ class Builder {
/// Reset the builder and make it ready for filling a new buffer.
void reset() {
_buf = new ByteData(initialSize);
_maxAlign = 1;
_tail = 0;
_currentVTable = null;

View File

@ -135,8 +135,8 @@ class CheckOtherLangaugesData {
@reflectiveTest
class BuilderTest {
void test_monsterBuilder() {
final fbBuilder = new Builder();
void test_monsterBuilder([Builder builder]) {
final fbBuilder = builder ?? new Builder();
final str = fbBuilder.writeString('MyMonster');
fbBuilder.writeString('test1');
@ -181,8 +181,8 @@ class BuilderTest {
fbBuilder.finish(mon);
}
void test_error_addInt32_withoutStartTable() {
Builder builder = new Builder();
void test_error_addInt32_withoutStartTable([Builder builder]) {
builder ??= new Builder();
expect(() {
builder.addInt32(0, 0);
}, throwsStateError);
@ -286,10 +286,10 @@ class BuilderTest {
20);
}
void test_table_format() {
void test_table_format([Builder builder]) {
Uint8List byteList;
{
Builder builder = new Builder(initialSize: 0);
builder ??= new Builder(initialSize: 0);
builder.startTable();
builder.addInt32(0, 10);
builder.addInt32(1, 20);
@ -341,10 +341,10 @@ class BuilderTest {
unicodeString);
}
void test_table_types() {
void test_table_types([Builder builder]) {
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
builder ??= new Builder(initialSize: 0);
int stringOffset = builder.writeString('12345');
builder.startTable();
builder.addBool(0, true);
@ -486,10 +486,10 @@ class BuilderTest {
}
}
void test_writeList_ofObjects() {
void test_writeList_ofObjects([Builder builder]) {
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
builder ??= new Builder(initialSize: 0);
// write the object #1
int object1;
{
@ -539,10 +539,10 @@ class BuilderTest {
expect(items, contains('ABC'));
}
void test_writeList_ofStrings_inObject() {
void test_writeList_ofStrings_inObject([Builder builder]) {
List<int> byteList;
{
Builder builder = new Builder(initialSize: 0);
builder ??= new Builder(initialSize: 0);
int listOffset = builder.writeList(
[builder.writeString('12345'), builder.writeString('ABC')]);
builder.startTable();
@ -600,6 +600,71 @@ class BuilderTest {
expect(items, hasLength(5));
expect(items, orderedEquals(<int>[1, 2, 3, 4, 0x9A]));
}
void test_reset() {
// We'll run a selection of tests , reusing the builder between them.
final testCases = <void Function(Builder)>[
test_monsterBuilder,
test_error_addInt32_withoutStartTable,
test_table_format,
test_table_types,
test_writeList_ofObjects,
test_writeList_ofStrings_inObject
];
// Execute all test cases in all permutations of their order.
// To do that, we generate permutations of test case indexes.
final testCasesPermutations =
_permutationsOf(List.generate(testCases.length, (index) => index));
expect(testCasesPermutations.length, _factorial(testCases.length));
testCasesPermutations.forEach((List<int> indexes) {
// print the order so failures are reproducible
printOnFailure('Running reset() test cases in order: $indexes');
Builder builder;
indexes.forEach((index) {
if (builder == null) {
// Initial size small enough so at least one test case increases it.
// On the other hand, it's large enough so that some test cases don't.
builder = Builder(initialSize: 32);
} else {
builder.reset();
}
testCases[index](builder);
});
});
}
// Generate permutations of the given list
List<List<T>> _permutationsOf<T>(List<T> source) {
final result = <List<T>>[];
void permutate(List<T> items, int startAt) {
for (var i = startAt; i < items.length; i++) {
List<T> permutation = items.toList(growable: false);
permutation[i] = items[startAt];
permutation[startAt] = items[i];
// add the current list upon reaching the end
if (startAt == items.length - 1) {
result.add(items);
} else {
permutate(permutation, startAt + 1);
}
}
}
permutate(source, 0);
return result;
}
// a very simple implementation of n!
int _factorial(int n) {
var result = 1;
for (var i = 2; i <= n; i++) result *= i;
return result;
}
}
class StringListWrapperImpl {