xref: /aosp_15_r20/external/flatbuffers/dart/lib/flat_buffers.dart (revision 890232f25432b36107d06881e0a25aaa6b473652)
1*890232f2SAndroid Build Coastguard Workerimport 'dart:collection';
2*890232f2SAndroid Build Coastguard Workerimport 'dart:convert';
3*890232f2SAndroid Build Coastguard Workerimport 'dart:math';
4*890232f2SAndroid Build Coastguard Workerimport 'dart:typed_data';
5*890232f2SAndroid Build Coastguard Worker
6*890232f2SAndroid Build Coastguard Workerconst int _sizeofUint8 = 1;
7*890232f2SAndroid Build Coastguard Workerconst int _sizeofUint16 = 2;
8*890232f2SAndroid Build Coastguard Workerconst int _sizeofUint32 = 4;
9*890232f2SAndroid Build Coastguard Workerconst int _sizeofUint64 = 8;
10*890232f2SAndroid Build Coastguard Workerconst int _sizeofInt8 = 1;
11*890232f2SAndroid Build Coastguard Workerconst int _sizeofInt16 = 2;
12*890232f2SAndroid Build Coastguard Workerconst int _sizeofInt32 = 4;
13*890232f2SAndroid Build Coastguard Workerconst int _sizeofInt64 = 8;
14*890232f2SAndroid Build Coastguard Workerconst int _sizeofFloat32 = 4;
15*890232f2SAndroid Build Coastguard Workerconst int _sizeofFloat64 = 8;
16*890232f2SAndroid Build Coastguard Worker
17*890232f2SAndroid Build Coastguard Worker/// Callback used to invoke a struct builder's finish method.
18*890232f2SAndroid Build Coastguard Worker///
19*890232f2SAndroid Build Coastguard Worker/// This callback is used by other struct's `finish` methods to write the nested
20*890232f2SAndroid Build Coastguard Worker/// struct's fields inline.
21*890232f2SAndroid Build Coastguard Workertypedef StructBuilder = void Function();
22*890232f2SAndroid Build Coastguard Worker
23*890232f2SAndroid Build Coastguard Worker/// Buffer with data and some context about it.
24*890232f2SAndroid Build Coastguard Workerclass BufferContext {
25*890232f2SAndroid Build Coastguard Worker  final ByteData _buffer;
26*890232f2SAndroid Build Coastguard Worker
27*890232f2SAndroid Build Coastguard Worker  ByteData get buffer => _buffer;
28*890232f2SAndroid Build Coastguard Worker
29*890232f2SAndroid Build Coastguard Worker  /// Create from a FlatBuffer represented by a list of bytes (uint8).
30*890232f2SAndroid Build Coastguard Worker  factory BufferContext.fromBytes(List<int> byteList) =>
31*890232f2SAndroid Build Coastguard Worker      BufferContext(byteList is Uint8List
32*890232f2SAndroid Build Coastguard Worker          ? byteList.buffer.asByteData(byteList.offsetInBytes)
33*890232f2SAndroid Build Coastguard Worker          : ByteData.view(Uint8List.fromList(byteList).buffer));
34*890232f2SAndroid Build Coastguard Worker
35*890232f2SAndroid Build Coastguard Worker  /// Create from a FlatBuffer represented by ByteData.
36*890232f2SAndroid Build Coastguard Worker  BufferContext(this._buffer);
37*890232f2SAndroid Build Coastguard Worker
38*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
39*890232f2SAndroid Build Coastguard Worker  int derefObject(int offset) => offset + _getUint32(offset);
40*890232f2SAndroid Build Coastguard Worker
41*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
42*890232f2SAndroid Build Coastguard Worker  Uint8List _asUint8List(int offset, int length) =>
43*890232f2SAndroid Build Coastguard Worker      _buffer.buffer.asUint8List(_buffer.offsetInBytes + offset, length);
44*890232f2SAndroid Build Coastguard Worker
45*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
46*890232f2SAndroid Build Coastguard Worker  double _getFloat64(int offset) => _buffer.getFloat64(offset, Endian.little);
47*890232f2SAndroid Build Coastguard Worker
48*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
49*890232f2SAndroid Build Coastguard Worker  double _getFloat32(int offset) => _buffer.getFloat32(offset, Endian.little);
50*890232f2SAndroid Build Coastguard Worker
51*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
52*890232f2SAndroid Build Coastguard Worker  int _getInt64(int offset) => _buffer.getInt64(offset, Endian.little);
53*890232f2SAndroid Build Coastguard Worker
54*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
55*890232f2SAndroid Build Coastguard Worker  int _getInt32(int offset) => _buffer.getInt32(offset, Endian.little);
56*890232f2SAndroid Build Coastguard Worker
57*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
58*890232f2SAndroid Build Coastguard Worker  int _getInt16(int offset) => _buffer.getInt16(offset, Endian.little);
59*890232f2SAndroid Build Coastguard Worker
60*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
61*890232f2SAndroid Build Coastguard Worker  int _getInt8(int offset) => _buffer.getInt8(offset);
62*890232f2SAndroid Build Coastguard Worker
63*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
64*890232f2SAndroid Build Coastguard Worker  int _getUint64(int offset) => _buffer.getUint64(offset, Endian.little);
65*890232f2SAndroid Build Coastguard Worker
66*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
67*890232f2SAndroid Build Coastguard Worker  int _getUint32(int offset) => _buffer.getUint32(offset, Endian.little);
68*890232f2SAndroid Build Coastguard Worker
69*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
70*890232f2SAndroid Build Coastguard Worker  int _getUint16(int offset) => _buffer.getUint16(offset, Endian.little);
71*890232f2SAndroid Build Coastguard Worker
72*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
73*890232f2SAndroid Build Coastguard Worker  int _getUint8(int offset) => _buffer.getUint8(offset);
74*890232f2SAndroid Build Coastguard Worker}
75*890232f2SAndroid Build Coastguard Worker
76*890232f2SAndroid Build Coastguard Worker/// Interface implemented by the "object-api" classes (ending with "T").
77*890232f2SAndroid Build Coastguard Workerabstract class Packable {
78*890232f2SAndroid Build Coastguard Worker  /// Serialize the object using the given builder, returning the offset.
79*890232f2SAndroid Build Coastguard Worker  int pack(Builder fbBuilder);
80*890232f2SAndroid Build Coastguard Worker}
81*890232f2SAndroid Build Coastguard Worker
82*890232f2SAndroid Build Coastguard Worker/// Class implemented by typed builders generated by flatc.
83*890232f2SAndroid Build Coastguard Workerabstract class ObjectBuilder {
84*890232f2SAndroid Build Coastguard Worker  int? _firstOffset;
85*890232f2SAndroid Build Coastguard Worker
86*890232f2SAndroid Build Coastguard Worker  /// Can be used to write the data represented by this builder to the [Builder]
87*890232f2SAndroid Build Coastguard Worker  /// and reuse the offset created in multiple tables.
88*890232f2SAndroid Build Coastguard Worker  ///
89*890232f2SAndroid Build Coastguard Worker  /// Note that this method assumes you call it using the same [Builder] instance
90*890232f2SAndroid Build Coastguard Worker  /// every time. The returned offset is only good for the [Builder] used in the
91*890232f2SAndroid Build Coastguard Worker  /// first call to this method.
92*890232f2SAndroid Build Coastguard Worker  int getOrCreateOffset(Builder fbBuilder) {
93*890232f2SAndroid Build Coastguard Worker    _firstOffset ??= finish(fbBuilder);
94*890232f2SAndroid Build Coastguard Worker    return _firstOffset!;
95*890232f2SAndroid Build Coastguard Worker  }
96*890232f2SAndroid Build Coastguard Worker
97*890232f2SAndroid Build Coastguard Worker  /// Writes the data in this helper to the [Builder].
98*890232f2SAndroid Build Coastguard Worker  int finish(Builder fbBuilder);
99*890232f2SAndroid Build Coastguard Worker
100*890232f2SAndroid Build Coastguard Worker  /// Convenience method that will create a new [Builder], [finish]es the data,
101*890232f2SAndroid Build Coastguard Worker  /// and returns the buffer as a [Uint8List] of bytes.
102*890232f2SAndroid Build Coastguard Worker  Uint8List toBytes();
103*890232f2SAndroid Build Coastguard Worker}
104*890232f2SAndroid Build Coastguard Worker
105*890232f2SAndroid Build Coastguard Worker/// Class that helps building flat buffers.
106*890232f2SAndroid Build Coastguard Workerclass Builder {
107*890232f2SAndroid Build Coastguard Worker  bool _finished = false;
108*890232f2SAndroid Build Coastguard Worker
109*890232f2SAndroid Build Coastguard Worker  final int initialSize;
110*890232f2SAndroid Build Coastguard Worker
111*890232f2SAndroid Build Coastguard Worker  /// The list of existing VTable(s).
112*890232f2SAndroid Build Coastguard Worker  final List<int> _vTables;
113*890232f2SAndroid Build Coastguard Worker
114*890232f2SAndroid Build Coastguard Worker  final bool deduplicateTables;
115*890232f2SAndroid Build Coastguard Worker
116*890232f2SAndroid Build Coastguard Worker  ByteData _buf;
117*890232f2SAndroid Build Coastguard Worker
118*890232f2SAndroid Build Coastguard Worker  final Allocator _allocator;
119*890232f2SAndroid Build Coastguard Worker
120*890232f2SAndroid Build Coastguard Worker  /// The maximum alignment that has been seen so far.  If [_buf] has to be
121*890232f2SAndroid Build Coastguard Worker  /// reallocated in the future (to insert room at its start for more bytes) the
122*890232f2SAndroid Build Coastguard Worker  /// reallocation will need to be a multiple of this many bytes.
123*890232f2SAndroid Build Coastguard Worker  int _maxAlign = 1;
124*890232f2SAndroid Build Coastguard Worker
125*890232f2SAndroid Build Coastguard Worker  /// The number of bytes that have been written to the buffer so far.  The
126*890232f2SAndroid Build Coastguard Worker  /// most recently written byte is this many bytes from the end of [_buf].
127*890232f2SAndroid Build Coastguard Worker  int _tail = 0;
128*890232f2SAndroid Build Coastguard Worker
129*890232f2SAndroid Build Coastguard Worker  /// The location of the end of the current table, measured in bytes from the
130*890232f2SAndroid Build Coastguard Worker  /// end of [_buf].
131*890232f2SAndroid Build Coastguard Worker  int _currentTableEndTail = 0;
132*890232f2SAndroid Build Coastguard Worker
133*890232f2SAndroid Build Coastguard Worker  _VTable? _currentVTable;
134*890232f2SAndroid Build Coastguard Worker
135*890232f2SAndroid Build Coastguard Worker  /// Map containing all strings that have been written so far.  This allows us
136*890232f2SAndroid Build Coastguard Worker  /// to avoid duplicating strings.
137*890232f2SAndroid Build Coastguard Worker  ///
138*890232f2SAndroid Build Coastguard Worker  /// Allocated only if `internStrings` is set to true on the constructor.
139*890232f2SAndroid Build Coastguard Worker  Map<String, int>? _strings;
140*890232f2SAndroid Build Coastguard Worker
141*890232f2SAndroid Build Coastguard Worker  /// Creates a new FlatBuffers Builder.
142*890232f2SAndroid Build Coastguard Worker  ///
143*890232f2SAndroid Build Coastguard Worker  /// `initialSize` is the initial array size in bytes.  The [Builder] will
144*890232f2SAndroid Build Coastguard Worker  /// automatically grow the array if/as needed.  `internStrings`, if set to
145*890232f2SAndroid Build Coastguard Worker  /// true, will cause [writeString] to pool strings in the buffer so that
146*890232f2SAndroid Build Coastguard Worker  /// identical strings will always use the same offset in tables.
147*890232f2SAndroid Build Coastguard Worker  Builder({
148*890232f2SAndroid Build Coastguard Worker    this.initialSize = 1024,
149*890232f2SAndroid Build Coastguard Worker    bool internStrings = false,
150*890232f2SAndroid Build Coastguard Worker    Allocator allocator = const DefaultAllocator(),
151*890232f2SAndroid Build Coastguard Worker    this.deduplicateTables = true,
152*890232f2SAndroid Build Coastguard Worker  })  : _allocator = allocator,
153*890232f2SAndroid Build Coastguard Worker        _buf = allocator.allocate(initialSize),
154*890232f2SAndroid Build Coastguard Worker        _vTables = deduplicateTables ? [] : const [] {
155*890232f2SAndroid Build Coastguard Worker    if (internStrings) {
156*890232f2SAndroid Build Coastguard Worker      _strings = <String, int>{};
157*890232f2SAndroid Build Coastguard Worker    }
158*890232f2SAndroid Build Coastguard Worker  }
159*890232f2SAndroid Build Coastguard Worker
160*890232f2SAndroid Build Coastguard Worker  /// Calculate the finished buffer size (aligned).
161*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
162*890232f2SAndroid Build Coastguard Worker  int size() => _tail + ((-_tail) & (_maxAlign - 1));
163*890232f2SAndroid Build Coastguard Worker
164*890232f2SAndroid Build Coastguard Worker  /// Add the [field] with the given boolean [value].  The field is not added if
165*890232f2SAndroid Build Coastguard Worker  /// the [value] is equal to [def].  Booleans are stored as 8-bit fields with
166*890232f2SAndroid Build Coastguard Worker  /// `0` for `false` and `1` for `true`.
167*890232f2SAndroid Build Coastguard Worker  void addBool(int field, bool? value, [bool? def]) {
168*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
169*890232f2SAndroid Build Coastguard Worker    if (value != null && value != def) {
170*890232f2SAndroid Build Coastguard Worker      _prepare(_sizeofUint8, 1);
171*890232f2SAndroid Build Coastguard Worker      _trackField(field);
172*890232f2SAndroid Build Coastguard Worker      _buf.setInt8(_buf.lengthInBytes - _tail, value ? 1 : 0);
173*890232f2SAndroid Build Coastguard Worker    }
174*890232f2SAndroid Build Coastguard Worker  }
175*890232f2SAndroid Build Coastguard Worker
176*890232f2SAndroid Build Coastguard Worker  /// Add the [field] with the given 32-bit signed integer [value].  The field is
177*890232f2SAndroid Build Coastguard Worker  /// not added if the [value] is equal to [def].
178*890232f2SAndroid Build Coastguard Worker  void addInt32(int field, int? value, [int? def]) {
179*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
180*890232f2SAndroid Build Coastguard Worker    if (value != null && value != def) {
181*890232f2SAndroid Build Coastguard Worker      _prepare(_sizeofInt32, 1);
182*890232f2SAndroid Build Coastguard Worker      _trackField(field);
183*890232f2SAndroid Build Coastguard Worker      _setInt32AtTail(_tail, value);
184*890232f2SAndroid Build Coastguard Worker    }
185*890232f2SAndroid Build Coastguard Worker  }
186*890232f2SAndroid Build Coastguard Worker
187*890232f2SAndroid Build Coastguard Worker  /// Add the [field] with the given 32-bit signed integer [value].  The field is
188*890232f2SAndroid Build Coastguard Worker  /// not added if the [value] is equal to [def].
189*890232f2SAndroid Build Coastguard Worker  void addInt16(int field, int? value, [int? def]) {
190*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
191*890232f2SAndroid Build Coastguard Worker    if (value != null && value != def) {
192*890232f2SAndroid Build Coastguard Worker      _prepare(_sizeofInt16, 1);
193*890232f2SAndroid Build Coastguard Worker      _trackField(field);
194*890232f2SAndroid Build Coastguard Worker      _setInt16AtTail(_tail, value);
195*890232f2SAndroid Build Coastguard Worker    }
196*890232f2SAndroid Build Coastguard Worker  }
197*890232f2SAndroid Build Coastguard Worker
198*890232f2SAndroid Build Coastguard Worker  /// Add the [field] with the given 8-bit signed integer [value].  The field is
199*890232f2SAndroid Build Coastguard Worker  /// not added if the [value] is equal to [def].
200*890232f2SAndroid Build Coastguard Worker  void addInt8(int field, int? value, [int? def]) {
201*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
202*890232f2SAndroid Build Coastguard Worker    if (value != null && value != def) {
203*890232f2SAndroid Build Coastguard Worker      _prepare(_sizeofInt8, 1);
204*890232f2SAndroid Build Coastguard Worker      _trackField(field);
205*890232f2SAndroid Build Coastguard Worker      _setInt8AtTail(_tail, value);
206*890232f2SAndroid Build Coastguard Worker    }
207*890232f2SAndroid Build Coastguard Worker  }
208*890232f2SAndroid Build Coastguard Worker
209*890232f2SAndroid Build Coastguard Worker  void addStruct(int field, int offset) {
210*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
211*890232f2SAndroid Build Coastguard Worker    _trackField(field);
212*890232f2SAndroid Build Coastguard Worker    _currentVTable!.addField(field, offset);
213*890232f2SAndroid Build Coastguard Worker  }
214*890232f2SAndroid Build Coastguard Worker
215*890232f2SAndroid Build Coastguard Worker  /// Add the [field] referencing an object with the given [offset].
216*890232f2SAndroid Build Coastguard Worker  void addOffset(int field, int? offset) {
217*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
218*890232f2SAndroid Build Coastguard Worker    if (offset != null) {
219*890232f2SAndroid Build Coastguard Worker      _prepare(_sizeofUint32, 1);
220*890232f2SAndroid Build Coastguard Worker      _trackField(field);
221*890232f2SAndroid Build Coastguard Worker      _setUint32AtTail(_tail, _tail - offset);
222*890232f2SAndroid Build Coastguard Worker    }
223*890232f2SAndroid Build Coastguard Worker  }
224*890232f2SAndroid Build Coastguard Worker
225*890232f2SAndroid Build Coastguard Worker  /// Add the [field] with the given 32-bit unsigned integer [value].  The field
226*890232f2SAndroid Build Coastguard Worker  /// is not added if the [value] is equal to [def].
227*890232f2SAndroid Build Coastguard Worker  void addUint32(int field, int? value, [int? def]) {
228*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
229*890232f2SAndroid Build Coastguard Worker    if (value != null && value != def) {
230*890232f2SAndroid Build Coastguard Worker      _prepare(_sizeofUint32, 1);
231*890232f2SAndroid Build Coastguard Worker      _trackField(field);
232*890232f2SAndroid Build Coastguard Worker      _setUint32AtTail(_tail, value);
233*890232f2SAndroid Build Coastguard Worker    }
234*890232f2SAndroid Build Coastguard Worker  }
235*890232f2SAndroid Build Coastguard Worker
236*890232f2SAndroid Build Coastguard Worker  /// Add the [field] with the given 32-bit unsigned integer [value].  The field
237*890232f2SAndroid Build Coastguard Worker  /// is not added if the [value] is equal to [def].
238*890232f2SAndroid Build Coastguard Worker  void addUint16(int field, int? value, [int? def]) {
239*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
240*890232f2SAndroid Build Coastguard Worker    if (value != null && value != def) {
241*890232f2SAndroid Build Coastguard Worker      _prepare(_sizeofUint16, 1);
242*890232f2SAndroid Build Coastguard Worker      _trackField(field);
243*890232f2SAndroid Build Coastguard Worker      _setUint16AtTail(_tail, value);
244*890232f2SAndroid Build Coastguard Worker    }
245*890232f2SAndroid Build Coastguard Worker  }
246*890232f2SAndroid Build Coastguard Worker
247*890232f2SAndroid Build Coastguard Worker  /// Add the [field] with the given 8-bit unsigned integer [value].  The field
248*890232f2SAndroid Build Coastguard Worker  /// is not added if the [value] is equal to [def].
249*890232f2SAndroid Build Coastguard Worker  void addUint8(int field, int? value, [int? def]) {
250*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
251*890232f2SAndroid Build Coastguard Worker    if (value != null && value != def) {
252*890232f2SAndroid Build Coastguard Worker      _prepare(_sizeofUint8, 1);
253*890232f2SAndroid Build Coastguard Worker      _trackField(field);
254*890232f2SAndroid Build Coastguard Worker      _setUint8AtTail(_tail, value);
255*890232f2SAndroid Build Coastguard Worker    }
256*890232f2SAndroid Build Coastguard Worker  }
257*890232f2SAndroid Build Coastguard Worker
258*890232f2SAndroid Build Coastguard Worker  /// Add the [field] with the given 32-bit float [value].  The field
259*890232f2SAndroid Build Coastguard Worker  /// is not added if the [value] is equal to [def].
260*890232f2SAndroid Build Coastguard Worker  void addFloat32(int field, double? value, [double? def]) {
261*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
262*890232f2SAndroid Build Coastguard Worker    if (value != null && value != def) {
263*890232f2SAndroid Build Coastguard Worker      _prepare(_sizeofFloat32, 1);
264*890232f2SAndroid Build Coastguard Worker      _trackField(field);
265*890232f2SAndroid Build Coastguard Worker      _setFloat32AtTail(_tail, value);
266*890232f2SAndroid Build Coastguard Worker    }
267*890232f2SAndroid Build Coastguard Worker  }
268*890232f2SAndroid Build Coastguard Worker
269*890232f2SAndroid Build Coastguard Worker  /// Add the [field] with the given 64-bit double [value].  The field
270*890232f2SAndroid Build Coastguard Worker  /// is not added if the [value] is equal to [def].
271*890232f2SAndroid Build Coastguard Worker  void addFloat64(int field, double? value, [double? def]) {
272*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
273*890232f2SAndroid Build Coastguard Worker    if (value != null && value != def) {
274*890232f2SAndroid Build Coastguard Worker      _prepare(_sizeofFloat64, 1);
275*890232f2SAndroid Build Coastguard Worker      _trackField(field);
276*890232f2SAndroid Build Coastguard Worker      _setFloat64AtTail(_tail, value);
277*890232f2SAndroid Build Coastguard Worker    }
278*890232f2SAndroid Build Coastguard Worker  }
279*890232f2SAndroid Build Coastguard Worker
280*890232f2SAndroid Build Coastguard Worker  /// Add the [field] with the given 64-bit unsigned integer [value].  The field
281*890232f2SAndroid Build Coastguard Worker  /// is not added if the [value] is equal to [def].
282*890232f2SAndroid Build Coastguard Worker  void addUint64(int field, int? value, [double? def]) {
283*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
284*890232f2SAndroid Build Coastguard Worker    if (value != null && value != def) {
285*890232f2SAndroid Build Coastguard Worker      _prepare(_sizeofUint64, 1);
286*890232f2SAndroid Build Coastguard Worker      _trackField(field);
287*890232f2SAndroid Build Coastguard Worker      _setUint64AtTail(_tail, value);
288*890232f2SAndroid Build Coastguard Worker    }
289*890232f2SAndroid Build Coastguard Worker  }
290*890232f2SAndroid Build Coastguard Worker
291*890232f2SAndroid Build Coastguard Worker  /// Add the [field] with the given 64-bit unsigned integer [value].  The field
292*890232f2SAndroid Build Coastguard Worker  /// is not added if the [value] is equal to [def].
293*890232f2SAndroid Build Coastguard Worker  void addInt64(int field, int? value, [double? def]) {
294*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
295*890232f2SAndroid Build Coastguard Worker    if (value != null && value != def) {
296*890232f2SAndroid Build Coastguard Worker      _prepare(_sizeofInt64, 1);
297*890232f2SAndroid Build Coastguard Worker      _trackField(field);
298*890232f2SAndroid Build Coastguard Worker      _setInt64AtTail(_tail, value);
299*890232f2SAndroid Build Coastguard Worker    }
300*890232f2SAndroid Build Coastguard Worker  }
301*890232f2SAndroid Build Coastguard Worker
302*890232f2SAndroid Build Coastguard Worker  /// End the current table and return its offset.
303*890232f2SAndroid Build Coastguard Worker  int endTable() {
304*890232f2SAndroid Build Coastguard Worker    assert(_inVTable);
305*890232f2SAndroid Build Coastguard Worker    // Prepare for writing the VTable.
306*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofInt32, 1);
307*890232f2SAndroid Build Coastguard Worker    var tableTail = _tail;
308*890232f2SAndroid Build Coastguard Worker    // Prepare the size of the current table.
309*890232f2SAndroid Build Coastguard Worker    final currentVTable = _currentVTable!;
310*890232f2SAndroid Build Coastguard Worker    currentVTable.tableSize = tableTail - _currentTableEndTail;
311*890232f2SAndroid Build Coastguard Worker    // Prepare the VTable to use for the current table.
312*890232f2SAndroid Build Coastguard Worker    int? vTableTail;
313*890232f2SAndroid Build Coastguard Worker    {
314*890232f2SAndroid Build Coastguard Worker      currentVTable.computeFieldOffsets(tableTail);
315*890232f2SAndroid Build Coastguard Worker
316*890232f2SAndroid Build Coastguard Worker      // Try to find an existing compatible VTable.
317*890232f2SAndroid Build Coastguard Worker      if (deduplicateTables) {
318*890232f2SAndroid Build Coastguard Worker        // Search backward - more likely to have recently used one
319*890232f2SAndroid Build Coastguard Worker        for (var i = _vTables.length - 1; i >= 0; i--) {
320*890232f2SAndroid Build Coastguard Worker          final vt2Offset = _vTables[i];
321*890232f2SAndroid Build Coastguard Worker          final vt2Start = _buf.lengthInBytes - vt2Offset;
322*890232f2SAndroid Build Coastguard Worker          final vt2Size = _buf.getUint16(vt2Start, Endian.little);
323*890232f2SAndroid Build Coastguard Worker
324*890232f2SAndroid Build Coastguard Worker          if (currentVTable._vTableSize == vt2Size &&
325*890232f2SAndroid Build Coastguard Worker              currentVTable._offsetsMatch(vt2Start, _buf)) {
326*890232f2SAndroid Build Coastguard Worker            vTableTail = vt2Offset;
327*890232f2SAndroid Build Coastguard Worker            break;
328*890232f2SAndroid Build Coastguard Worker          }
329*890232f2SAndroid Build Coastguard Worker        }
330*890232f2SAndroid Build Coastguard Worker      }
331*890232f2SAndroid Build Coastguard Worker
332*890232f2SAndroid Build Coastguard Worker      // Write a new VTable.
333*890232f2SAndroid Build Coastguard Worker      if (vTableTail == null) {
334*890232f2SAndroid Build Coastguard Worker        _prepare(_sizeofUint16, _currentVTable!.numOfUint16);
335*890232f2SAndroid Build Coastguard Worker        vTableTail = _tail;
336*890232f2SAndroid Build Coastguard Worker        currentVTable.tail = vTableTail;
337*890232f2SAndroid Build Coastguard Worker        currentVTable.output(_buf, _buf.lengthInBytes - _tail);
338*890232f2SAndroid Build Coastguard Worker        if (deduplicateTables) _vTables.add(currentVTable.tail);
339*890232f2SAndroid Build Coastguard Worker      }
340*890232f2SAndroid Build Coastguard Worker    }
341*890232f2SAndroid Build Coastguard Worker    // Set the VTable offset.
342*890232f2SAndroid Build Coastguard Worker    _setInt32AtTail(tableTail, vTableTail - tableTail);
343*890232f2SAndroid Build Coastguard Worker    // Done with this table.
344*890232f2SAndroid Build Coastguard Worker    _currentVTable = null;
345*890232f2SAndroid Build Coastguard Worker    return tableTail;
346*890232f2SAndroid Build Coastguard Worker  }
347*890232f2SAndroid Build Coastguard Worker
348*890232f2SAndroid Build Coastguard Worker  /// Returns the finished buffer. You must call [finish] before accessing this.
349*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
350*890232f2SAndroid Build Coastguard Worker  Uint8List get buffer {
351*890232f2SAndroid Build Coastguard Worker    assert(_finished);
352*890232f2SAndroid Build Coastguard Worker    final finishedSize = size();
353*890232f2SAndroid Build Coastguard Worker    return _buf.buffer
354*890232f2SAndroid Build Coastguard Worker        .asUint8List(_buf.lengthInBytes - finishedSize, finishedSize);
355*890232f2SAndroid Build Coastguard Worker  }
356*890232f2SAndroid Build Coastguard Worker
357*890232f2SAndroid Build Coastguard Worker  /// Finish off the creation of the buffer.  The given [offset] is used as the
358*890232f2SAndroid Build Coastguard Worker  /// root object offset, and usually references directly or indirectly every
359*890232f2SAndroid Build Coastguard Worker  /// written object.  If [fileIdentifier] is specified (and not `null`), it is
360*890232f2SAndroid Build Coastguard Worker  /// interpreted as a 4-byte Latin-1 encoded string that should be placed at
361*890232f2SAndroid Build Coastguard Worker  /// bytes 4-7 of the file.
362*890232f2SAndroid Build Coastguard Worker  void finish(int offset, [String? fileIdentifier]) {
363*890232f2SAndroid Build Coastguard Worker    final sizeBeforePadding = size();
364*890232f2SAndroid Build Coastguard Worker    final requiredBytes = _sizeofUint32 * (fileIdentifier == null ? 1 : 2);
365*890232f2SAndroid Build Coastguard Worker    _prepare(max(requiredBytes, _maxAlign), 1);
366*890232f2SAndroid Build Coastguard Worker    final finishedSize = size();
367*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(finishedSize, finishedSize - offset);
368*890232f2SAndroid Build Coastguard Worker    if (fileIdentifier != null) {
369*890232f2SAndroid Build Coastguard Worker      for (var i = 0; i < 4; i++) {
370*890232f2SAndroid Build Coastguard Worker        _setUint8AtTail(
371*890232f2SAndroid Build Coastguard Worker            finishedSize - _sizeofUint32 - i, fileIdentifier.codeUnitAt(i));
372*890232f2SAndroid Build Coastguard Worker      }
373*890232f2SAndroid Build Coastguard Worker    }
374*890232f2SAndroid Build Coastguard Worker
375*890232f2SAndroid Build Coastguard Worker    // zero out the added padding
376*890232f2SAndroid Build Coastguard Worker    for (var i = sizeBeforePadding + 1;
377*890232f2SAndroid Build Coastguard Worker        i <= finishedSize - requiredBytes;
378*890232f2SAndroid Build Coastguard Worker        i++) {
379*890232f2SAndroid Build Coastguard Worker      _setUint8AtTail(i, 0);
380*890232f2SAndroid Build Coastguard Worker    }
381*890232f2SAndroid Build Coastguard Worker    _finished = true;
382*890232f2SAndroid Build Coastguard Worker  }
383*890232f2SAndroid Build Coastguard Worker
384*890232f2SAndroid Build Coastguard Worker  /// Writes a Float64 to the tail of the buffer after preparing space for it.
385*890232f2SAndroid Build Coastguard Worker  ///
386*890232f2SAndroid Build Coastguard Worker  /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
387*890232f2SAndroid Build Coastguard Worker  void putFloat64(double value) {
388*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofFloat64, 1);
389*890232f2SAndroid Build Coastguard Worker    _setFloat32AtTail(_tail, value);
390*890232f2SAndroid Build Coastguard Worker  }
391*890232f2SAndroid Build Coastguard Worker
392*890232f2SAndroid Build Coastguard Worker  /// Writes a Float32 to the tail of the buffer after preparing space for it.
393*890232f2SAndroid Build Coastguard Worker  ///
394*890232f2SAndroid Build Coastguard Worker  /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
395*890232f2SAndroid Build Coastguard Worker  void putFloat32(double value) {
396*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofFloat32, 1);
397*890232f2SAndroid Build Coastguard Worker    _setFloat32AtTail(_tail, value);
398*890232f2SAndroid Build Coastguard Worker  }
399*890232f2SAndroid Build Coastguard Worker
400*890232f2SAndroid Build Coastguard Worker  /// Writes a bool to the tail of the buffer after preparing space for it.
401*890232f2SAndroid Build Coastguard Worker  /// Bools are represented as a Uint8, with the value set to '1' for true, and '0' for false
402*890232f2SAndroid Build Coastguard Worker  ///
403*890232f2SAndroid Build Coastguard Worker  /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
404*890232f2SAndroid Build Coastguard Worker  void putBool(bool value) {
405*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint8, 1);
406*890232f2SAndroid Build Coastguard Worker    _buf.setInt8(_buf.lengthInBytes - _tail, value ? 1 : 0);
407*890232f2SAndroid Build Coastguard Worker  }
408*890232f2SAndroid Build Coastguard Worker
409*890232f2SAndroid Build Coastguard Worker  /// Writes a Int64 to the tail of the buffer after preparing space for it.
410*890232f2SAndroid Build Coastguard Worker  ///
411*890232f2SAndroid Build Coastguard Worker  /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
412*890232f2SAndroid Build Coastguard Worker  void putInt64(int value) {
413*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofInt64, 1);
414*890232f2SAndroid Build Coastguard Worker    _setInt64AtTail(_tail, value);
415*890232f2SAndroid Build Coastguard Worker  }
416*890232f2SAndroid Build Coastguard Worker
417*890232f2SAndroid Build Coastguard Worker  /// Writes a Uint32 to the tail of the buffer after preparing space for it.
418*890232f2SAndroid Build Coastguard Worker  ///
419*890232f2SAndroid Build Coastguard Worker  /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
420*890232f2SAndroid Build Coastguard Worker  void putInt32(int value) {
421*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofInt32, 1);
422*890232f2SAndroid Build Coastguard Worker    _setInt32AtTail(_tail, value);
423*890232f2SAndroid Build Coastguard Worker  }
424*890232f2SAndroid Build Coastguard Worker
425*890232f2SAndroid Build Coastguard Worker  /// Writes a Uint16 to the tail of the buffer after preparing space for it.
426*890232f2SAndroid Build Coastguard Worker  ///
427*890232f2SAndroid Build Coastguard Worker  /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
428*890232f2SAndroid Build Coastguard Worker  void putInt16(int value) {
429*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofInt16, 1);
430*890232f2SAndroid Build Coastguard Worker    _setInt16AtTail(_tail, value);
431*890232f2SAndroid Build Coastguard Worker  }
432*890232f2SAndroid Build Coastguard Worker
433*890232f2SAndroid Build Coastguard Worker  /// Writes a Uint8 to the tail of the buffer after preparing space for it.
434*890232f2SAndroid Build Coastguard Worker  ///
435*890232f2SAndroid Build Coastguard Worker  /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
436*890232f2SAndroid Build Coastguard Worker  void putInt8(int value) {
437*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofInt8, 1);
438*890232f2SAndroid Build Coastguard Worker    _buf.setInt8(_buf.lengthInBytes - _tail, value);
439*890232f2SAndroid Build Coastguard Worker  }
440*890232f2SAndroid Build Coastguard Worker
441*890232f2SAndroid Build Coastguard Worker  /// Writes a Uint64 to the tail of the buffer after preparing space for it.
442*890232f2SAndroid Build Coastguard Worker  ///
443*890232f2SAndroid Build Coastguard Worker  /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
444*890232f2SAndroid Build Coastguard Worker  void putUint64(int value) {
445*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint64, 1);
446*890232f2SAndroid Build Coastguard Worker    _setUint64AtTail(_tail, value);
447*890232f2SAndroid Build Coastguard Worker  }
448*890232f2SAndroid Build Coastguard Worker
449*890232f2SAndroid Build Coastguard Worker  /// Writes a Uint32 to the tail of the buffer after preparing space for it.
450*890232f2SAndroid Build Coastguard Worker  ///
451*890232f2SAndroid Build Coastguard Worker  /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
452*890232f2SAndroid Build Coastguard Worker  void putUint32(int value) {
453*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint32, 1);
454*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(_tail, value);
455*890232f2SAndroid Build Coastguard Worker  }
456*890232f2SAndroid Build Coastguard Worker
457*890232f2SAndroid Build Coastguard Worker  /// Writes a Uint16 to the tail of the buffer after preparing space for it.
458*890232f2SAndroid Build Coastguard Worker  ///
459*890232f2SAndroid Build Coastguard Worker  /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
460*890232f2SAndroid Build Coastguard Worker  void putUint16(int value) {
461*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint16, 1);
462*890232f2SAndroid Build Coastguard Worker    _setUint16AtTail(_tail, value);
463*890232f2SAndroid Build Coastguard Worker  }
464*890232f2SAndroid Build Coastguard Worker
465*890232f2SAndroid Build Coastguard Worker  /// Writes a Uint8 to the tail of the buffer after preparing space for it.
466*890232f2SAndroid Build Coastguard Worker  ///
467*890232f2SAndroid Build Coastguard Worker  /// Updates the [offset] pointer.  This method is intended for use when writing structs to the buffer.
468*890232f2SAndroid Build Coastguard Worker  void putUint8(int value) {
469*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint8, 1);
470*890232f2SAndroid Build Coastguard Worker    _buf.setUint8(_buf.lengthInBytes - _tail, value);
471*890232f2SAndroid Build Coastguard Worker  }
472*890232f2SAndroid Build Coastguard Worker
473*890232f2SAndroid Build Coastguard Worker  /// Reset the builder and make it ready for filling a new buffer.
474*890232f2SAndroid Build Coastguard Worker  void reset() {
475*890232f2SAndroid Build Coastguard Worker    _finished = false;
476*890232f2SAndroid Build Coastguard Worker    _maxAlign = 1;
477*890232f2SAndroid Build Coastguard Worker    _tail = 0;
478*890232f2SAndroid Build Coastguard Worker    _currentVTable = null;
479*890232f2SAndroid Build Coastguard Worker    if (deduplicateTables) _vTables.clear();
480*890232f2SAndroid Build Coastguard Worker    if (_strings != null) {
481*890232f2SAndroid Build Coastguard Worker      _strings = <String, int>{};
482*890232f2SAndroid Build Coastguard Worker    }
483*890232f2SAndroid Build Coastguard Worker  }
484*890232f2SAndroid Build Coastguard Worker
485*890232f2SAndroid Build Coastguard Worker  /// Start a new table. Must be finished with [endTable] invocation.
486*890232f2SAndroid Build Coastguard Worker  void startTable(int numFields) {
487*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable); // Inline tables are not supported.
488*890232f2SAndroid Build Coastguard Worker    _currentVTable = _VTable(numFields);
489*890232f2SAndroid Build Coastguard Worker    _currentTableEndTail = _tail;
490*890232f2SAndroid Build Coastguard Worker  }
491*890232f2SAndroid Build Coastguard Worker
492*890232f2SAndroid Build Coastguard Worker  /// Finish a Struct vector.  Most callers should preferto use [writeListOfStructs].
493*890232f2SAndroid Build Coastguard Worker  ///
494*890232f2SAndroid Build Coastguard Worker  /// Most callers should prefer [writeListOfStructs].
495*890232f2SAndroid Build Coastguard Worker  int endStructVector(int count) {
496*890232f2SAndroid Build Coastguard Worker    putUint32(count);
497*890232f2SAndroid Build Coastguard Worker    return _tail;
498*890232f2SAndroid Build Coastguard Worker  }
499*890232f2SAndroid Build Coastguard Worker
500*890232f2SAndroid Build Coastguard Worker  /// Writes a list of Structs to the buffer, returning the offset
501*890232f2SAndroid Build Coastguard Worker  int writeListOfStructs(List<ObjectBuilder> structBuilders) {
502*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
503*890232f2SAndroid Build Coastguard Worker    for (var i = structBuilders.length - 1; i >= 0; i--) {
504*890232f2SAndroid Build Coastguard Worker      structBuilders[i].finish(this);
505*890232f2SAndroid Build Coastguard Worker    }
506*890232f2SAndroid Build Coastguard Worker    return endStructVector(structBuilders.length);
507*890232f2SAndroid Build Coastguard Worker  }
508*890232f2SAndroid Build Coastguard Worker
509*890232f2SAndroid Build Coastguard Worker  /// Write the given list of [values].
510*890232f2SAndroid Build Coastguard Worker  int writeList(List<int> values) {
511*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
512*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint32, 1 + values.length);
513*890232f2SAndroid Build Coastguard Worker    final result = _tail;
514*890232f2SAndroid Build Coastguard Worker    var tail = _tail;
515*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(tail, values.length);
516*890232f2SAndroid Build Coastguard Worker    tail -= _sizeofUint32;
517*890232f2SAndroid Build Coastguard Worker    for (var value in values) {
518*890232f2SAndroid Build Coastguard Worker      _setUint32AtTail(tail, tail - value);
519*890232f2SAndroid Build Coastguard Worker      tail -= _sizeofUint32;
520*890232f2SAndroid Build Coastguard Worker    }
521*890232f2SAndroid Build Coastguard Worker    return result;
522*890232f2SAndroid Build Coastguard Worker  }
523*890232f2SAndroid Build Coastguard Worker
524*890232f2SAndroid Build Coastguard Worker  /// Write the given list of 64-bit float [values].
525*890232f2SAndroid Build Coastguard Worker  int writeListFloat64(List<double> values) {
526*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
527*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofFloat64, values.length, additionalBytes: _sizeofUint32);
528*890232f2SAndroid Build Coastguard Worker    final result = _tail;
529*890232f2SAndroid Build Coastguard Worker    var tail = _tail;
530*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(tail, values.length);
531*890232f2SAndroid Build Coastguard Worker    tail -= _sizeofUint32;
532*890232f2SAndroid Build Coastguard Worker    for (var value in values) {
533*890232f2SAndroid Build Coastguard Worker      _setFloat64AtTail(tail, value);
534*890232f2SAndroid Build Coastguard Worker      tail -= _sizeofFloat64;
535*890232f2SAndroid Build Coastguard Worker    }
536*890232f2SAndroid Build Coastguard Worker    return result;
537*890232f2SAndroid Build Coastguard Worker  }
538*890232f2SAndroid Build Coastguard Worker
539*890232f2SAndroid Build Coastguard Worker  /// Write the given list of 32-bit float [values].
540*890232f2SAndroid Build Coastguard Worker  int writeListFloat32(List<double> values) {
541*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
542*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofFloat32, 1 + values.length);
543*890232f2SAndroid Build Coastguard Worker    final result = _tail;
544*890232f2SAndroid Build Coastguard Worker    var tail = _tail;
545*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(tail, values.length);
546*890232f2SAndroid Build Coastguard Worker    tail -= _sizeofUint32;
547*890232f2SAndroid Build Coastguard Worker    for (var value in values) {
548*890232f2SAndroid Build Coastguard Worker      _setFloat32AtTail(tail, value);
549*890232f2SAndroid Build Coastguard Worker      tail -= _sizeofFloat32;
550*890232f2SAndroid Build Coastguard Worker    }
551*890232f2SAndroid Build Coastguard Worker    return result;
552*890232f2SAndroid Build Coastguard Worker  }
553*890232f2SAndroid Build Coastguard Worker
554*890232f2SAndroid Build Coastguard Worker  /// Write the given list of signed 64-bit integer [values].
555*890232f2SAndroid Build Coastguard Worker  int writeListInt64(List<int> values) {
556*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
557*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofInt64, values.length, additionalBytes: _sizeofUint32);
558*890232f2SAndroid Build Coastguard Worker    final result = _tail;
559*890232f2SAndroid Build Coastguard Worker    var tail = _tail;
560*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(tail, values.length);
561*890232f2SAndroid Build Coastguard Worker    tail -= _sizeofUint32;
562*890232f2SAndroid Build Coastguard Worker    for (var value in values) {
563*890232f2SAndroid Build Coastguard Worker      _setInt64AtTail(tail, value);
564*890232f2SAndroid Build Coastguard Worker      tail -= _sizeofInt64;
565*890232f2SAndroid Build Coastguard Worker    }
566*890232f2SAndroid Build Coastguard Worker    return result;
567*890232f2SAndroid Build Coastguard Worker  }
568*890232f2SAndroid Build Coastguard Worker
569*890232f2SAndroid Build Coastguard Worker  /// Write the given list of signed 64-bit integer [values].
570*890232f2SAndroid Build Coastguard Worker  int writeListUint64(List<int> values) {
571*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
572*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint64, values.length, additionalBytes: _sizeofUint32);
573*890232f2SAndroid Build Coastguard Worker    final result = _tail;
574*890232f2SAndroid Build Coastguard Worker    var tail = _tail;
575*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(tail, values.length);
576*890232f2SAndroid Build Coastguard Worker    tail -= _sizeofUint32;
577*890232f2SAndroid Build Coastguard Worker    for (var value in values) {
578*890232f2SAndroid Build Coastguard Worker      _setUint64AtTail(tail, value);
579*890232f2SAndroid Build Coastguard Worker      tail -= _sizeofUint64;
580*890232f2SAndroid Build Coastguard Worker    }
581*890232f2SAndroid Build Coastguard Worker    return result;
582*890232f2SAndroid Build Coastguard Worker  }
583*890232f2SAndroid Build Coastguard Worker
584*890232f2SAndroid Build Coastguard Worker  /// Write the given list of signed 32-bit integer [values].
585*890232f2SAndroid Build Coastguard Worker  int writeListInt32(List<int> values) {
586*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
587*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint32, 1 + values.length);
588*890232f2SAndroid Build Coastguard Worker    final result = _tail;
589*890232f2SAndroid Build Coastguard Worker    var tail = _tail;
590*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(tail, values.length);
591*890232f2SAndroid Build Coastguard Worker    tail -= _sizeofUint32;
592*890232f2SAndroid Build Coastguard Worker    for (var value in values) {
593*890232f2SAndroid Build Coastguard Worker      _setInt32AtTail(tail, value);
594*890232f2SAndroid Build Coastguard Worker      tail -= _sizeofInt32;
595*890232f2SAndroid Build Coastguard Worker    }
596*890232f2SAndroid Build Coastguard Worker    return result;
597*890232f2SAndroid Build Coastguard Worker  }
598*890232f2SAndroid Build Coastguard Worker
599*890232f2SAndroid Build Coastguard Worker  /// Write the given list of unsigned 32-bit integer [values].
600*890232f2SAndroid Build Coastguard Worker  int writeListUint32(List<int> values) {
601*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
602*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint32, 1 + values.length);
603*890232f2SAndroid Build Coastguard Worker    final result = _tail;
604*890232f2SAndroid Build Coastguard Worker    var tail = _tail;
605*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(tail, values.length);
606*890232f2SAndroid Build Coastguard Worker    tail -= _sizeofUint32;
607*890232f2SAndroid Build Coastguard Worker    for (var value in values) {
608*890232f2SAndroid Build Coastguard Worker      _setUint32AtTail(tail, value);
609*890232f2SAndroid Build Coastguard Worker      tail -= _sizeofUint32;
610*890232f2SAndroid Build Coastguard Worker    }
611*890232f2SAndroid Build Coastguard Worker    return result;
612*890232f2SAndroid Build Coastguard Worker  }
613*890232f2SAndroid Build Coastguard Worker
614*890232f2SAndroid Build Coastguard Worker  /// Write the given list of signed 16-bit integer [values].
615*890232f2SAndroid Build Coastguard Worker  int writeListInt16(List<int> values) {
616*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
617*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint32, 1, additionalBytes: 2 * values.length);
618*890232f2SAndroid Build Coastguard Worker    final result = _tail;
619*890232f2SAndroid Build Coastguard Worker    var tail = _tail;
620*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(tail, values.length);
621*890232f2SAndroid Build Coastguard Worker    tail -= _sizeofUint32;
622*890232f2SAndroid Build Coastguard Worker    for (var value in values) {
623*890232f2SAndroid Build Coastguard Worker      _setInt16AtTail(tail, value);
624*890232f2SAndroid Build Coastguard Worker      tail -= _sizeofInt16;
625*890232f2SAndroid Build Coastguard Worker    }
626*890232f2SAndroid Build Coastguard Worker    return result;
627*890232f2SAndroid Build Coastguard Worker  }
628*890232f2SAndroid Build Coastguard Worker
629*890232f2SAndroid Build Coastguard Worker  /// Write the given list of unsigned 16-bit integer [values].
630*890232f2SAndroid Build Coastguard Worker  int writeListUint16(List<int> values) {
631*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
632*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint32, 1, additionalBytes: 2 * values.length);
633*890232f2SAndroid Build Coastguard Worker    final result = _tail;
634*890232f2SAndroid Build Coastguard Worker    var tail = _tail;
635*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(tail, values.length);
636*890232f2SAndroid Build Coastguard Worker    tail -= _sizeofUint32;
637*890232f2SAndroid Build Coastguard Worker    for (var value in values) {
638*890232f2SAndroid Build Coastguard Worker      _setUint16AtTail(tail, value);
639*890232f2SAndroid Build Coastguard Worker      tail -= _sizeofUint16;
640*890232f2SAndroid Build Coastguard Worker    }
641*890232f2SAndroid Build Coastguard Worker    return result;
642*890232f2SAndroid Build Coastguard Worker  }
643*890232f2SAndroid Build Coastguard Worker
644*890232f2SAndroid Build Coastguard Worker  /// Write the given list of bools as unsigend 8-bit integer [values].
645*890232f2SAndroid Build Coastguard Worker  int writeListBool(List<bool> values) {
646*890232f2SAndroid Build Coastguard Worker    return writeListUint8(values.map((b) => b ? 1 : 0).toList());
647*890232f2SAndroid Build Coastguard Worker  }
648*890232f2SAndroid Build Coastguard Worker
649*890232f2SAndroid Build Coastguard Worker  /// Write the given list of signed 8-bit integer [values].
650*890232f2SAndroid Build Coastguard Worker  int writeListInt8(List<int> values) {
651*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
652*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint32, 1, additionalBytes: values.length);
653*890232f2SAndroid Build Coastguard Worker    final result = _tail;
654*890232f2SAndroid Build Coastguard Worker    var tail = _tail;
655*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(tail, values.length);
656*890232f2SAndroid Build Coastguard Worker    tail -= _sizeofUint32;
657*890232f2SAndroid Build Coastguard Worker    for (var value in values) {
658*890232f2SAndroid Build Coastguard Worker      _setInt8AtTail(tail, value);
659*890232f2SAndroid Build Coastguard Worker      tail -= _sizeofUint8;
660*890232f2SAndroid Build Coastguard Worker    }
661*890232f2SAndroid Build Coastguard Worker    return result;
662*890232f2SAndroid Build Coastguard Worker  }
663*890232f2SAndroid Build Coastguard Worker
664*890232f2SAndroid Build Coastguard Worker  /// Write the given list of unsigned 8-bit integer [values].
665*890232f2SAndroid Build Coastguard Worker  int writeListUint8(List<int> values) {
666*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
667*890232f2SAndroid Build Coastguard Worker    _prepare(_sizeofUint32, 1, additionalBytes: values.length);
668*890232f2SAndroid Build Coastguard Worker    final result = _tail;
669*890232f2SAndroid Build Coastguard Worker    var tail = _tail;
670*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(tail, values.length);
671*890232f2SAndroid Build Coastguard Worker    tail -= _sizeofUint32;
672*890232f2SAndroid Build Coastguard Worker    for (var value in values) {
673*890232f2SAndroid Build Coastguard Worker      _setUint8AtTail(tail, value);
674*890232f2SAndroid Build Coastguard Worker      tail -= _sizeofUint8;
675*890232f2SAndroid Build Coastguard Worker    }
676*890232f2SAndroid Build Coastguard Worker    return result;
677*890232f2SAndroid Build Coastguard Worker  }
678*890232f2SAndroid Build Coastguard Worker
679*890232f2SAndroid Build Coastguard Worker  /// Write the given string [value] and return its offset.
680*890232f2SAndroid Build Coastguard Worker  ///
681*890232f2SAndroid Build Coastguard Worker  /// Dart strings are UTF-16 but must be stored as UTF-8 in FlatBuffers.
682*890232f2SAndroid Build Coastguard Worker  /// If the given string consists only of ASCII characters, you can indicate
683*890232f2SAndroid Build Coastguard Worker  /// enable [asciiOptimization]. In this mode, [writeString()] first tries to
684*890232f2SAndroid Build Coastguard Worker  /// copy the ASCII string directly to the output buffer and if that fails
685*890232f2SAndroid Build Coastguard Worker  /// (because there are no-ASCII characters in the string) it falls back and to
686*890232f2SAndroid Build Coastguard Worker  /// the default UTF-16 -> UTF-8 conversion (with slight performance penalty).
687*890232f2SAndroid Build Coastguard Worker  int writeString(String value, {bool asciiOptimization = false}) {
688*890232f2SAndroid Build Coastguard Worker    assert(!_inVTable);
689*890232f2SAndroid Build Coastguard Worker    if (_strings != null) {
690*890232f2SAndroid Build Coastguard Worker      return _strings!
691*890232f2SAndroid Build Coastguard Worker          .putIfAbsent(value, () => _writeString(value, asciiOptimization));
692*890232f2SAndroid Build Coastguard Worker    } else {
693*890232f2SAndroid Build Coastguard Worker      return _writeString(value, asciiOptimization);
694*890232f2SAndroid Build Coastguard Worker    }
695*890232f2SAndroid Build Coastguard Worker  }
696*890232f2SAndroid Build Coastguard Worker
697*890232f2SAndroid Build Coastguard Worker  int _writeString(String value, bool asciiOptimization) {
698*890232f2SAndroid Build Coastguard Worker    if (asciiOptimization) {
699*890232f2SAndroid Build Coastguard Worker      // [utf8.encode()] is slow (up to at least Dart SDK 2.13). If the given
700*890232f2SAndroid Build Coastguard Worker      // string is ASCII we can just write it directly, without any conversion.
701*890232f2SAndroid Build Coastguard Worker      final originalTail = _tail;
702*890232f2SAndroid Build Coastguard Worker      if (_tryWriteASCIIString(value)) return _tail;
703*890232f2SAndroid Build Coastguard Worker      // if non-ASCII: reset the output buffer position for [_writeUTFString()]
704*890232f2SAndroid Build Coastguard Worker      _tail = originalTail;
705*890232f2SAndroid Build Coastguard Worker    }
706*890232f2SAndroid Build Coastguard Worker    _writeUTFString(value);
707*890232f2SAndroid Build Coastguard Worker    return _tail;
708*890232f2SAndroid Build Coastguard Worker  }
709*890232f2SAndroid Build Coastguard Worker
710*890232f2SAndroid Build Coastguard Worker  // Try to write the string as ASCII, return false if there's a non-ascii char.
711*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
712*890232f2SAndroid Build Coastguard Worker  bool _tryWriteASCIIString(String value) {
713*890232f2SAndroid Build Coastguard Worker    _prepare(4, 1, additionalBytes: value.length + 1);
714*890232f2SAndroid Build Coastguard Worker    final length = value.length;
715*890232f2SAndroid Build Coastguard Worker    var offset = _buf.lengthInBytes - _tail + 4;
716*890232f2SAndroid Build Coastguard Worker    for (var i = 0; i < length; i++) {
717*890232f2SAndroid Build Coastguard Worker      // utf16 code unit, e.g. for '†' it's [0x20 0x20], which is 8224 decimal.
718*890232f2SAndroid Build Coastguard Worker      // ASCII characters go from 0x00 to 0x7F (which is 0 to 127 decimal).
719*890232f2SAndroid Build Coastguard Worker      final char = value.codeUnitAt(i);
720*890232f2SAndroid Build Coastguard Worker      if ((char & ~0x7F) != 0) {
721*890232f2SAndroid Build Coastguard Worker        return false;
722*890232f2SAndroid Build Coastguard Worker      }
723*890232f2SAndroid Build Coastguard Worker      _buf.setUint8(offset++, char);
724*890232f2SAndroid Build Coastguard Worker    }
725*890232f2SAndroid Build Coastguard Worker    _buf.setUint8(offset, 0); // trailing zero
726*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(_tail, value.length);
727*890232f2SAndroid Build Coastguard Worker    return true;
728*890232f2SAndroid Build Coastguard Worker  }
729*890232f2SAndroid Build Coastguard Worker
730*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
731*890232f2SAndroid Build Coastguard Worker  void _writeUTFString(String value) {
732*890232f2SAndroid Build Coastguard Worker    final bytes = utf8.encode(value) as Uint8List;
733*890232f2SAndroid Build Coastguard Worker    final length = bytes.length;
734*890232f2SAndroid Build Coastguard Worker    _prepare(4, 1, additionalBytes: length + 1);
735*890232f2SAndroid Build Coastguard Worker    _setUint32AtTail(_tail, length);
736*890232f2SAndroid Build Coastguard Worker    var offset = _buf.lengthInBytes - _tail + 4;
737*890232f2SAndroid Build Coastguard Worker    for (var i = 0; i < length; i++) {
738*890232f2SAndroid Build Coastguard Worker      _buf.setUint8(offset++, bytes[i]);
739*890232f2SAndroid Build Coastguard Worker    }
740*890232f2SAndroid Build Coastguard Worker    _buf.setUint8(offset, 0); // trailing zero
741*890232f2SAndroid Build Coastguard Worker  }
742*890232f2SAndroid Build Coastguard Worker
743*890232f2SAndroid Build Coastguard Worker  /// Used to assert whether a "Table" is currently being built.
744*890232f2SAndroid Build Coastguard Worker  ///
745*890232f2SAndroid Build Coastguard Worker  /// If you hit `assert(!_inVTable())`, you're trying to add table fields
746*890232f2SAndroid Build Coastguard Worker  /// without starting a table with [Builder.startTable()].
747*890232f2SAndroid Build Coastguard Worker  ///
748*890232f2SAndroid Build Coastguard Worker  /// If you hit `assert(_inVTable())`, you're trying to construct a
749*890232f2SAndroid Build Coastguard Worker  /// Table/Vector/String during the construction of its parent table,
750*890232f2SAndroid Build Coastguard Worker  /// between the MyTableBuilder and [Builder.endTable()].
751*890232f2SAndroid Build Coastguard Worker  /// Move the creation of these sub-objects to before the MyTableBuilder to
752*890232f2SAndroid Build Coastguard Worker  /// not get this assert.
753*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
754*890232f2SAndroid Build Coastguard Worker  bool get _inVTable => _currentVTable != null;
755*890232f2SAndroid Build Coastguard Worker
756*890232f2SAndroid Build Coastguard Worker  /// The number of bytes that have been written to the buffer so far.  The
757*890232f2SAndroid Build Coastguard Worker  /// most recently written byte is this many bytes from the end of the buffer.
758*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
759*890232f2SAndroid Build Coastguard Worker  int get offset => _tail;
760*890232f2SAndroid Build Coastguard Worker
761*890232f2SAndroid Build Coastguard Worker  /// Zero-pads the buffer, which may be required for some struct layouts.
762*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
763*890232f2SAndroid Build Coastguard Worker  void pad(int howManyBytes) {
764*890232f2SAndroid Build Coastguard Worker    for (var i = 0; i < howManyBytes; i++) {
765*890232f2SAndroid Build Coastguard Worker      putUint8(0);
766*890232f2SAndroid Build Coastguard Worker    }
767*890232f2SAndroid Build Coastguard Worker  }
768*890232f2SAndroid Build Coastguard Worker
769*890232f2SAndroid Build Coastguard Worker  /// Prepare for writing the given `count` of scalars of the given `size`.
770*890232f2SAndroid Build Coastguard Worker  /// Additionally allocate the specified `additionalBytes`. Update the current
771*890232f2SAndroid Build Coastguard Worker  /// tail pointer to point at the allocated space.
772*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
773*890232f2SAndroid Build Coastguard Worker  void _prepare(int size, int count, {int additionalBytes = 0}) {
774*890232f2SAndroid Build Coastguard Worker    assert(!_finished);
775*890232f2SAndroid Build Coastguard Worker    // Update the alignment.
776*890232f2SAndroid Build Coastguard Worker    if (_maxAlign < size) {
777*890232f2SAndroid Build Coastguard Worker      _maxAlign = size;
778*890232f2SAndroid Build Coastguard Worker    }
779*890232f2SAndroid Build Coastguard Worker    // Prepare amount of required space.
780*890232f2SAndroid Build Coastguard Worker    var dataSize = size * count + additionalBytes;
781*890232f2SAndroid Build Coastguard Worker    var alignDelta = (-(_tail + dataSize)) & (size - 1);
782*890232f2SAndroid Build Coastguard Worker    var bufSize = alignDelta + dataSize;
783*890232f2SAndroid Build Coastguard Worker    // Ensure that we have the required amount of space.
784*890232f2SAndroid Build Coastguard Worker    {
785*890232f2SAndroid Build Coastguard Worker      var oldCapacity = _buf.lengthInBytes;
786*890232f2SAndroid Build Coastguard Worker      if (_tail + bufSize > oldCapacity) {
787*890232f2SAndroid Build Coastguard Worker        var desiredNewCapacity = (oldCapacity + bufSize) * 2;
788*890232f2SAndroid Build Coastguard Worker        var deltaCapacity = desiredNewCapacity - oldCapacity;
789*890232f2SAndroid Build Coastguard Worker        deltaCapacity += (-deltaCapacity) & (_maxAlign - 1);
790*890232f2SAndroid Build Coastguard Worker        var newCapacity = oldCapacity + deltaCapacity;
791*890232f2SAndroid Build Coastguard Worker        _buf = _allocator.resize(_buf, newCapacity, _tail, 0);
792*890232f2SAndroid Build Coastguard Worker      }
793*890232f2SAndroid Build Coastguard Worker    }
794*890232f2SAndroid Build Coastguard Worker
795*890232f2SAndroid Build Coastguard Worker    // zero out the added padding
796*890232f2SAndroid Build Coastguard Worker    for (var i = _tail + 1; i <= _tail + alignDelta; i++) {
797*890232f2SAndroid Build Coastguard Worker      _setUint8AtTail(i, 0);
798*890232f2SAndroid Build Coastguard Worker    }
799*890232f2SAndroid Build Coastguard Worker
800*890232f2SAndroid Build Coastguard Worker    // Update the tail pointer.
801*890232f2SAndroid Build Coastguard Worker    _tail += bufSize;
802*890232f2SAndroid Build Coastguard Worker  }
803*890232f2SAndroid Build Coastguard Worker
804*890232f2SAndroid Build Coastguard Worker  /// Record the offset of the given [field].
805*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
806*890232f2SAndroid Build Coastguard Worker  void _trackField(int field) => _currentVTable!.addField(field, _tail);
807*890232f2SAndroid Build Coastguard Worker
808*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
809*890232f2SAndroid Build Coastguard Worker  void _setFloat64AtTail(int tail, double x) =>
810*890232f2SAndroid Build Coastguard Worker      _buf.setFloat64(_buf.lengthInBytes - tail, x, Endian.little);
811*890232f2SAndroid Build Coastguard Worker
812*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
813*890232f2SAndroid Build Coastguard Worker  void _setFloat32AtTail(int tail, double x) =>
814*890232f2SAndroid Build Coastguard Worker      _buf.setFloat32(_buf.lengthInBytes - tail, x, Endian.little);
815*890232f2SAndroid Build Coastguard Worker
816*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
817*890232f2SAndroid Build Coastguard Worker  void _setUint64AtTail(int tail, int x) =>
818*890232f2SAndroid Build Coastguard Worker      _buf.setUint64(_buf.lengthInBytes - tail, x, Endian.little);
819*890232f2SAndroid Build Coastguard Worker
820*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
821*890232f2SAndroid Build Coastguard Worker  void _setInt64AtTail(int tail, int x) =>
822*890232f2SAndroid Build Coastguard Worker      _buf.setInt64(_buf.lengthInBytes - tail, x, Endian.little);
823*890232f2SAndroid Build Coastguard Worker
824*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
825*890232f2SAndroid Build Coastguard Worker  void _setInt32AtTail(int tail, int x) =>
826*890232f2SAndroid Build Coastguard Worker      _buf.setInt32(_buf.lengthInBytes - tail, x, Endian.little);
827*890232f2SAndroid Build Coastguard Worker
828*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
829*890232f2SAndroid Build Coastguard Worker  void _setUint32AtTail(int tail, int x) =>
830*890232f2SAndroid Build Coastguard Worker      _buf.setUint32(_buf.lengthInBytes - tail, x, Endian.little);
831*890232f2SAndroid Build Coastguard Worker
832*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
833*890232f2SAndroid Build Coastguard Worker  void _setInt16AtTail(int tail, int x) =>
834*890232f2SAndroid Build Coastguard Worker      _buf.setInt16(_buf.lengthInBytes - tail, x, Endian.little);
835*890232f2SAndroid Build Coastguard Worker
836*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
837*890232f2SAndroid Build Coastguard Worker  void _setUint16AtTail(int tail, int x) =>
838*890232f2SAndroid Build Coastguard Worker      _buf.setUint16(_buf.lengthInBytes - tail, x, Endian.little);
839*890232f2SAndroid Build Coastguard Worker
840*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
841*890232f2SAndroid Build Coastguard Worker  void _setInt8AtTail(int tail, int x) =>
842*890232f2SAndroid Build Coastguard Worker      _buf.setInt8(_buf.lengthInBytes - tail, x);
843*890232f2SAndroid Build Coastguard Worker
844*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
845*890232f2SAndroid Build Coastguard Worker  void _setUint8AtTail(int tail, int x) =>
846*890232f2SAndroid Build Coastguard Worker      _buf.setUint8(_buf.lengthInBytes - tail, x);
847*890232f2SAndroid Build Coastguard Worker}
848*890232f2SAndroid Build Coastguard Worker
849*890232f2SAndroid Build Coastguard Worker/// Reader of lists of boolean values.
850*890232f2SAndroid Build Coastguard Worker///
851*890232f2SAndroid Build Coastguard Worker/// The returned unmodifiable lists lazily read values on access.
852*890232f2SAndroid Build Coastguard Workerclass BoolListReader extends Reader<List<bool>> {
853*890232f2SAndroid Build Coastguard Worker  const BoolListReader();
854*890232f2SAndroid Build Coastguard Worker
855*890232f2SAndroid Build Coastguard Worker  @override
856*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
857*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofUint32;
858*890232f2SAndroid Build Coastguard Worker
859*890232f2SAndroid Build Coastguard Worker  @override
860*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
861*890232f2SAndroid Build Coastguard Worker  List<bool> read(BufferContext bc, int offset) =>
862*890232f2SAndroid Build Coastguard Worker      _FbBoolList(bc, bc.derefObject(offset));
863*890232f2SAndroid Build Coastguard Worker}
864*890232f2SAndroid Build Coastguard Worker
865*890232f2SAndroid Build Coastguard Worker/// The reader of booleans.
866*890232f2SAndroid Build Coastguard Workerclass BoolReader extends Reader<bool> {
867*890232f2SAndroid Build Coastguard Worker  const BoolReader() : super();
868*890232f2SAndroid Build Coastguard Worker
869*890232f2SAndroid Build Coastguard Worker  @override
870*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
871*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofUint8;
872*890232f2SAndroid Build Coastguard Worker
873*890232f2SAndroid Build Coastguard Worker  @override
874*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
875*890232f2SAndroid Build Coastguard Worker  bool read(BufferContext bc, int offset) => bc._getInt8(offset) != 0;
876*890232f2SAndroid Build Coastguard Worker}
877*890232f2SAndroid Build Coastguard Worker
878*890232f2SAndroid Build Coastguard Worker/// The reader of lists of 64-bit float values.
879*890232f2SAndroid Build Coastguard Worker///
880*890232f2SAndroid Build Coastguard Worker/// The returned unmodifiable lists lazily read values on access.
881*890232f2SAndroid Build Coastguard Workerclass Float64ListReader extends Reader<List<double>> {
882*890232f2SAndroid Build Coastguard Worker  const Float64ListReader();
883*890232f2SAndroid Build Coastguard Worker
884*890232f2SAndroid Build Coastguard Worker  @override
885*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
886*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofFloat64;
887*890232f2SAndroid Build Coastguard Worker
888*890232f2SAndroid Build Coastguard Worker  @override
889*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
890*890232f2SAndroid Build Coastguard Worker  List<double> read(BufferContext bc, int offset) =>
891*890232f2SAndroid Build Coastguard Worker      _FbFloat64List(bc, bc.derefObject(offset));
892*890232f2SAndroid Build Coastguard Worker}
893*890232f2SAndroid Build Coastguard Worker
894*890232f2SAndroid Build Coastguard Workerclass Float32ListReader extends Reader<List<double>> {
895*890232f2SAndroid Build Coastguard Worker  const Float32ListReader();
896*890232f2SAndroid Build Coastguard Worker
897*890232f2SAndroid Build Coastguard Worker  @override
898*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
899*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofFloat32;
900*890232f2SAndroid Build Coastguard Worker
901*890232f2SAndroid Build Coastguard Worker  @override
902*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
903*890232f2SAndroid Build Coastguard Worker  List<double> read(BufferContext bc, int offset) =>
904*890232f2SAndroid Build Coastguard Worker      _FbFloat32List(bc, bc.derefObject(offset));
905*890232f2SAndroid Build Coastguard Worker}
906*890232f2SAndroid Build Coastguard Worker
907*890232f2SAndroid Build Coastguard Workerclass Float64Reader extends Reader<double> {
908*890232f2SAndroid Build Coastguard Worker  const Float64Reader();
909*890232f2SAndroid Build Coastguard Worker
910*890232f2SAndroid Build Coastguard Worker  @override
911*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
912*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofFloat64;
913*890232f2SAndroid Build Coastguard Worker
914*890232f2SAndroid Build Coastguard Worker  @override
915*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
916*890232f2SAndroid Build Coastguard Worker  double read(BufferContext bc, int offset) => bc._getFloat64(offset);
917*890232f2SAndroid Build Coastguard Worker}
918*890232f2SAndroid Build Coastguard Worker
919*890232f2SAndroid Build Coastguard Workerclass Float32Reader extends Reader<double> {
920*890232f2SAndroid Build Coastguard Worker  const Float32Reader();
921*890232f2SAndroid Build Coastguard Worker
922*890232f2SAndroid Build Coastguard Worker  @override
923*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
924*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofFloat32;
925*890232f2SAndroid Build Coastguard Worker
926*890232f2SAndroid Build Coastguard Worker  @override
927*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
928*890232f2SAndroid Build Coastguard Worker  double read(BufferContext bc, int offset) => bc._getFloat32(offset);
929*890232f2SAndroid Build Coastguard Worker}
930*890232f2SAndroid Build Coastguard Worker
931*890232f2SAndroid Build Coastguard Workerclass Int64Reader extends Reader<int> {
932*890232f2SAndroid Build Coastguard Worker  const Int64Reader() : super();
933*890232f2SAndroid Build Coastguard Worker
934*890232f2SAndroid Build Coastguard Worker  @override
935*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
936*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofInt64;
937*890232f2SAndroid Build Coastguard Worker
938*890232f2SAndroid Build Coastguard Worker  @override
939*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
940*890232f2SAndroid Build Coastguard Worker  int read(BufferContext bc, int offset) => bc._getInt64(offset);
941*890232f2SAndroid Build Coastguard Worker}
942*890232f2SAndroid Build Coastguard Worker
943*890232f2SAndroid Build Coastguard Worker/// The reader of signed 32-bit integers.
944*890232f2SAndroid Build Coastguard Workerclass Int32Reader extends Reader<int> {
945*890232f2SAndroid Build Coastguard Worker  const Int32Reader() : super();
946*890232f2SAndroid Build Coastguard Worker
947*890232f2SAndroid Build Coastguard Worker  @override
948*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
949*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofInt32;
950*890232f2SAndroid Build Coastguard Worker
951*890232f2SAndroid Build Coastguard Worker  @override
952*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
953*890232f2SAndroid Build Coastguard Worker  int read(BufferContext bc, int offset) => bc._getInt32(offset);
954*890232f2SAndroid Build Coastguard Worker}
955*890232f2SAndroid Build Coastguard Worker
956*890232f2SAndroid Build Coastguard Worker/// The reader of signed 32-bit integers.
957*890232f2SAndroid Build Coastguard Workerclass Int16Reader extends Reader<int> {
958*890232f2SAndroid Build Coastguard Worker  const Int16Reader() : super();
959*890232f2SAndroid Build Coastguard Worker
960*890232f2SAndroid Build Coastguard Worker  @override
961*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
962*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofInt16;
963*890232f2SAndroid Build Coastguard Worker
964*890232f2SAndroid Build Coastguard Worker  @override
965*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
966*890232f2SAndroid Build Coastguard Worker  int read(BufferContext bc, int offset) => bc._getInt16(offset);
967*890232f2SAndroid Build Coastguard Worker}
968*890232f2SAndroid Build Coastguard Worker
969*890232f2SAndroid Build Coastguard Worker/// The reader of 8-bit signed integers.
970*890232f2SAndroid Build Coastguard Workerclass Int8Reader extends Reader<int> {
971*890232f2SAndroid Build Coastguard Worker  const Int8Reader() : super();
972*890232f2SAndroid Build Coastguard Worker
973*890232f2SAndroid Build Coastguard Worker  @override
974*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
975*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofInt8;
976*890232f2SAndroid Build Coastguard Worker
977*890232f2SAndroid Build Coastguard Worker  @override
978*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
979*890232f2SAndroid Build Coastguard Worker  int read(BufferContext bc, int offset) => bc._getInt8(offset);
980*890232f2SAndroid Build Coastguard Worker}
981*890232f2SAndroid Build Coastguard Worker
982*890232f2SAndroid Build Coastguard Worker/// The reader of lists of objects. Lazy by default - see [lazy].
983*890232f2SAndroid Build Coastguard Workerclass ListReader<E> extends Reader<List<E>> {
984*890232f2SAndroid Build Coastguard Worker  final Reader<E> _elementReader;
985*890232f2SAndroid Build Coastguard Worker
986*890232f2SAndroid Build Coastguard Worker  /// Enables lazy reading of the list
987*890232f2SAndroid Build Coastguard Worker  ///
988*890232f2SAndroid Build Coastguard Worker  /// If true, the returned unmodifiable list lazily reads objects on access.
989*890232f2SAndroid Build Coastguard Worker  /// Therefore, the underlying buffer must not change while accessing the list.
990*890232f2SAndroid Build Coastguard Worker  ///
991*890232f2SAndroid Build Coastguard Worker  /// If false, reads the whole list immediately on access.
992*890232f2SAndroid Build Coastguard Worker  final bool lazy;
993*890232f2SAndroid Build Coastguard Worker
994*890232f2SAndroid Build Coastguard Worker  const ListReader(this._elementReader, {this.lazy = true});
995*890232f2SAndroid Build Coastguard Worker
996*890232f2SAndroid Build Coastguard Worker  @override
997*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
998*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofUint32;
999*890232f2SAndroid Build Coastguard Worker
1000*890232f2SAndroid Build Coastguard Worker  @override
1001*890232f2SAndroid Build Coastguard Worker  List<E> read(BufferContext bc, int offset) {
1002*890232f2SAndroid Build Coastguard Worker    final listOffset = bc.derefObject(offset);
1003*890232f2SAndroid Build Coastguard Worker    return lazy
1004*890232f2SAndroid Build Coastguard Worker        ? _FbGenericList<E>(_elementReader, bc, listOffset)
1005*890232f2SAndroid Build Coastguard Worker        : List<E>.generate(
1006*890232f2SAndroid Build Coastguard Worker            bc.buffer.getUint32(listOffset, Endian.little),
1007*890232f2SAndroid Build Coastguard Worker            (int index) => _elementReader.read(
1008*890232f2SAndroid Build Coastguard Worker                bc, listOffset + size + _elementReader.size * index),
1009*890232f2SAndroid Build Coastguard Worker            growable: true);
1010*890232f2SAndroid Build Coastguard Worker  }
1011*890232f2SAndroid Build Coastguard Worker}
1012*890232f2SAndroid Build Coastguard Worker
1013*890232f2SAndroid Build Coastguard Worker/// Object that can read a value at a [BufferContext].
1014*890232f2SAndroid Build Coastguard Workerabstract class Reader<T> {
1015*890232f2SAndroid Build Coastguard Worker  const Reader();
1016*890232f2SAndroid Build Coastguard Worker
1017*890232f2SAndroid Build Coastguard Worker  /// The size of the value in bytes.
1018*890232f2SAndroid Build Coastguard Worker  int get size;
1019*890232f2SAndroid Build Coastguard Worker
1020*890232f2SAndroid Build Coastguard Worker  /// Read the value at the given [offset] in [bc].
1021*890232f2SAndroid Build Coastguard Worker  T read(BufferContext bc, int offset);
1022*890232f2SAndroid Build Coastguard Worker
1023*890232f2SAndroid Build Coastguard Worker  /// Read the value of the given [field] in the given [object].
1024*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1025*890232f2SAndroid Build Coastguard Worker  T vTableGet(BufferContext object, int offset, int field, T defaultValue) {
1026*890232f2SAndroid Build Coastguard Worker    var fieldOffset = _vTableFieldOffset(object, offset, field);
1027*890232f2SAndroid Build Coastguard Worker    return fieldOffset == 0 ? defaultValue : read(object, offset + fieldOffset);
1028*890232f2SAndroid Build Coastguard Worker  }
1029*890232f2SAndroid Build Coastguard Worker
1030*890232f2SAndroid Build Coastguard Worker  /// Read the value of the given [field] in the given [object].
1031*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1032*890232f2SAndroid Build Coastguard Worker  T? vTableGetNullable(BufferContext object, int offset, int field) {
1033*890232f2SAndroid Build Coastguard Worker    var fieldOffset = _vTableFieldOffset(object, offset, field);
1034*890232f2SAndroid Build Coastguard Worker    return fieldOffset == 0 ? null : read(object, offset + fieldOffset);
1035*890232f2SAndroid Build Coastguard Worker  }
1036*890232f2SAndroid Build Coastguard Worker
1037*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1038*890232f2SAndroid Build Coastguard Worker  int _vTableFieldOffset(BufferContext object, int offset, int field) {
1039*890232f2SAndroid Build Coastguard Worker    var vTableSOffset = object._getInt32(offset);
1040*890232f2SAndroid Build Coastguard Worker    var vTableOffset = offset - vTableSOffset;
1041*890232f2SAndroid Build Coastguard Worker    var vTableSize = object._getUint16(vTableOffset);
1042*890232f2SAndroid Build Coastguard Worker    if (field >= vTableSize) return 0;
1043*890232f2SAndroid Build Coastguard Worker    return object._getUint16(vTableOffset + field);
1044*890232f2SAndroid Build Coastguard Worker  }
1045*890232f2SAndroid Build Coastguard Worker}
1046*890232f2SAndroid Build Coastguard Worker
1047*890232f2SAndroid Build Coastguard Worker/// The reader of string values.
1048*890232f2SAndroid Build Coastguard Workerclass StringReader extends Reader<String> {
1049*890232f2SAndroid Build Coastguard Worker  final bool asciiOptimization;
1050*890232f2SAndroid Build Coastguard Worker
1051*890232f2SAndroid Build Coastguard Worker  const StringReader({this.asciiOptimization = false}) : super();
1052*890232f2SAndroid Build Coastguard Worker
1053*890232f2SAndroid Build Coastguard Worker  @override
1054*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1055*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofUint32;
1056*890232f2SAndroid Build Coastguard Worker
1057*890232f2SAndroid Build Coastguard Worker  @override
1058*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1059*890232f2SAndroid Build Coastguard Worker  String read(BufferContext bc, int offset) {
1060*890232f2SAndroid Build Coastguard Worker    var strOffset = bc.derefObject(offset);
1061*890232f2SAndroid Build Coastguard Worker    var length = bc._getUint32(strOffset);
1062*890232f2SAndroid Build Coastguard Worker    var bytes = bc._asUint8List(strOffset + _sizeofUint32, length);
1063*890232f2SAndroid Build Coastguard Worker    if (asciiOptimization && _isLatin(bytes)) {
1064*890232f2SAndroid Build Coastguard Worker      return String.fromCharCodes(bytes);
1065*890232f2SAndroid Build Coastguard Worker    }
1066*890232f2SAndroid Build Coastguard Worker    return utf8.decode(bytes);
1067*890232f2SAndroid Build Coastguard Worker  }
1068*890232f2SAndroid Build Coastguard Worker
1069*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1070*890232f2SAndroid Build Coastguard Worker  static bool _isLatin(Uint8List bytes) {
1071*890232f2SAndroid Build Coastguard Worker    var length = bytes.length;
1072*890232f2SAndroid Build Coastguard Worker    for (var i = 0; i < length; i++) {
1073*890232f2SAndroid Build Coastguard Worker      if (bytes[i] > 127) {
1074*890232f2SAndroid Build Coastguard Worker        return false;
1075*890232f2SAndroid Build Coastguard Worker      }
1076*890232f2SAndroid Build Coastguard Worker    }
1077*890232f2SAndroid Build Coastguard Worker    return true;
1078*890232f2SAndroid Build Coastguard Worker  }
1079*890232f2SAndroid Build Coastguard Worker}
1080*890232f2SAndroid Build Coastguard Worker
1081*890232f2SAndroid Build Coastguard Worker/// An abstract reader for structs.
1082*890232f2SAndroid Build Coastguard Workerabstract class StructReader<T> extends Reader<T> {
1083*890232f2SAndroid Build Coastguard Worker  const StructReader();
1084*890232f2SAndroid Build Coastguard Worker
1085*890232f2SAndroid Build Coastguard Worker  /// Return the object at `offset`.
1086*890232f2SAndroid Build Coastguard Worker  T createObject(BufferContext bc, int offset);
1087*890232f2SAndroid Build Coastguard Worker
1088*890232f2SAndroid Build Coastguard Worker  @override
1089*890232f2SAndroid Build Coastguard Worker  T read(BufferContext bc, int offset) {
1090*890232f2SAndroid Build Coastguard Worker    return createObject(bc, offset);
1091*890232f2SAndroid Build Coastguard Worker  }
1092*890232f2SAndroid Build Coastguard Worker}
1093*890232f2SAndroid Build Coastguard Worker
1094*890232f2SAndroid Build Coastguard Worker/// An abstract reader for tables.
1095*890232f2SAndroid Build Coastguard Workerabstract class TableReader<T> extends Reader<T> {
1096*890232f2SAndroid Build Coastguard Worker  const TableReader();
1097*890232f2SAndroid Build Coastguard Worker
1098*890232f2SAndroid Build Coastguard Worker  @override
1099*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1100*890232f2SAndroid Build Coastguard Worker  int get size => 4;
1101*890232f2SAndroid Build Coastguard Worker
1102*890232f2SAndroid Build Coastguard Worker  /// Return the object at [offset].
1103*890232f2SAndroid Build Coastguard Worker  T createObject(BufferContext bc, int offset);
1104*890232f2SAndroid Build Coastguard Worker
1105*890232f2SAndroid Build Coastguard Worker  @override
1106*890232f2SAndroid Build Coastguard Worker  T read(BufferContext bc, int offset) {
1107*890232f2SAndroid Build Coastguard Worker    var objectOffset = bc.derefObject(offset);
1108*890232f2SAndroid Build Coastguard Worker    return createObject(bc, objectOffset);
1109*890232f2SAndroid Build Coastguard Worker  }
1110*890232f2SAndroid Build Coastguard Worker}
1111*890232f2SAndroid Build Coastguard Worker
1112*890232f2SAndroid Build Coastguard Worker/// Reader of lists of unsigned 32-bit integer values.
1113*890232f2SAndroid Build Coastguard Worker///
1114*890232f2SAndroid Build Coastguard Worker/// The returned unmodifiable lists lazily read values on access.
1115*890232f2SAndroid Build Coastguard Workerclass Uint32ListReader extends Reader<List<int>> {
1116*890232f2SAndroid Build Coastguard Worker  const Uint32ListReader();
1117*890232f2SAndroid Build Coastguard Worker
1118*890232f2SAndroid Build Coastguard Worker  @override
1119*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1120*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofUint32;
1121*890232f2SAndroid Build Coastguard Worker
1122*890232f2SAndroid Build Coastguard Worker  @override
1123*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1124*890232f2SAndroid Build Coastguard Worker  List<int> read(BufferContext bc, int offset) =>
1125*890232f2SAndroid Build Coastguard Worker      _FbUint32List(bc, bc.derefObject(offset));
1126*890232f2SAndroid Build Coastguard Worker}
1127*890232f2SAndroid Build Coastguard Worker
1128*890232f2SAndroid Build Coastguard Worker/// The reader of unsigned 64-bit integers.
1129*890232f2SAndroid Build Coastguard Worker///
1130*890232f2SAndroid Build Coastguard Worker/// WARNING: May have compatibility issues with JavaScript
1131*890232f2SAndroid Build Coastguard Workerclass Uint64Reader extends Reader<int> {
1132*890232f2SAndroid Build Coastguard Worker  const Uint64Reader() : super();
1133*890232f2SAndroid Build Coastguard Worker
1134*890232f2SAndroid Build Coastguard Worker  @override
1135*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1136*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofUint64;
1137*890232f2SAndroid Build Coastguard Worker
1138*890232f2SAndroid Build Coastguard Worker  @override
1139*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1140*890232f2SAndroid Build Coastguard Worker  int read(BufferContext bc, int offset) => bc._getUint64(offset);
1141*890232f2SAndroid Build Coastguard Worker}
1142*890232f2SAndroid Build Coastguard Worker
1143*890232f2SAndroid Build Coastguard Worker/// The reader of unsigned 32-bit integers.
1144*890232f2SAndroid Build Coastguard Workerclass Uint32Reader extends Reader<int> {
1145*890232f2SAndroid Build Coastguard Worker  const Uint32Reader() : super();
1146*890232f2SAndroid Build Coastguard Worker
1147*890232f2SAndroid Build Coastguard Worker  @override
1148*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1149*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofUint32;
1150*890232f2SAndroid Build Coastguard Worker
1151*890232f2SAndroid Build Coastguard Worker  @override
1152*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1153*890232f2SAndroid Build Coastguard Worker  int read(BufferContext bc, int offset) => bc._getUint32(offset);
1154*890232f2SAndroid Build Coastguard Worker}
1155*890232f2SAndroid Build Coastguard Worker
1156*890232f2SAndroid Build Coastguard Worker/// Reader of lists of unsigned 32-bit integer values.
1157*890232f2SAndroid Build Coastguard Worker///
1158*890232f2SAndroid Build Coastguard Worker/// The returned unmodifiable lists lazily read values on access.
1159*890232f2SAndroid Build Coastguard Workerclass Uint16ListReader extends Reader<List<int>> {
1160*890232f2SAndroid Build Coastguard Worker  const Uint16ListReader();
1161*890232f2SAndroid Build Coastguard Worker
1162*890232f2SAndroid Build Coastguard Worker  @override
1163*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1164*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofUint32;
1165*890232f2SAndroid Build Coastguard Worker
1166*890232f2SAndroid Build Coastguard Worker  @override
1167*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1168*890232f2SAndroid Build Coastguard Worker  List<int> read(BufferContext bc, int offset) =>
1169*890232f2SAndroid Build Coastguard Worker      _FbUint16List(bc, bc.derefObject(offset));
1170*890232f2SAndroid Build Coastguard Worker}
1171*890232f2SAndroid Build Coastguard Worker
1172*890232f2SAndroid Build Coastguard Worker/// The reader of unsigned 32-bit integers.
1173*890232f2SAndroid Build Coastguard Workerclass Uint16Reader extends Reader<int> {
1174*890232f2SAndroid Build Coastguard Worker  const Uint16Reader() : super();
1175*890232f2SAndroid Build Coastguard Worker
1176*890232f2SAndroid Build Coastguard Worker  @override
1177*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1178*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofUint16;
1179*890232f2SAndroid Build Coastguard Worker
1180*890232f2SAndroid Build Coastguard Worker  @override
1181*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1182*890232f2SAndroid Build Coastguard Worker  int read(BufferContext bc, int offset) => bc._getUint16(offset);
1183*890232f2SAndroid Build Coastguard Worker}
1184*890232f2SAndroid Build Coastguard Worker
1185*890232f2SAndroid Build Coastguard Worker/// Reader of unmodifiable binary data (a list of unsigned 8-bit integers).
1186*890232f2SAndroid Build Coastguard Workerclass Uint8ListReader extends Reader<List<int>> {
1187*890232f2SAndroid Build Coastguard Worker  /// Enables lazy reading of the list
1188*890232f2SAndroid Build Coastguard Worker  ///
1189*890232f2SAndroid Build Coastguard Worker  /// If true, the returned unmodifiable list lazily reads bytes on access.
1190*890232f2SAndroid Build Coastguard Worker  /// Therefore, the underlying buffer must not change while accessing the list.
1191*890232f2SAndroid Build Coastguard Worker  ///
1192*890232f2SAndroid Build Coastguard Worker  /// If false, reads the whole list immediately as an Uint8List.
1193*890232f2SAndroid Build Coastguard Worker  final bool lazy;
1194*890232f2SAndroid Build Coastguard Worker
1195*890232f2SAndroid Build Coastguard Worker  const Uint8ListReader({this.lazy = true});
1196*890232f2SAndroid Build Coastguard Worker
1197*890232f2SAndroid Build Coastguard Worker  @override
1198*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1199*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofUint32;
1200*890232f2SAndroid Build Coastguard Worker
1201*890232f2SAndroid Build Coastguard Worker  @override
1202*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1203*890232f2SAndroid Build Coastguard Worker  List<int> read(BufferContext bc, int offset) {
1204*890232f2SAndroid Build Coastguard Worker    final listOffset = bc.derefObject(offset);
1205*890232f2SAndroid Build Coastguard Worker    if (lazy) return _FbUint8List(bc, listOffset);
1206*890232f2SAndroid Build Coastguard Worker
1207*890232f2SAndroid Build Coastguard Worker    final length = bc._getUint32(listOffset);
1208*890232f2SAndroid Build Coastguard Worker    final result = Uint8List(length);
1209*890232f2SAndroid Build Coastguard Worker    var pos = listOffset + _sizeofUint32;
1210*890232f2SAndroid Build Coastguard Worker    for (var i = 0; i < length; i++, pos++) {
1211*890232f2SAndroid Build Coastguard Worker      result[i] = bc._getUint8(pos);
1212*890232f2SAndroid Build Coastguard Worker    }
1213*890232f2SAndroid Build Coastguard Worker    return result;
1214*890232f2SAndroid Build Coastguard Worker  }
1215*890232f2SAndroid Build Coastguard Worker}
1216*890232f2SAndroid Build Coastguard Worker
1217*890232f2SAndroid Build Coastguard Worker/// The reader of unsigned 8-bit integers.
1218*890232f2SAndroid Build Coastguard Workerclass Uint8Reader extends Reader<int> {
1219*890232f2SAndroid Build Coastguard Worker  const Uint8Reader() : super();
1220*890232f2SAndroid Build Coastguard Worker
1221*890232f2SAndroid Build Coastguard Worker  @override
1222*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1223*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofUint8;
1224*890232f2SAndroid Build Coastguard Worker
1225*890232f2SAndroid Build Coastguard Worker  @override
1226*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1227*890232f2SAndroid Build Coastguard Worker  int read(BufferContext bc, int offset) => bc._getUint8(offset);
1228*890232f2SAndroid Build Coastguard Worker}
1229*890232f2SAndroid Build Coastguard Worker
1230*890232f2SAndroid Build Coastguard Worker/// Reader of unmodifiable binary data (a list of signed 8-bit integers).
1231*890232f2SAndroid Build Coastguard Workerclass Int8ListReader extends Reader<List<int>> {
1232*890232f2SAndroid Build Coastguard Worker  /// Enables lazy reading of the list
1233*890232f2SAndroid Build Coastguard Worker  ///
1234*890232f2SAndroid Build Coastguard Worker  /// If true, the returned unmodifiable list lazily reads bytes on access.
1235*890232f2SAndroid Build Coastguard Worker  /// Therefore, the underlying buffer must not change while accessing the list.
1236*890232f2SAndroid Build Coastguard Worker  ///
1237*890232f2SAndroid Build Coastguard Worker  /// If false, reads the whole list immediately as an Uint8List.
1238*890232f2SAndroid Build Coastguard Worker  final bool lazy;
1239*890232f2SAndroid Build Coastguard Worker
1240*890232f2SAndroid Build Coastguard Worker  const Int8ListReader({this.lazy = true});
1241*890232f2SAndroid Build Coastguard Worker
1242*890232f2SAndroid Build Coastguard Worker  @override
1243*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1244*890232f2SAndroid Build Coastguard Worker  int get size => _sizeofUint32;
1245*890232f2SAndroid Build Coastguard Worker
1246*890232f2SAndroid Build Coastguard Worker  @override
1247*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1248*890232f2SAndroid Build Coastguard Worker  List<int> read(BufferContext bc, int offset) {
1249*890232f2SAndroid Build Coastguard Worker    final listOffset = bc.derefObject(offset);
1250*890232f2SAndroid Build Coastguard Worker    if (lazy) return _FbUint8List(bc, listOffset);
1251*890232f2SAndroid Build Coastguard Worker
1252*890232f2SAndroid Build Coastguard Worker    final length = bc._getUint32(listOffset);
1253*890232f2SAndroid Build Coastguard Worker    final result = Int8List(length);
1254*890232f2SAndroid Build Coastguard Worker    var pos = listOffset + _sizeofUint32;
1255*890232f2SAndroid Build Coastguard Worker    for (var i = 0; i < length; i++, pos++) {
1256*890232f2SAndroid Build Coastguard Worker      result[i] = bc._getInt8(pos);
1257*890232f2SAndroid Build Coastguard Worker    }
1258*890232f2SAndroid Build Coastguard Worker    return result;
1259*890232f2SAndroid Build Coastguard Worker  }
1260*890232f2SAndroid Build Coastguard Worker}
1261*890232f2SAndroid Build Coastguard Worker
1262*890232f2SAndroid Build Coastguard Worker/// The list backed by 64-bit values - Uint64 length and Float64.
1263*890232f2SAndroid Build Coastguard Workerclass _FbFloat64List extends _FbList<double> {
1264*890232f2SAndroid Build Coastguard Worker  _FbFloat64List(BufferContext bc, int offset) : super(bc, offset);
1265*890232f2SAndroid Build Coastguard Worker
1266*890232f2SAndroid Build Coastguard Worker  @override
1267*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1268*890232f2SAndroid Build Coastguard Worker  double operator [](int i) => bc._getFloat64(offset + 4 + 8 * i);
1269*890232f2SAndroid Build Coastguard Worker}
1270*890232f2SAndroid Build Coastguard Worker
1271*890232f2SAndroid Build Coastguard Worker/// The list backed by 32-bit values - Float32.
1272*890232f2SAndroid Build Coastguard Workerclass _FbFloat32List extends _FbList<double> {
1273*890232f2SAndroid Build Coastguard Worker  _FbFloat32List(BufferContext bc, int offset) : super(bc, offset);
1274*890232f2SAndroid Build Coastguard Worker
1275*890232f2SAndroid Build Coastguard Worker  @override
1276*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1277*890232f2SAndroid Build Coastguard Worker  double operator [](int i) => bc._getFloat32(offset + 4 + 4 * i);
1278*890232f2SAndroid Build Coastguard Worker}
1279*890232f2SAndroid Build Coastguard Worker
1280*890232f2SAndroid Build Coastguard Worker/// List backed by a generic object which may have any size.
1281*890232f2SAndroid Build Coastguard Workerclass _FbGenericList<E> extends _FbList<E> {
1282*890232f2SAndroid Build Coastguard Worker  final Reader<E> elementReader;
1283*890232f2SAndroid Build Coastguard Worker
1284*890232f2SAndroid Build Coastguard Worker  List<E?>? _items;
1285*890232f2SAndroid Build Coastguard Worker
1286*890232f2SAndroid Build Coastguard Worker  _FbGenericList(this.elementReader, BufferContext bp, int offset)
1287*890232f2SAndroid Build Coastguard Worker      : super(bp, offset);
1288*890232f2SAndroid Build Coastguard Worker
1289*890232f2SAndroid Build Coastguard Worker  @override
1290*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1291*890232f2SAndroid Build Coastguard Worker  E operator [](int i) {
1292*890232f2SAndroid Build Coastguard Worker    _items ??= List<E?>.filled(length, null);
1293*890232f2SAndroid Build Coastguard Worker    var item = _items![i];
1294*890232f2SAndroid Build Coastguard Worker    if (item == null) {
1295*890232f2SAndroid Build Coastguard Worker      item = elementReader.read(bc, offset + 4 + elementReader.size * i);
1296*890232f2SAndroid Build Coastguard Worker      _items![i] = item;
1297*890232f2SAndroid Build Coastguard Worker    }
1298*890232f2SAndroid Build Coastguard Worker    return item!;
1299*890232f2SAndroid Build Coastguard Worker  }
1300*890232f2SAndroid Build Coastguard Worker}
1301*890232f2SAndroid Build Coastguard Worker
1302*890232f2SAndroid Build Coastguard Worker/// The base class for immutable lists read from flat buffers.
1303*890232f2SAndroid Build Coastguard Workerabstract class _FbList<E> extends Object with ListMixin<E> implements List<E> {
1304*890232f2SAndroid Build Coastguard Worker  final BufferContext bc;
1305*890232f2SAndroid Build Coastguard Worker  final int offset;
1306*890232f2SAndroid Build Coastguard Worker  int? _length;
1307*890232f2SAndroid Build Coastguard Worker
1308*890232f2SAndroid Build Coastguard Worker  _FbList(this.bc, this.offset);
1309*890232f2SAndroid Build Coastguard Worker
1310*890232f2SAndroid Build Coastguard Worker  @override
1311*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1312*890232f2SAndroid Build Coastguard Worker  int get length => _length ??= bc._getUint32(offset);
1313*890232f2SAndroid Build Coastguard Worker
1314*890232f2SAndroid Build Coastguard Worker  @override
1315*890232f2SAndroid Build Coastguard Worker  set length(int i) => throw StateError('Attempt to modify immutable list');
1316*890232f2SAndroid Build Coastguard Worker
1317*890232f2SAndroid Build Coastguard Worker  @override
1318*890232f2SAndroid Build Coastguard Worker  void operator []=(int i, E e) =>
1319*890232f2SAndroid Build Coastguard Worker      throw StateError('Attempt to modify immutable list');
1320*890232f2SAndroid Build Coastguard Worker}
1321*890232f2SAndroid Build Coastguard Worker
1322*890232f2SAndroid Build Coastguard Worker/// List backed by 32-bit unsigned integers.
1323*890232f2SAndroid Build Coastguard Workerclass _FbUint32List extends _FbList<int> {
1324*890232f2SAndroid Build Coastguard Worker  _FbUint32List(BufferContext bc, int offset) : super(bc, offset);
1325*890232f2SAndroid Build Coastguard Worker
1326*890232f2SAndroid Build Coastguard Worker  @override
1327*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1328*890232f2SAndroid Build Coastguard Worker  int operator [](int i) => bc._getUint32(offset + 4 + 4 * i);
1329*890232f2SAndroid Build Coastguard Worker}
1330*890232f2SAndroid Build Coastguard Worker
1331*890232f2SAndroid Build Coastguard Worker/// List backed by 16-bit unsigned integers.
1332*890232f2SAndroid Build Coastguard Workerclass _FbUint16List extends _FbList<int> {
1333*890232f2SAndroid Build Coastguard Worker  _FbUint16List(BufferContext bc, int offset) : super(bc, offset);
1334*890232f2SAndroid Build Coastguard Worker
1335*890232f2SAndroid Build Coastguard Worker  @override
1336*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1337*890232f2SAndroid Build Coastguard Worker  int operator [](int i) => bc._getUint16(offset + 4 + 2 * i);
1338*890232f2SAndroid Build Coastguard Worker}
1339*890232f2SAndroid Build Coastguard Worker
1340*890232f2SAndroid Build Coastguard Worker/// List backed by 8-bit unsigned integers.
1341*890232f2SAndroid Build Coastguard Workerclass _FbUint8List extends _FbList<int> {
1342*890232f2SAndroid Build Coastguard Worker  _FbUint8List(BufferContext bc, int offset) : super(bc, offset);
1343*890232f2SAndroid Build Coastguard Worker
1344*890232f2SAndroid Build Coastguard Worker  @override
1345*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1346*890232f2SAndroid Build Coastguard Worker  int operator [](int i) => bc._getUint8(offset + 4 + i);
1347*890232f2SAndroid Build Coastguard Worker}
1348*890232f2SAndroid Build Coastguard Worker
1349*890232f2SAndroid Build Coastguard Worker/// List backed by 8-bit signed integers.
1350*890232f2SAndroid Build Coastguard Workerclass _FbInt8List extends _FbList<int> {
1351*890232f2SAndroid Build Coastguard Worker  _FbInt8List(BufferContext bc, int offset) : super(bc, offset);
1352*890232f2SAndroid Build Coastguard Worker
1353*890232f2SAndroid Build Coastguard Worker  @override
1354*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1355*890232f2SAndroid Build Coastguard Worker  int operator [](int i) => bc._getInt8(offset + 4 + i);
1356*890232f2SAndroid Build Coastguard Worker}
1357*890232f2SAndroid Build Coastguard Worker
1358*890232f2SAndroid Build Coastguard Worker/// List backed by 8-bit unsigned integers.
1359*890232f2SAndroid Build Coastguard Workerclass _FbBoolList extends _FbList<bool> {
1360*890232f2SAndroid Build Coastguard Worker  _FbBoolList(BufferContext bc, int offset) : super(bc, offset);
1361*890232f2SAndroid Build Coastguard Worker
1362*890232f2SAndroid Build Coastguard Worker  @override
1363*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1364*890232f2SAndroid Build Coastguard Worker  bool operator [](int i) => bc._getUint8(offset + 4 + i) == 1 ? true : false;
1365*890232f2SAndroid Build Coastguard Worker}
1366*890232f2SAndroid Build Coastguard Worker
1367*890232f2SAndroid Build Coastguard Worker/// Class that describes the structure of a table.
1368*890232f2SAndroid Build Coastguard Workerclass _VTable {
1369*890232f2SAndroid Build Coastguard Worker  static const int _metadataLength = 4;
1370*890232f2SAndroid Build Coastguard Worker
1371*890232f2SAndroid Build Coastguard Worker  final int numFields;
1372*890232f2SAndroid Build Coastguard Worker
1373*890232f2SAndroid Build Coastguard Worker  // Note: fieldOffsets start as "tail offsets" and are then transformed by
1374*890232f2SAndroid Build Coastguard Worker  // [computeFieldOffsets()] to actual offsets when a table is finished.
1375*890232f2SAndroid Build Coastguard Worker  final Uint32List fieldOffsets;
1376*890232f2SAndroid Build Coastguard Worker  bool offsetsComputed = false;
1377*890232f2SAndroid Build Coastguard Worker
1378*890232f2SAndroid Build Coastguard Worker  _VTable(this.numFields) : fieldOffsets = Uint32List(numFields);
1379*890232f2SAndroid Build Coastguard Worker
1380*890232f2SAndroid Build Coastguard Worker  /// The size of the table that uses this VTable.
1381*890232f2SAndroid Build Coastguard Worker  int tableSize = 0;
1382*890232f2SAndroid Build Coastguard Worker
1383*890232f2SAndroid Build Coastguard Worker  /// The tail of this VTable. It is used to share the same VTable between
1384*890232f2SAndroid Build Coastguard Worker  /// multiple tables of identical structure.
1385*890232f2SAndroid Build Coastguard Worker  int tail = 0;
1386*890232f2SAndroid Build Coastguard Worker
1387*890232f2SAndroid Build Coastguard Worker  int get _vTableSize => numOfUint16 * _sizeofUint16;
1388*890232f2SAndroid Build Coastguard Worker
1389*890232f2SAndroid Build Coastguard Worker  int get numOfUint16 => 1 + 1 + numFields;
1390*890232f2SAndroid Build Coastguard Worker
1391*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1392*890232f2SAndroid Build Coastguard Worker  void addField(int field, int offset) {
1393*890232f2SAndroid Build Coastguard Worker    assert(!offsetsComputed);
1394*890232f2SAndroid Build Coastguard Worker    assert(offset > 0); // it's impossible for field to start at the buffer end
1395*890232f2SAndroid Build Coastguard Worker    assert(offset <= 4294967295); // uint32 max
1396*890232f2SAndroid Build Coastguard Worker    fieldOffsets[field] = offset;
1397*890232f2SAndroid Build Coastguard Worker  }
1398*890232f2SAndroid Build Coastguard Worker
1399*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1400*890232f2SAndroid Build Coastguard Worker  bool _offsetsMatch(int vt2Start, ByteData buf) {
1401*890232f2SAndroid Build Coastguard Worker    assert(offsetsComputed);
1402*890232f2SAndroid Build Coastguard Worker    for (var i = 0; i < numFields; i++) {
1403*890232f2SAndroid Build Coastguard Worker      if (fieldOffsets[i] !=
1404*890232f2SAndroid Build Coastguard Worker          buf.getUint16(vt2Start + _metadataLength + (2 * i), Endian.little)) {
1405*890232f2SAndroid Build Coastguard Worker        return false;
1406*890232f2SAndroid Build Coastguard Worker      }
1407*890232f2SAndroid Build Coastguard Worker    }
1408*890232f2SAndroid Build Coastguard Worker    return true;
1409*890232f2SAndroid Build Coastguard Worker  }
1410*890232f2SAndroid Build Coastguard Worker
1411*890232f2SAndroid Build Coastguard Worker  /// Fill the [fieldOffsets] field.
1412*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1413*890232f2SAndroid Build Coastguard Worker  void computeFieldOffsets(int tableTail) {
1414*890232f2SAndroid Build Coastguard Worker    assert(!offsetsComputed);
1415*890232f2SAndroid Build Coastguard Worker    offsetsComputed = true;
1416*890232f2SAndroid Build Coastguard Worker    for (var i = 0; i < numFields; i++) {
1417*890232f2SAndroid Build Coastguard Worker      if (fieldOffsets[i] != 0) {
1418*890232f2SAndroid Build Coastguard Worker        fieldOffsets[i] = tableTail - fieldOffsets[i];
1419*890232f2SAndroid Build Coastguard Worker      }
1420*890232f2SAndroid Build Coastguard Worker    }
1421*890232f2SAndroid Build Coastguard Worker  }
1422*890232f2SAndroid Build Coastguard Worker
1423*890232f2SAndroid Build Coastguard Worker  /// Outputs this VTable to [buf], which is is expected to be aligned to 16-bit
1424*890232f2SAndroid Build Coastguard Worker  /// and have at least [numOfUint16] 16-bit words available.
1425*890232f2SAndroid Build Coastguard Worker  @pragma('vm:prefer-inline')
1426*890232f2SAndroid Build Coastguard Worker  void output(ByteData buf, int bufOffset) {
1427*890232f2SAndroid Build Coastguard Worker    assert(offsetsComputed);
1428*890232f2SAndroid Build Coastguard Worker    // VTable size.
1429*890232f2SAndroid Build Coastguard Worker    buf.setUint16(bufOffset, numOfUint16 * 2, Endian.little);
1430*890232f2SAndroid Build Coastguard Worker    bufOffset += 2;
1431*890232f2SAndroid Build Coastguard Worker    // Table size.
1432*890232f2SAndroid Build Coastguard Worker    buf.setUint16(bufOffset, tableSize, Endian.little);
1433*890232f2SAndroid Build Coastguard Worker    bufOffset += 2;
1434*890232f2SAndroid Build Coastguard Worker    // Field offsets.
1435*890232f2SAndroid Build Coastguard Worker    for (var i = 0; i < numFields; i++) {
1436*890232f2SAndroid Build Coastguard Worker      buf.setUint16(bufOffset, fieldOffsets[i], Endian.little);
1437*890232f2SAndroid Build Coastguard Worker      bufOffset += 2;
1438*890232f2SAndroid Build Coastguard Worker    }
1439*890232f2SAndroid Build Coastguard Worker  }
1440*890232f2SAndroid Build Coastguard Worker}
1441*890232f2SAndroid Build Coastguard Worker
1442*890232f2SAndroid Build Coastguard Worker/// The interface that [Builder] uses to allocate buffers for encoding.
1443*890232f2SAndroid Build Coastguard Workerabstract class Allocator {
1444*890232f2SAndroid Build Coastguard Worker  const Allocator();
1445*890232f2SAndroid Build Coastguard Worker
1446*890232f2SAndroid Build Coastguard Worker  /// Allocate a [ByteData] buffer of a given size.
1447*890232f2SAndroid Build Coastguard Worker  ByteData allocate(int size);
1448*890232f2SAndroid Build Coastguard Worker
1449*890232f2SAndroid Build Coastguard Worker  /// Free the given [ByteData] buffer previously allocated by [allocate].
1450*890232f2SAndroid Build Coastguard Worker  void deallocate(ByteData data);
1451*890232f2SAndroid Build Coastguard Worker
1452*890232f2SAndroid Build Coastguard Worker  /// Reallocate [newSize] bytes of memory, replacing the old [oldData]. This
1453*890232f2SAndroid Build Coastguard Worker  /// grows downwards, and is intended specifically for use with [Builder].
1454*890232f2SAndroid Build Coastguard Worker  /// Params [inUseBack] and [inUseFront] indicate how much of [oldData] is
1455*890232f2SAndroid Build Coastguard Worker  /// actually in use at each end, and needs to be copied.
1456*890232f2SAndroid Build Coastguard Worker  ByteData resize(
1457*890232f2SAndroid Build Coastguard Worker      ByteData oldData, int newSize, int inUseBack, int inUseFront) {
1458*890232f2SAndroid Build Coastguard Worker    final newData = allocate(newSize);
1459*890232f2SAndroid Build Coastguard Worker    _copyDownward(oldData, newData, inUseBack, inUseFront);
1460*890232f2SAndroid Build Coastguard Worker    deallocate(oldData);
1461*890232f2SAndroid Build Coastguard Worker    return newData;
1462*890232f2SAndroid Build Coastguard Worker  }
1463*890232f2SAndroid Build Coastguard Worker
1464*890232f2SAndroid Build Coastguard Worker  /// Called by [resize] to copy memory from [oldData] to [newData]. Only
1465*890232f2SAndroid Build Coastguard Worker  /// memory of size [inUseFront] and [inUseBack] will be copied from the front
1466*890232f2SAndroid Build Coastguard Worker  /// and back of the old memory allocation.
1467*890232f2SAndroid Build Coastguard Worker  void _copyDownward(
1468*890232f2SAndroid Build Coastguard Worker      ByteData oldData, ByteData newData, int inUseBack, int inUseFront) {
1469*890232f2SAndroid Build Coastguard Worker    if (inUseBack != 0) {
1470*890232f2SAndroid Build Coastguard Worker      newData.buffer.asUint8List().setAll(
1471*890232f2SAndroid Build Coastguard Worker          newData.lengthInBytes - inUseBack,
1472*890232f2SAndroid Build Coastguard Worker          oldData.buffer.asUint8List().getRange(
1473*890232f2SAndroid Build Coastguard Worker              oldData.lengthInBytes - inUseBack, oldData.lengthInBytes));
1474*890232f2SAndroid Build Coastguard Worker    }
1475*890232f2SAndroid Build Coastguard Worker    if (inUseFront != 0) {
1476*890232f2SAndroid Build Coastguard Worker      newData.buffer
1477*890232f2SAndroid Build Coastguard Worker          .asUint8List()
1478*890232f2SAndroid Build Coastguard Worker          .setAll(0, oldData.buffer.asUint8List().getRange(0, inUseFront));
1479*890232f2SAndroid Build Coastguard Worker    }
1480*890232f2SAndroid Build Coastguard Worker  }
1481*890232f2SAndroid Build Coastguard Worker}
1482*890232f2SAndroid Build Coastguard Worker
1483*890232f2SAndroid Build Coastguard Workerclass DefaultAllocator extends Allocator {
1484*890232f2SAndroid Build Coastguard Worker  const DefaultAllocator();
1485*890232f2SAndroid Build Coastguard Worker
1486*890232f2SAndroid Build Coastguard Worker  @override
1487*890232f2SAndroid Build Coastguard Worker  ByteData allocate(int size) => ByteData(size);
1488*890232f2SAndroid Build Coastguard Worker
1489*890232f2SAndroid Build Coastguard Worker  @override
1490*890232f2SAndroid Build Coastguard Worker  void deallocate(ByteData data) {
1491*890232f2SAndroid Build Coastguard Worker    // nothing to do, it's garbage-collected
1492*890232f2SAndroid Build Coastguard Worker  }
1493*890232f2SAndroid Build Coastguard Worker}
1494