xref: /aosp_15_r20/external/flatbuffers/ts/builder.ts (revision 890232f25432b36107d06881e0a25aaa6b473652)
1*890232f2SAndroid Build Coastguard Workerimport { ByteBuffer } from "./byte-buffer.js"
2*890232f2SAndroid Build Coastguard Workerimport { SIZEOF_SHORT, SIZE_PREFIX_LENGTH, SIZEOF_INT, FILE_IDENTIFIER_LENGTH } from "./constants.js"
3*890232f2SAndroid Build Coastguard Workerimport { Offset, IGeneratedObject } from "./types.js"
4*890232f2SAndroid Build Coastguard Worker
5*890232f2SAndroid Build Coastguard Workerexport class Builder {
6*890232f2SAndroid Build Coastguard Worker    private bb: ByteBuffer
7*890232f2SAndroid Build Coastguard Worker    /** Remaining space in the ByteBuffer. */
8*890232f2SAndroid Build Coastguard Worker    private space: number
9*890232f2SAndroid Build Coastguard Worker    /** Minimum alignment encountered so far. */
10*890232f2SAndroid Build Coastguard Worker    private minalign = 1
11*890232f2SAndroid Build Coastguard Worker    /** The vtable for the current table. */
12*890232f2SAndroid Build Coastguard Worker    private vtable: number[] | null = null
13*890232f2SAndroid Build Coastguard Worker    /** The amount of fields we're actually using. */
14*890232f2SAndroid Build Coastguard Worker    private vtable_in_use = 0
15*890232f2SAndroid Build Coastguard Worker    /** Whether we are currently serializing a table. */
16*890232f2SAndroid Build Coastguard Worker    private isNested = false;
17*890232f2SAndroid Build Coastguard Worker    /** Starting offset of the current struct/table. */
18*890232f2SAndroid Build Coastguard Worker    private object_start = 0
19*890232f2SAndroid Build Coastguard Worker    /** List of offsets of all vtables. */
20*890232f2SAndroid Build Coastguard Worker    private vtables: number[] = []
21*890232f2SAndroid Build Coastguard Worker    /** For the current vector being built. */
22*890232f2SAndroid Build Coastguard Worker    private vector_num_elems = 0
23*890232f2SAndroid Build Coastguard Worker    /** False omits default values from the serialized data */
24*890232f2SAndroid Build Coastguard Worker    private force_defaults = false;
25*890232f2SAndroid Build Coastguard Worker
26*890232f2SAndroid Build Coastguard Worker    private string_maps: Map<string | Uint8Array, number> | null = null;
27*890232f2SAndroid Build Coastguard Worker    private text_encoder = new TextEncoder();
28*890232f2SAndroid Build Coastguard Worker
29*890232f2SAndroid Build Coastguard Worker    /**
30*890232f2SAndroid Build Coastguard Worker     * Create a FlatBufferBuilder.
31*890232f2SAndroid Build Coastguard Worker     */
32*890232f2SAndroid Build Coastguard Worker    constructor(opt_initial_size?: number) {
33*890232f2SAndroid Build Coastguard Worker      let initial_size: number;
34*890232f2SAndroid Build Coastguard Worker
35*890232f2SAndroid Build Coastguard Worker      if (!opt_initial_size) {
36*890232f2SAndroid Build Coastguard Worker        initial_size = 1024;
37*890232f2SAndroid Build Coastguard Worker      } else {
38*890232f2SAndroid Build Coastguard Worker        initial_size = opt_initial_size;
39*890232f2SAndroid Build Coastguard Worker      }
40*890232f2SAndroid Build Coastguard Worker
41*890232f2SAndroid Build Coastguard Worker      /**
42*890232f2SAndroid Build Coastguard Worker       * @type {ByteBuffer}
43*890232f2SAndroid Build Coastguard Worker       * @private
44*890232f2SAndroid Build Coastguard Worker       */
45*890232f2SAndroid Build Coastguard Worker      this.bb = ByteBuffer.allocate(initial_size);
46*890232f2SAndroid Build Coastguard Worker      this.space = initial_size;
47*890232f2SAndroid Build Coastguard Worker    }
48*890232f2SAndroid Build Coastguard Worker
49*890232f2SAndroid Build Coastguard Worker
50*890232f2SAndroid Build Coastguard Worker    clear(): void {
51*890232f2SAndroid Build Coastguard Worker      this.bb.clear();
52*890232f2SAndroid Build Coastguard Worker      this.space = this.bb.capacity();
53*890232f2SAndroid Build Coastguard Worker      this.minalign = 1;
54*890232f2SAndroid Build Coastguard Worker      this.vtable = null;
55*890232f2SAndroid Build Coastguard Worker      this.vtable_in_use = 0;
56*890232f2SAndroid Build Coastguard Worker      this.isNested = false;
57*890232f2SAndroid Build Coastguard Worker      this.object_start = 0;
58*890232f2SAndroid Build Coastguard Worker      this.vtables = [];
59*890232f2SAndroid Build Coastguard Worker      this.vector_num_elems = 0;
60*890232f2SAndroid Build Coastguard Worker      this.force_defaults = false;
61*890232f2SAndroid Build Coastguard Worker      this.string_maps = null;
62*890232f2SAndroid Build Coastguard Worker    }
63*890232f2SAndroid Build Coastguard Worker
64*890232f2SAndroid Build Coastguard Worker    /**
65*890232f2SAndroid Build Coastguard Worker     * In order to save space, fields that are set to their default value
66*890232f2SAndroid Build Coastguard Worker     * don't get serialized into the buffer. Forcing defaults provides a
67*890232f2SAndroid Build Coastguard Worker     * way to manually disable this optimization.
68*890232f2SAndroid Build Coastguard Worker     *
69*890232f2SAndroid Build Coastguard Worker     * @param forceDefaults true always serializes default values
70*890232f2SAndroid Build Coastguard Worker     */
71*890232f2SAndroid Build Coastguard Worker    forceDefaults(forceDefaults: boolean): void {
72*890232f2SAndroid Build Coastguard Worker      this.force_defaults = forceDefaults;
73*890232f2SAndroid Build Coastguard Worker    }
74*890232f2SAndroid Build Coastguard Worker
75*890232f2SAndroid Build Coastguard Worker    /**
76*890232f2SAndroid Build Coastguard Worker     * Get the ByteBuffer representing the FlatBuffer. Only call this after you've
77*890232f2SAndroid Build Coastguard Worker     * called finish(). The actual data starts at the ByteBuffer's current position,
78*890232f2SAndroid Build Coastguard Worker     * not necessarily at 0.
79*890232f2SAndroid Build Coastguard Worker     */
80*890232f2SAndroid Build Coastguard Worker    dataBuffer(): ByteBuffer {
81*890232f2SAndroid Build Coastguard Worker      return this.bb;
82*890232f2SAndroid Build Coastguard Worker    }
83*890232f2SAndroid Build Coastguard Worker
84*890232f2SAndroid Build Coastguard Worker    /**
85*890232f2SAndroid Build Coastguard Worker     * Get the bytes representing the FlatBuffer. Only call this after you've
86*890232f2SAndroid Build Coastguard Worker     * called finish().
87*890232f2SAndroid Build Coastguard Worker     */
88*890232f2SAndroid Build Coastguard Worker    asUint8Array(): Uint8Array {
89*890232f2SAndroid Build Coastguard Worker      return this.bb.bytes().subarray(this.bb.position(), this.bb.position() + this.offset());
90*890232f2SAndroid Build Coastguard Worker    }
91*890232f2SAndroid Build Coastguard Worker
92*890232f2SAndroid Build Coastguard Worker    /**
93*890232f2SAndroid Build Coastguard Worker     * Prepare to write an element of `size` after `additional_bytes` have been
94*890232f2SAndroid Build Coastguard Worker     * written, e.g. if you write a string, you need to align such the int length
95*890232f2SAndroid Build Coastguard Worker     * field is aligned to 4 bytes, and the string data follows it directly. If all
96*890232f2SAndroid Build Coastguard Worker     * you need to do is alignment, `additional_bytes` will be 0.
97*890232f2SAndroid Build Coastguard Worker     *
98*890232f2SAndroid Build Coastguard Worker     * @param size This is the of the new element to write
99*890232f2SAndroid Build Coastguard Worker     * @param additional_bytes The padding size
100*890232f2SAndroid Build Coastguard Worker     */
101*890232f2SAndroid Build Coastguard Worker    prep(size: number, additional_bytes: number): void {
102*890232f2SAndroid Build Coastguard Worker      // Track the biggest thing we've ever aligned to.
103*890232f2SAndroid Build Coastguard Worker      if (size > this.minalign) {
104*890232f2SAndroid Build Coastguard Worker        this.minalign = size;
105*890232f2SAndroid Build Coastguard Worker      }
106*890232f2SAndroid Build Coastguard Worker
107*890232f2SAndroid Build Coastguard Worker      // Find the amount of alignment needed such that `size` is properly
108*890232f2SAndroid Build Coastguard Worker      // aligned after `additional_bytes`
109*890232f2SAndroid Build Coastguard Worker      const align_size = ((~(this.bb.capacity() - this.space + additional_bytes)) + 1) & (size - 1);
110*890232f2SAndroid Build Coastguard Worker
111*890232f2SAndroid Build Coastguard Worker      // Reallocate the buffer if needed.
112*890232f2SAndroid Build Coastguard Worker      while (this.space < align_size + size + additional_bytes) {
113*890232f2SAndroid Build Coastguard Worker        const old_buf_size = this.bb.capacity();
114*890232f2SAndroid Build Coastguard Worker        this.bb = Builder.growByteBuffer(this.bb);
115*890232f2SAndroid Build Coastguard Worker        this.space += this.bb.capacity() - old_buf_size;
116*890232f2SAndroid Build Coastguard Worker      }
117*890232f2SAndroid Build Coastguard Worker
118*890232f2SAndroid Build Coastguard Worker      this.pad(align_size);
119*890232f2SAndroid Build Coastguard Worker    }
120*890232f2SAndroid Build Coastguard Worker
121*890232f2SAndroid Build Coastguard Worker    pad(byte_size: number): void {
122*890232f2SAndroid Build Coastguard Worker      for (let i = 0; i < byte_size; i++) {
123*890232f2SAndroid Build Coastguard Worker        this.bb.writeInt8(--this.space, 0);
124*890232f2SAndroid Build Coastguard Worker      }
125*890232f2SAndroid Build Coastguard Worker    }
126*890232f2SAndroid Build Coastguard Worker
127*890232f2SAndroid Build Coastguard Worker    writeInt8(value: number): void {
128*890232f2SAndroid Build Coastguard Worker      this.bb.writeInt8(this.space -= 1, value);
129*890232f2SAndroid Build Coastguard Worker    }
130*890232f2SAndroid Build Coastguard Worker
131*890232f2SAndroid Build Coastguard Worker    writeInt16(value: number): void {
132*890232f2SAndroid Build Coastguard Worker      this.bb.writeInt16(this.space -= 2, value);
133*890232f2SAndroid Build Coastguard Worker    }
134*890232f2SAndroid Build Coastguard Worker
135*890232f2SAndroid Build Coastguard Worker    writeInt32(value: number): void {
136*890232f2SAndroid Build Coastguard Worker      this.bb.writeInt32(this.space -= 4, value);
137*890232f2SAndroid Build Coastguard Worker    }
138*890232f2SAndroid Build Coastguard Worker
139*890232f2SAndroid Build Coastguard Worker    writeInt64(value: bigint): void {
140*890232f2SAndroid Build Coastguard Worker      this.bb.writeInt64(this.space -= 8, value);
141*890232f2SAndroid Build Coastguard Worker    }
142*890232f2SAndroid Build Coastguard Worker
143*890232f2SAndroid Build Coastguard Worker    writeFloat32(value: number): void {
144*890232f2SAndroid Build Coastguard Worker      this.bb.writeFloat32(this.space -= 4, value);
145*890232f2SAndroid Build Coastguard Worker    }
146*890232f2SAndroid Build Coastguard Worker
147*890232f2SAndroid Build Coastguard Worker    writeFloat64(value: number): void {
148*890232f2SAndroid Build Coastguard Worker      this.bb.writeFloat64(this.space -= 8, value);
149*890232f2SAndroid Build Coastguard Worker    }
150*890232f2SAndroid Build Coastguard Worker
151*890232f2SAndroid Build Coastguard Worker    /**
152*890232f2SAndroid Build Coastguard Worker     * Add an `int8` to the buffer, properly aligned, and grows the buffer (if necessary).
153*890232f2SAndroid Build Coastguard Worker     * @param value The `int8` to add the the buffer.
154*890232f2SAndroid Build Coastguard Worker     */
155*890232f2SAndroid Build Coastguard Worker    addInt8(value: number): void {
156*890232f2SAndroid Build Coastguard Worker      this.prep(1, 0);
157*890232f2SAndroid Build Coastguard Worker      this.writeInt8(value);
158*890232f2SAndroid Build Coastguard Worker    }
159*890232f2SAndroid Build Coastguard Worker
160*890232f2SAndroid Build Coastguard Worker    /**
161*890232f2SAndroid Build Coastguard Worker     * Add an `int16` to the buffer, properly aligned, and grows the buffer (if necessary).
162*890232f2SAndroid Build Coastguard Worker     * @param value The `int16` to add the the buffer.
163*890232f2SAndroid Build Coastguard Worker     */
164*890232f2SAndroid Build Coastguard Worker    addInt16(value: number): void {
165*890232f2SAndroid Build Coastguard Worker      this.prep(2, 0);
166*890232f2SAndroid Build Coastguard Worker      this.writeInt16(value);
167*890232f2SAndroid Build Coastguard Worker    }
168*890232f2SAndroid Build Coastguard Worker
169*890232f2SAndroid Build Coastguard Worker    /**
170*890232f2SAndroid Build Coastguard Worker     * Add an `int32` to the buffer, properly aligned, and grows the buffer (if necessary).
171*890232f2SAndroid Build Coastguard Worker     * @param value The `int32` to add the the buffer.
172*890232f2SAndroid Build Coastguard Worker     */
173*890232f2SAndroid Build Coastguard Worker    addInt32(value: number): void {
174*890232f2SAndroid Build Coastguard Worker      this.prep(4, 0);
175*890232f2SAndroid Build Coastguard Worker      this.writeInt32(value);
176*890232f2SAndroid Build Coastguard Worker    }
177*890232f2SAndroid Build Coastguard Worker
178*890232f2SAndroid Build Coastguard Worker    /**
179*890232f2SAndroid Build Coastguard Worker     * Add an `int64` to the buffer, properly aligned, and grows the buffer (if necessary).
180*890232f2SAndroid Build Coastguard Worker     * @param value The `int64` to add the the buffer.
181*890232f2SAndroid Build Coastguard Worker     */
182*890232f2SAndroid Build Coastguard Worker    addInt64(value: bigint): void {
183*890232f2SAndroid Build Coastguard Worker      this.prep(8, 0);
184*890232f2SAndroid Build Coastguard Worker      this.writeInt64(value);
185*890232f2SAndroid Build Coastguard Worker    }
186*890232f2SAndroid Build Coastguard Worker
187*890232f2SAndroid Build Coastguard Worker    /**
188*890232f2SAndroid Build Coastguard Worker     * Add a `float32` to the buffer, properly aligned, and grows the buffer (if necessary).
189*890232f2SAndroid Build Coastguard Worker     * @param value The `float32` to add the the buffer.
190*890232f2SAndroid Build Coastguard Worker     */
191*890232f2SAndroid Build Coastguard Worker    addFloat32(value: number): void {
192*890232f2SAndroid Build Coastguard Worker      this.prep(4, 0);
193*890232f2SAndroid Build Coastguard Worker      this.writeFloat32(value);
194*890232f2SAndroid Build Coastguard Worker    }
195*890232f2SAndroid Build Coastguard Worker
196*890232f2SAndroid Build Coastguard Worker    /**
197*890232f2SAndroid Build Coastguard Worker     * Add a `float64` to the buffer, properly aligned, and grows the buffer (if necessary).
198*890232f2SAndroid Build Coastguard Worker     * @param value The `float64` to add the the buffer.
199*890232f2SAndroid Build Coastguard Worker     */
200*890232f2SAndroid Build Coastguard Worker    addFloat64(value: number): void {
201*890232f2SAndroid Build Coastguard Worker      this.prep(8, 0);
202*890232f2SAndroid Build Coastguard Worker      this.writeFloat64(value);
203*890232f2SAndroid Build Coastguard Worker    }
204*890232f2SAndroid Build Coastguard Worker
205*890232f2SAndroid Build Coastguard Worker    addFieldInt8(voffset: number, value: number, defaultValue: number): void {
206*890232f2SAndroid Build Coastguard Worker      if (this.force_defaults || value != defaultValue) {
207*890232f2SAndroid Build Coastguard Worker        this.addInt8(value);
208*890232f2SAndroid Build Coastguard Worker        this.slot(voffset);
209*890232f2SAndroid Build Coastguard Worker      }
210*890232f2SAndroid Build Coastguard Worker    }
211*890232f2SAndroid Build Coastguard Worker
212*890232f2SAndroid Build Coastguard Worker    addFieldInt16(voffset: number, value: number, defaultValue: number): void {
213*890232f2SAndroid Build Coastguard Worker      if (this.force_defaults || value != defaultValue) {
214*890232f2SAndroid Build Coastguard Worker        this.addInt16(value);
215*890232f2SAndroid Build Coastguard Worker        this.slot(voffset);
216*890232f2SAndroid Build Coastguard Worker      }
217*890232f2SAndroid Build Coastguard Worker    }
218*890232f2SAndroid Build Coastguard Worker
219*890232f2SAndroid Build Coastguard Worker    addFieldInt32(voffset: number, value: number, defaultValue: number): void {
220*890232f2SAndroid Build Coastguard Worker      if (this.force_defaults || value != defaultValue) {
221*890232f2SAndroid Build Coastguard Worker        this.addInt32(value);
222*890232f2SAndroid Build Coastguard Worker        this.slot(voffset);
223*890232f2SAndroid Build Coastguard Worker      }
224*890232f2SAndroid Build Coastguard Worker    }
225*890232f2SAndroid Build Coastguard Worker
226*890232f2SAndroid Build Coastguard Worker    addFieldInt64(voffset: number, value: bigint, defaultValue: bigint): void {
227*890232f2SAndroid Build Coastguard Worker      if (this.force_defaults || value !== defaultValue) {
228*890232f2SAndroid Build Coastguard Worker        this.addInt64(value);
229*890232f2SAndroid Build Coastguard Worker        this.slot(voffset);
230*890232f2SAndroid Build Coastguard Worker      }
231*890232f2SAndroid Build Coastguard Worker    }
232*890232f2SAndroid Build Coastguard Worker
233*890232f2SAndroid Build Coastguard Worker    addFieldFloat32(voffset: number, value: number, defaultValue: number): void {
234*890232f2SAndroid Build Coastguard Worker      if (this.force_defaults || value != defaultValue) {
235*890232f2SAndroid Build Coastguard Worker        this.addFloat32(value);
236*890232f2SAndroid Build Coastguard Worker        this.slot(voffset);
237*890232f2SAndroid Build Coastguard Worker      }
238*890232f2SAndroid Build Coastguard Worker    }
239*890232f2SAndroid Build Coastguard Worker
240*890232f2SAndroid Build Coastguard Worker    addFieldFloat64(voffset: number, value: number, defaultValue: number): void {
241*890232f2SAndroid Build Coastguard Worker      if (this.force_defaults || value != defaultValue) {
242*890232f2SAndroid Build Coastguard Worker        this.addFloat64(value);
243*890232f2SAndroid Build Coastguard Worker        this.slot(voffset);
244*890232f2SAndroid Build Coastguard Worker      }
245*890232f2SAndroid Build Coastguard Worker    }
246*890232f2SAndroid Build Coastguard Worker
247*890232f2SAndroid Build Coastguard Worker    addFieldOffset(voffset: number, value: Offset, defaultValue: Offset): void {
248*890232f2SAndroid Build Coastguard Worker      if (this.force_defaults || value != defaultValue) {
249*890232f2SAndroid Build Coastguard Worker        this.addOffset(value);
250*890232f2SAndroid Build Coastguard Worker        this.slot(voffset);
251*890232f2SAndroid Build Coastguard Worker      }
252*890232f2SAndroid Build Coastguard Worker    }
253*890232f2SAndroid Build Coastguard Worker
254*890232f2SAndroid Build Coastguard Worker    /**
255*890232f2SAndroid Build Coastguard Worker     * Structs are stored inline, so nothing additional is being added. `d` is always 0.
256*890232f2SAndroid Build Coastguard Worker     */
257*890232f2SAndroid Build Coastguard Worker    addFieldStruct(voffset: number, value: Offset, defaultValue: Offset): void {
258*890232f2SAndroid Build Coastguard Worker      if (value != defaultValue) {
259*890232f2SAndroid Build Coastguard Worker        this.nested(value);
260*890232f2SAndroid Build Coastguard Worker        this.slot(voffset);
261*890232f2SAndroid Build Coastguard Worker      }
262*890232f2SAndroid Build Coastguard Worker    }
263*890232f2SAndroid Build Coastguard Worker
264*890232f2SAndroid Build Coastguard Worker    /**
265*890232f2SAndroid Build Coastguard Worker     * Structures are always stored inline, they need to be created right
266*890232f2SAndroid Build Coastguard Worker     * where they're used.  You'll get this assertion failure if you
267*890232f2SAndroid Build Coastguard Worker     * created it elsewhere.
268*890232f2SAndroid Build Coastguard Worker     */
269*890232f2SAndroid Build Coastguard Worker    nested(obj: Offset): void {
270*890232f2SAndroid Build Coastguard Worker      if (obj != this.offset()) {
271*890232f2SAndroid Build Coastguard Worker        throw new Error('FlatBuffers: struct must be serialized inline.');
272*890232f2SAndroid Build Coastguard Worker      }
273*890232f2SAndroid Build Coastguard Worker    }
274*890232f2SAndroid Build Coastguard Worker
275*890232f2SAndroid Build Coastguard Worker    /**
276*890232f2SAndroid Build Coastguard Worker     * Should not be creating any other object, string or vector
277*890232f2SAndroid Build Coastguard Worker     * while an object is being constructed
278*890232f2SAndroid Build Coastguard Worker     */
279*890232f2SAndroid Build Coastguard Worker    notNested(): void {
280*890232f2SAndroid Build Coastguard Worker      if (this.isNested) {
281*890232f2SAndroid Build Coastguard Worker        throw new Error('FlatBuffers: object serialization must not be nested.');
282*890232f2SAndroid Build Coastguard Worker      }
283*890232f2SAndroid Build Coastguard Worker    }
284*890232f2SAndroid Build Coastguard Worker
285*890232f2SAndroid Build Coastguard Worker    /**
286*890232f2SAndroid Build Coastguard Worker     * Set the current vtable at `voffset` to the current location in the buffer.
287*890232f2SAndroid Build Coastguard Worker     */
288*890232f2SAndroid Build Coastguard Worker    slot(voffset: number): void {
289*890232f2SAndroid Build Coastguard Worker      if (this.vtable !== null)
290*890232f2SAndroid Build Coastguard Worker        this.vtable[voffset] = this.offset();
291*890232f2SAndroid Build Coastguard Worker    }
292*890232f2SAndroid Build Coastguard Worker
293*890232f2SAndroid Build Coastguard Worker    /**
294*890232f2SAndroid Build Coastguard Worker     * @returns Offset relative to the end of the buffer.
295*890232f2SAndroid Build Coastguard Worker     */
296*890232f2SAndroid Build Coastguard Worker    offset(): Offset {
297*890232f2SAndroid Build Coastguard Worker      return this.bb.capacity() - this.space;
298*890232f2SAndroid Build Coastguard Worker    }
299*890232f2SAndroid Build Coastguard Worker
300*890232f2SAndroid Build Coastguard Worker    /**
301*890232f2SAndroid Build Coastguard Worker     * Doubles the size of the backing ByteBuffer and copies the old data towards
302*890232f2SAndroid Build Coastguard Worker     * the end of the new buffer (since we build the buffer backwards).
303*890232f2SAndroid Build Coastguard Worker     *
304*890232f2SAndroid Build Coastguard Worker     * @param bb The current buffer with the existing data
305*890232f2SAndroid Build Coastguard Worker     * @returns A new byte buffer with the old data copied
306*890232f2SAndroid Build Coastguard Worker     * to it. The data is located at the end of the buffer.
307*890232f2SAndroid Build Coastguard Worker     *
308*890232f2SAndroid Build Coastguard Worker     * uint8Array.set() formally takes {Array<number>|ArrayBufferView}, so to pass
309*890232f2SAndroid Build Coastguard Worker     * it a uint8Array we need to suppress the type check:
310*890232f2SAndroid Build Coastguard Worker     * @suppress {checkTypes}
311*890232f2SAndroid Build Coastguard Worker     */
312*890232f2SAndroid Build Coastguard Worker    static growByteBuffer(bb: ByteBuffer): ByteBuffer {
313*890232f2SAndroid Build Coastguard Worker      const old_buf_size = bb.capacity();
314*890232f2SAndroid Build Coastguard Worker
315*890232f2SAndroid Build Coastguard Worker      // Ensure we don't grow beyond what fits in an int.
316*890232f2SAndroid Build Coastguard Worker      if (old_buf_size & 0xC0000000) {
317*890232f2SAndroid Build Coastguard Worker        throw new Error('FlatBuffers: cannot grow buffer beyond 2 gigabytes.');
318*890232f2SAndroid Build Coastguard Worker      }
319*890232f2SAndroid Build Coastguard Worker
320*890232f2SAndroid Build Coastguard Worker      const new_buf_size = old_buf_size << 1;
321*890232f2SAndroid Build Coastguard Worker      const nbb = ByteBuffer.allocate(new_buf_size);
322*890232f2SAndroid Build Coastguard Worker      nbb.setPosition(new_buf_size - old_buf_size);
323*890232f2SAndroid Build Coastguard Worker      nbb.bytes().set(bb.bytes(), new_buf_size - old_buf_size);
324*890232f2SAndroid Build Coastguard Worker      return nbb;
325*890232f2SAndroid Build Coastguard Worker    }
326*890232f2SAndroid Build Coastguard Worker
327*890232f2SAndroid Build Coastguard Worker    /**
328*890232f2SAndroid Build Coastguard Worker     * Adds on offset, relative to where it will be written.
329*890232f2SAndroid Build Coastguard Worker     *
330*890232f2SAndroid Build Coastguard Worker     * @param offset The offset to add.
331*890232f2SAndroid Build Coastguard Worker     */
332*890232f2SAndroid Build Coastguard Worker    addOffset(offset: Offset): void {
333*890232f2SAndroid Build Coastguard Worker      this.prep(SIZEOF_INT, 0); // Ensure alignment is already done.
334*890232f2SAndroid Build Coastguard Worker      this.writeInt32(this.offset() - offset + SIZEOF_INT);
335*890232f2SAndroid Build Coastguard Worker    }
336*890232f2SAndroid Build Coastguard Worker
337*890232f2SAndroid Build Coastguard Worker    /**
338*890232f2SAndroid Build Coastguard Worker     * Start encoding a new object in the buffer.  Users will not usually need to
339*890232f2SAndroid Build Coastguard Worker     * call this directly. The FlatBuffers compiler will generate helper methods
340*890232f2SAndroid Build Coastguard Worker     * that call this method internally.
341*890232f2SAndroid Build Coastguard Worker     */
342*890232f2SAndroid Build Coastguard Worker    startObject(numfields: number): void {
343*890232f2SAndroid Build Coastguard Worker      this.notNested();
344*890232f2SAndroid Build Coastguard Worker      if (this.vtable == null) {
345*890232f2SAndroid Build Coastguard Worker        this.vtable = [];
346*890232f2SAndroid Build Coastguard Worker      }
347*890232f2SAndroid Build Coastguard Worker      this.vtable_in_use = numfields;
348*890232f2SAndroid Build Coastguard Worker      for (let i = 0; i < numfields; i++) {
349*890232f2SAndroid Build Coastguard Worker        this.vtable[i] = 0; // This will push additional elements as needed
350*890232f2SAndroid Build Coastguard Worker      }
351*890232f2SAndroid Build Coastguard Worker      this.isNested = true;
352*890232f2SAndroid Build Coastguard Worker      this.object_start = this.offset();
353*890232f2SAndroid Build Coastguard Worker    }
354*890232f2SAndroid Build Coastguard Worker
355*890232f2SAndroid Build Coastguard Worker    /**
356*890232f2SAndroid Build Coastguard Worker     * Finish off writing the object that is under construction.
357*890232f2SAndroid Build Coastguard Worker     *
358*890232f2SAndroid Build Coastguard Worker     * @returns The offset to the object inside `dataBuffer`
359*890232f2SAndroid Build Coastguard Worker     */
360*890232f2SAndroid Build Coastguard Worker    endObject(): Offset {
361*890232f2SAndroid Build Coastguard Worker      if (this.vtable == null || !this.isNested) {
362*890232f2SAndroid Build Coastguard Worker        throw new Error('FlatBuffers: endObject called without startObject');
363*890232f2SAndroid Build Coastguard Worker      }
364*890232f2SAndroid Build Coastguard Worker
365*890232f2SAndroid Build Coastguard Worker      this.addInt32(0);
366*890232f2SAndroid Build Coastguard Worker      const vtableloc = this.offset();
367*890232f2SAndroid Build Coastguard Worker
368*890232f2SAndroid Build Coastguard Worker      // Trim trailing zeroes.
369*890232f2SAndroid Build Coastguard Worker      let i = this.vtable_in_use - 1;
370*890232f2SAndroid Build Coastguard Worker      // eslint-disable-next-line no-empty
371*890232f2SAndroid Build Coastguard Worker      for (; i >= 0 && this.vtable[i] == 0; i--) {}
372*890232f2SAndroid Build Coastguard Worker      const trimmed_size = i + 1;
373*890232f2SAndroid Build Coastguard Worker
374*890232f2SAndroid Build Coastguard Worker      // Write out the current vtable.
375*890232f2SAndroid Build Coastguard Worker      for (; i >= 0; i--) {
376*890232f2SAndroid Build Coastguard Worker        // Offset relative to the start of the table.
377*890232f2SAndroid Build Coastguard Worker        this.addInt16(this.vtable[i] != 0 ? vtableloc - this.vtable[i] : 0);
378*890232f2SAndroid Build Coastguard Worker      }
379*890232f2SAndroid Build Coastguard Worker
380*890232f2SAndroid Build Coastguard Worker      const standard_fields = 2; // The fields below:
381*890232f2SAndroid Build Coastguard Worker      this.addInt16(vtableloc - this.object_start);
382*890232f2SAndroid Build Coastguard Worker      const len = (trimmed_size + standard_fields) * SIZEOF_SHORT;
383*890232f2SAndroid Build Coastguard Worker      this.addInt16(len);
384*890232f2SAndroid Build Coastguard Worker
385*890232f2SAndroid Build Coastguard Worker      // Search for an existing vtable that matches the current one.
386*890232f2SAndroid Build Coastguard Worker      let existing_vtable = 0;
387*890232f2SAndroid Build Coastguard Worker      const vt1 = this.space;
388*890232f2SAndroid Build Coastguard Worker    outer_loop:
389*890232f2SAndroid Build Coastguard Worker      for (i = 0; i < this.vtables.length; i++) {
390*890232f2SAndroid Build Coastguard Worker        const vt2 = this.bb.capacity() - this.vtables[i];
391*890232f2SAndroid Build Coastguard Worker        if (len == this.bb.readInt16(vt2)) {
392*890232f2SAndroid Build Coastguard Worker          for (let j = SIZEOF_SHORT; j < len; j += SIZEOF_SHORT) {
393*890232f2SAndroid Build Coastguard Worker            if (this.bb.readInt16(vt1 + j) != this.bb.readInt16(vt2 + j)) {
394*890232f2SAndroid Build Coastguard Worker              continue outer_loop;
395*890232f2SAndroid Build Coastguard Worker            }
396*890232f2SAndroid Build Coastguard Worker          }
397*890232f2SAndroid Build Coastguard Worker          existing_vtable = this.vtables[i];
398*890232f2SAndroid Build Coastguard Worker          break;
399*890232f2SAndroid Build Coastguard Worker        }
400*890232f2SAndroid Build Coastguard Worker      }
401*890232f2SAndroid Build Coastguard Worker
402*890232f2SAndroid Build Coastguard Worker      if (existing_vtable) {
403*890232f2SAndroid Build Coastguard Worker        // Found a match:
404*890232f2SAndroid Build Coastguard Worker        // Remove the current vtable.
405*890232f2SAndroid Build Coastguard Worker        this.space = this.bb.capacity() - vtableloc;
406*890232f2SAndroid Build Coastguard Worker
407*890232f2SAndroid Build Coastguard Worker        // Point table to existing vtable.
408*890232f2SAndroid Build Coastguard Worker        this.bb.writeInt32(this.space, existing_vtable - vtableloc);
409*890232f2SAndroid Build Coastguard Worker      } else {
410*890232f2SAndroid Build Coastguard Worker        // No match:
411*890232f2SAndroid Build Coastguard Worker        // Add the location of the current vtable to the list of vtables.
412*890232f2SAndroid Build Coastguard Worker        this.vtables.push(this.offset());
413*890232f2SAndroid Build Coastguard Worker
414*890232f2SAndroid Build Coastguard Worker        // Point table to current vtable.
415*890232f2SAndroid Build Coastguard Worker        this.bb.writeInt32(this.bb.capacity() - vtableloc, this.offset() - vtableloc);
416*890232f2SAndroid Build Coastguard Worker      }
417*890232f2SAndroid Build Coastguard Worker
418*890232f2SAndroid Build Coastguard Worker      this.isNested = false;
419*890232f2SAndroid Build Coastguard Worker      return vtableloc as Offset;
420*890232f2SAndroid Build Coastguard Worker    }
421*890232f2SAndroid Build Coastguard Worker
422*890232f2SAndroid Build Coastguard Worker    /**
423*890232f2SAndroid Build Coastguard Worker     * Finalize a buffer, poiting to the given `root_table`.
424*890232f2SAndroid Build Coastguard Worker     */
425*890232f2SAndroid Build Coastguard Worker    finish(root_table: Offset, opt_file_identifier?: string, opt_size_prefix?: boolean): void {
426*890232f2SAndroid Build Coastguard Worker      const size_prefix = opt_size_prefix ? SIZE_PREFIX_LENGTH : 0;
427*890232f2SAndroid Build Coastguard Worker      if (opt_file_identifier) {
428*890232f2SAndroid Build Coastguard Worker        const file_identifier = opt_file_identifier;
429*890232f2SAndroid Build Coastguard Worker        this.prep(this.minalign, SIZEOF_INT +
430*890232f2SAndroid Build Coastguard Worker          FILE_IDENTIFIER_LENGTH + size_prefix);
431*890232f2SAndroid Build Coastguard Worker        if (file_identifier.length != FILE_IDENTIFIER_LENGTH) {
432*890232f2SAndroid Build Coastguard Worker          throw new Error('FlatBuffers: file identifier must be length ' +
433*890232f2SAndroid Build Coastguard Worker            FILE_IDENTIFIER_LENGTH);
434*890232f2SAndroid Build Coastguard Worker        }
435*890232f2SAndroid Build Coastguard Worker        for (let i = FILE_IDENTIFIER_LENGTH - 1; i >= 0; i--) {
436*890232f2SAndroid Build Coastguard Worker          this.writeInt8(file_identifier.charCodeAt(i));
437*890232f2SAndroid Build Coastguard Worker        }
438*890232f2SAndroid Build Coastguard Worker      }
439*890232f2SAndroid Build Coastguard Worker      this.prep(this.minalign, SIZEOF_INT + size_prefix);
440*890232f2SAndroid Build Coastguard Worker      this.addOffset(root_table);
441*890232f2SAndroid Build Coastguard Worker      if (size_prefix) {
442*890232f2SAndroid Build Coastguard Worker        this.addInt32(this.bb.capacity() - this.space);
443*890232f2SAndroid Build Coastguard Worker      }
444*890232f2SAndroid Build Coastguard Worker      this.bb.setPosition(this.space);
445*890232f2SAndroid Build Coastguard Worker    }
446*890232f2SAndroid Build Coastguard Worker
447*890232f2SAndroid Build Coastguard Worker    /**
448*890232f2SAndroid Build Coastguard Worker     * Finalize a size prefixed buffer, pointing to the given `root_table`.
449*890232f2SAndroid Build Coastguard Worker     */
450*890232f2SAndroid Build Coastguard Worker    finishSizePrefixed(this: Builder, root_table: Offset, opt_file_identifier?: string): void {
451*890232f2SAndroid Build Coastguard Worker      this.finish(root_table, opt_file_identifier, true);
452*890232f2SAndroid Build Coastguard Worker    }
453*890232f2SAndroid Build Coastguard Worker
454*890232f2SAndroid Build Coastguard Worker    /**
455*890232f2SAndroid Build Coastguard Worker     * This checks a required field has been set in a given table that has
456*890232f2SAndroid Build Coastguard Worker     * just been constructed.
457*890232f2SAndroid Build Coastguard Worker     */
458*890232f2SAndroid Build Coastguard Worker    requiredField(table: Offset, field: number): void {
459*890232f2SAndroid Build Coastguard Worker      const table_start = this.bb.capacity() - table;
460*890232f2SAndroid Build Coastguard Worker      const vtable_start = table_start - this.bb.readInt32(table_start);
461*890232f2SAndroid Build Coastguard Worker      const ok = this.bb.readInt16(vtable_start + field) != 0;
462*890232f2SAndroid Build Coastguard Worker
463*890232f2SAndroid Build Coastguard Worker      // If this fails, the caller will show what field needs to be set.
464*890232f2SAndroid Build Coastguard Worker      if (!ok) {
465*890232f2SAndroid Build Coastguard Worker        throw new Error('FlatBuffers: field ' + field + ' must be set');
466*890232f2SAndroid Build Coastguard Worker      }
467*890232f2SAndroid Build Coastguard Worker    }
468*890232f2SAndroid Build Coastguard Worker
469*890232f2SAndroid Build Coastguard Worker    /**
470*890232f2SAndroid Build Coastguard Worker     * Start a new array/vector of objects.  Users usually will not call
471*890232f2SAndroid Build Coastguard Worker     * this directly. The FlatBuffers compiler will create a start/end
472*890232f2SAndroid Build Coastguard Worker     * method for vector types in generated code.
473*890232f2SAndroid Build Coastguard Worker     *
474*890232f2SAndroid Build Coastguard Worker     * @param elem_size The size of each element in the array
475*890232f2SAndroid Build Coastguard Worker     * @param num_elems The number of elements in the array
476*890232f2SAndroid Build Coastguard Worker     * @param alignment The alignment of the array
477*890232f2SAndroid Build Coastguard Worker     */
478*890232f2SAndroid Build Coastguard Worker    startVector(elem_size: number, num_elems: number, alignment: number): void {
479*890232f2SAndroid Build Coastguard Worker      this.notNested();
480*890232f2SAndroid Build Coastguard Worker      this.vector_num_elems = num_elems;
481*890232f2SAndroid Build Coastguard Worker      this.prep(SIZEOF_INT, elem_size * num_elems);
482*890232f2SAndroid Build Coastguard Worker      this.prep(alignment, elem_size * num_elems); // Just in case alignment > int.
483*890232f2SAndroid Build Coastguard Worker    }
484*890232f2SAndroid Build Coastguard Worker
485*890232f2SAndroid Build Coastguard Worker    /**
486*890232f2SAndroid Build Coastguard Worker     * Finish off the creation of an array and all its elements. The array must be
487*890232f2SAndroid Build Coastguard Worker     * created with `startVector`.
488*890232f2SAndroid Build Coastguard Worker     *
489*890232f2SAndroid Build Coastguard Worker     * @returns The offset at which the newly created array
490*890232f2SAndroid Build Coastguard Worker     * starts.
491*890232f2SAndroid Build Coastguard Worker     */
492*890232f2SAndroid Build Coastguard Worker    endVector(): Offset {
493*890232f2SAndroid Build Coastguard Worker      this.writeInt32(this.vector_num_elems);
494*890232f2SAndroid Build Coastguard Worker      return this.offset();
495*890232f2SAndroid Build Coastguard Worker    }
496*890232f2SAndroid Build Coastguard Worker
497*890232f2SAndroid Build Coastguard Worker    /**
498*890232f2SAndroid Build Coastguard Worker     * Encode the string `s` in the buffer using UTF-8. If the string passed has
499*890232f2SAndroid Build Coastguard Worker     * already been seen, we return the offset of the already written string
500*890232f2SAndroid Build Coastguard Worker     *
501*890232f2SAndroid Build Coastguard Worker     * @param s The string to encode
502*890232f2SAndroid Build Coastguard Worker     * @return The offset in the buffer where the encoded string starts
503*890232f2SAndroid Build Coastguard Worker     */
504*890232f2SAndroid Build Coastguard Worker    createSharedString(s: string | Uint8Array): Offset {
505*890232f2SAndroid Build Coastguard Worker      if (!s) { return 0 }
506*890232f2SAndroid Build Coastguard Worker
507*890232f2SAndroid Build Coastguard Worker      if (!this.string_maps) {
508*890232f2SAndroid Build Coastguard Worker        this.string_maps = new Map();
509*890232f2SAndroid Build Coastguard Worker      }
510*890232f2SAndroid Build Coastguard Worker
511*890232f2SAndroid Build Coastguard Worker      if (this.string_maps.has(s)) {
512*890232f2SAndroid Build Coastguard Worker        return this.string_maps.get(s) as Offset
513*890232f2SAndroid Build Coastguard Worker      }
514*890232f2SAndroid Build Coastguard Worker      const offset = this.createString(s)
515*890232f2SAndroid Build Coastguard Worker      this.string_maps.set(s, offset)
516*890232f2SAndroid Build Coastguard Worker      return offset
517*890232f2SAndroid Build Coastguard Worker    }
518*890232f2SAndroid Build Coastguard Worker
519*890232f2SAndroid Build Coastguard Worker    /**
520*890232f2SAndroid Build Coastguard Worker     * Encode the string `s` in the buffer using UTF-8. If a Uint8Array is passed
521*890232f2SAndroid Build Coastguard Worker     * instead of a string, it is assumed to contain valid UTF-8 encoded data.
522*890232f2SAndroid Build Coastguard Worker     *
523*890232f2SAndroid Build Coastguard Worker     * @param s The string to encode
524*890232f2SAndroid Build Coastguard Worker     * @return The offset in the buffer where the encoded string starts
525*890232f2SAndroid Build Coastguard Worker     */
526*890232f2SAndroid Build Coastguard Worker    createString(s: string | Uint8Array | null | undefined): Offset {
527*890232f2SAndroid Build Coastguard Worker      if (s === null || s === undefined) {
528*890232f2SAndroid Build Coastguard Worker        return 0;
529*890232f2SAndroid Build Coastguard Worker      }
530*890232f2SAndroid Build Coastguard Worker
531*890232f2SAndroid Build Coastguard Worker      let utf8: string | Uint8Array | number[];
532*890232f2SAndroid Build Coastguard Worker      if (s instanceof Uint8Array) {
533*890232f2SAndroid Build Coastguard Worker        utf8 = s;
534*890232f2SAndroid Build Coastguard Worker      } else {
535*890232f2SAndroid Build Coastguard Worker        utf8 = this.text_encoder.encode(s);
536*890232f2SAndroid Build Coastguard Worker      }
537*890232f2SAndroid Build Coastguard Worker
538*890232f2SAndroid Build Coastguard Worker      this.addInt8(0);
539*890232f2SAndroid Build Coastguard Worker      this.startVector(1, utf8.length, 1);
540*890232f2SAndroid Build Coastguard Worker      this.bb.setPosition(this.space -= utf8.length);
541*890232f2SAndroid Build Coastguard Worker      for (let i = 0, offset = this.space, bytes = this.bb.bytes(); i < utf8.length; i++) {
542*890232f2SAndroid Build Coastguard Worker        bytes[offset++] = utf8[i];
543*890232f2SAndroid Build Coastguard Worker      }
544*890232f2SAndroid Build Coastguard Worker      return this.endVector();
545*890232f2SAndroid Build Coastguard Worker    }
546*890232f2SAndroid Build Coastguard Worker
547*890232f2SAndroid Build Coastguard Worker    /**
548*890232f2SAndroid Build Coastguard Worker     * A helper function to pack an object
549*890232f2SAndroid Build Coastguard Worker     *
550*890232f2SAndroid Build Coastguard Worker     * @returns offset of obj
551*890232f2SAndroid Build Coastguard Worker     */
552*890232f2SAndroid Build Coastguard Worker    createObjectOffset(obj: string | any): Offset {
553*890232f2SAndroid Build Coastguard Worker      if(obj === null) {
554*890232f2SAndroid Build Coastguard Worker        return 0
555*890232f2SAndroid Build Coastguard Worker      }
556*890232f2SAndroid Build Coastguard Worker
557*890232f2SAndroid Build Coastguard Worker      if(typeof obj === 'string') {
558*890232f2SAndroid Build Coastguard Worker        return this.createString(obj);
559*890232f2SAndroid Build Coastguard Worker      } else {
560*890232f2SAndroid Build Coastguard Worker        return obj.pack(this);
561*890232f2SAndroid Build Coastguard Worker      }
562*890232f2SAndroid Build Coastguard Worker    }
563*890232f2SAndroid Build Coastguard Worker
564*890232f2SAndroid Build Coastguard Worker    /**
565*890232f2SAndroid Build Coastguard Worker     * A helper function to pack a list of object
566*890232f2SAndroid Build Coastguard Worker     *
567*890232f2SAndroid Build Coastguard Worker     * @returns list of offsets of each non null object
568*890232f2SAndroid Build Coastguard Worker     */
569*890232f2SAndroid Build Coastguard Worker    createObjectOffsetList(list: string[] | any[]): Offset[] {
570*890232f2SAndroid Build Coastguard Worker      const ret: number[] = [];
571*890232f2SAndroid Build Coastguard Worker
572*890232f2SAndroid Build Coastguard Worker      for(let i = 0; i < list.length; ++i) {
573*890232f2SAndroid Build Coastguard Worker        const val = list[i];
574*890232f2SAndroid Build Coastguard Worker
575*890232f2SAndroid Build Coastguard Worker        if(val !== null) {
576*890232f2SAndroid Build Coastguard Worker          ret.push(this.createObjectOffset(val));
577*890232f2SAndroid Build Coastguard Worker        } else {
578*890232f2SAndroid Build Coastguard Worker          throw new Error(
579*890232f2SAndroid Build Coastguard Worker            'FlatBuffers: Argument for createObjectOffsetList cannot contain null.');
580*890232f2SAndroid Build Coastguard Worker        }
581*890232f2SAndroid Build Coastguard Worker      }
582*890232f2SAndroid Build Coastguard Worker
583*890232f2SAndroid Build Coastguard Worker      return ret;
584*890232f2SAndroid Build Coastguard Worker    }
585*890232f2SAndroid Build Coastguard Worker
586*890232f2SAndroid Build Coastguard Worker    createStructOffsetList(list: string[] | any[], startFunc: (builder: Builder, length: number) => void): Offset {
587*890232f2SAndroid Build Coastguard Worker      startFunc(this, list.length);
588*890232f2SAndroid Build Coastguard Worker      this.createObjectOffsetList(list.slice().reverse());
589*890232f2SAndroid Build Coastguard Worker      return this.endVector();
590*890232f2SAndroid Build Coastguard Worker    }
591*890232f2SAndroid Build Coastguard Worker  }
592