• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1package flatbuffers
2
3// Builder is a state machine for creating FlatBuffer objects.
4// Use a Builder to construct object(s) starting from leaf nodes.
5//
6// A Builder constructs byte buffers in a last-first manner for simplicity and
7// performance.
8type Builder struct {
9	// `Bytes` gives raw access to the buffer. Most users will want to use
10	// FinishedBytes() instead.
11	Bytes []byte
12
13	minalign  int
14	vtable    []UOffsetT
15	objectEnd UOffsetT
16	vtables   []UOffsetT
17	head      UOffsetT
18	nested    bool
19	finished  bool
20}
21
22// NewBuilder initializes a Builder of size `initial_size`.
23// The internal buffer is grown as needed.
24func NewBuilder(initialSize int) *Builder {
25	if initialSize <= 0 {
26		initialSize = 0
27	}
28
29	b := &Builder{}
30	b.Bytes = make([]byte, initialSize)
31	b.head = UOffsetT(initialSize)
32	b.minalign = 1
33	b.vtables = make([]UOffsetT, 0, 16) // sensible default capacity
34
35	return b
36}
37
38// Reset truncates the underlying Builder buffer, facilitating alloc-free
39// reuse of a Builder. It also resets bookkeeping data.
40func (b *Builder) Reset() {
41	if b.Bytes != nil {
42		b.Bytes = b.Bytes[:cap(b.Bytes)]
43	}
44
45	if b.vtables != nil {
46		b.vtables = b.vtables[:0]
47	}
48
49	if b.vtable != nil {
50		b.vtable = b.vtable[:0]
51	}
52
53	b.head = UOffsetT(len(b.Bytes))
54	b.minalign = 1
55	b.nested = false
56	b.finished = false
57}
58
59// FinishedBytes returns a pointer to the written data in the byte buffer.
60// Panics if the builder is not in a finished state (which is caused by calling
61// `Finish()`).
62func (b *Builder) FinishedBytes() []byte {
63	b.assertFinished()
64	return b.Bytes[b.Head():]
65}
66
67// StartObject initializes bookkeeping for writing a new object.
68func (b *Builder) StartObject(numfields int) {
69	b.assertNotNested()
70	b.nested = true
71
72	// use 32-bit offsets so that arithmetic doesn't overflow.
73	if cap(b.vtable) < numfields || b.vtable == nil {
74		b.vtable = make([]UOffsetT, numfields)
75	} else {
76		b.vtable = b.vtable[:numfields]
77		for i := 0; i < len(b.vtable); i++ {
78			b.vtable[i] = 0
79		}
80	}
81
82	b.objectEnd = b.Offset()
83	b.minalign = 1
84}
85
86// WriteVtable serializes the vtable for the current object, if applicable.
87//
88// Before writing out the vtable, this checks pre-existing vtables for equality
89// to this one. If an equal vtable is found, point the object to the existing
90// vtable and return.
91//
92// Because vtable values are sensitive to alignment of object data, not all
93// logically-equal vtables will be deduplicated.
94//
95// A vtable has the following format:
96//   <VOffsetT: size of the vtable in bytes, including this value>
97//   <VOffsetT: size of the object in bytes, including the vtable offset>
98//   <VOffsetT: offset for a field> * N, where N is the number of fields in
99//	        the schema for this type. Includes deprecated fields.
100// Thus, a vtable is made of 2 + N elements, each SizeVOffsetT bytes wide.
101//
102// An object has the following format:
103//   <SOffsetT: offset to this object's vtable (may be negative)>
104//   <byte: data>+
105func (b *Builder) WriteVtable() (n UOffsetT) {
106	// Prepend a zero scalar to the object. Later in this function we'll
107	// write an offset here that points to the object's vtable:
108	b.PrependSOffsetT(0)
109
110	objectOffset := b.Offset()
111	existingVtable := UOffsetT(0)
112
113	// Search backwards through existing vtables, because similar vtables
114	// are likely to have been recently appended. See
115	// BenchmarkVtableDeduplication for a case in which this heuristic
116	// saves about 30% of the time used in writing objects with duplicate
117	// tables.
118	for i := len(b.vtables) - 1; i >= 0; i-- {
119		// Find the other vtable, which is associated with `i`:
120		vt2Offset := b.vtables[i]
121		vt2Start := len(b.Bytes) - int(vt2Offset)
122		vt2Len := GetVOffsetT(b.Bytes[vt2Start:])
123
124		metadata := VtableMetadataFields * SizeVOffsetT
125		vt2End := vt2Start + int(vt2Len)
126		vt2 := b.Bytes[vt2Start+metadata : vt2End]
127
128		// Compare the other vtable to the one under consideration.
129		// If they are equal, store the offset and break:
130		if vtableEqual(b.vtable, objectOffset, vt2) {
131			existingVtable = vt2Offset
132			break
133		}
134	}
135
136	if existingVtable == 0 {
137		// Did not find a vtable, so write this one to the buffer.
138
139		// Write out the current vtable in reverse , because
140		// serialization occurs in last-first order:
141		for i := len(b.vtable) - 1; i >= 0; i-- {
142			var off UOffsetT
143			if b.vtable[i] != 0 {
144				// Forward reference to field;
145				// use 32bit number to assert no overflow:
146				off = objectOffset - b.vtable[i]
147			}
148
149			b.PrependVOffsetT(VOffsetT(off))
150		}
151
152		// The two metadata fields are written last.
153
154		// First, store the object bytesize:
155		objectSize := objectOffset - b.objectEnd
156		b.PrependVOffsetT(VOffsetT(objectSize))
157
158		// Second, store the vtable bytesize:
159		vBytes := (len(b.vtable) + VtableMetadataFields) * SizeVOffsetT
160		b.PrependVOffsetT(VOffsetT(vBytes))
161
162		// Next, write the offset to the new vtable in the
163		// already-allocated SOffsetT at the beginning of this object:
164		objectStart := SOffsetT(len(b.Bytes)) - SOffsetT(objectOffset)
165		WriteSOffsetT(b.Bytes[objectStart:],
166			SOffsetT(b.Offset())-SOffsetT(objectOffset))
167
168		// Finally, store this vtable in memory for future
169		// deduplication:
170		b.vtables = append(b.vtables, b.Offset())
171	} else {
172		// Found a duplicate vtable.
173
174		objectStart := SOffsetT(len(b.Bytes)) - SOffsetT(objectOffset)
175		b.head = UOffsetT(objectStart)
176
177		// Write the offset to the found vtable in the
178		// already-allocated SOffsetT at the beginning of this object:
179		WriteSOffsetT(b.Bytes[b.head:],
180			SOffsetT(existingVtable)-SOffsetT(objectOffset))
181	}
182
183	b.vtable = b.vtable[:0]
184	return objectOffset
185}
186
187// EndObject writes data necessary to finish object construction.
188func (b *Builder) EndObject() UOffsetT {
189	b.assertNested()
190	n := b.WriteVtable()
191	b.nested = false
192	return n
193}
194
195// Doubles the size of the byteslice, and copies the old data towards the
196// end of the new byteslice (since we build the buffer backwards).
197func (b *Builder) growByteBuffer() {
198	if (int64(len(b.Bytes)) & int64(0xC0000000)) != 0 {
199		panic("cannot grow buffer beyond 2 gigabytes")
200	}
201	newLen := len(b.Bytes) * 2
202	if newLen == 0 {
203		newLen = 1
204	}
205
206	if cap(b.Bytes) >= newLen {
207		b.Bytes = b.Bytes[:newLen]
208	} else {
209		extension := make([]byte, newLen-len(b.Bytes))
210		b.Bytes = append(b.Bytes, extension...)
211	}
212
213	middle := newLen / 2
214	copy(b.Bytes[middle:], b.Bytes[:middle])
215}
216
217// Head gives the start of useful data in the underlying byte buffer.
218// Note: unlike other functions, this value is interpreted as from the left.
219func (b *Builder) Head() UOffsetT {
220	return b.head
221}
222
223// Offset relative to the end of the buffer.
224func (b *Builder) Offset() UOffsetT {
225	return UOffsetT(len(b.Bytes)) - b.head
226}
227
228// Pad places zeros at the current offset.
229func (b *Builder) Pad(n int) {
230	for i := 0; i < n; i++ {
231		b.PlaceByte(0)
232	}
233}
234
235// Prep prepares to write an element of `size` after `additional_bytes`
236// have been written, e.g. if you write a string, you need to align such
237// the int length field is aligned to SizeInt32, and the string data follows it
238// directly.
239// If all you need to do is align, `additionalBytes` will be 0.
240func (b *Builder) Prep(size, additionalBytes int) {
241	// Track the biggest thing we've ever aligned to.
242	if size > b.minalign {
243		b.minalign = size
244	}
245	// Find the amount of alignment needed such that `size` is properly
246	// aligned after `additionalBytes`:
247	alignSize := (^(len(b.Bytes) - int(b.Head()) + additionalBytes)) + 1
248	alignSize &= (size - 1)
249
250	// Reallocate the buffer if needed:
251	for int(b.head) <= alignSize+size+additionalBytes {
252		oldBufSize := len(b.Bytes)
253		b.growByteBuffer()
254		b.head += UOffsetT(len(b.Bytes) - oldBufSize)
255	}
256	b.Pad(alignSize)
257}
258
259// PrependSOffsetT prepends an SOffsetT, relative to where it will be written.
260func (b *Builder) PrependSOffsetT(off SOffsetT) {
261	b.Prep(SizeSOffsetT, 0) // Ensure alignment is already done.
262	if !(UOffsetT(off) <= b.Offset()) {
263		panic("unreachable: off <= b.Offset()")
264	}
265	off2 := SOffsetT(b.Offset()) - off + SOffsetT(SizeSOffsetT)
266	b.PlaceSOffsetT(off2)
267}
268
269// PrependUOffsetT prepends an UOffsetT, relative to where it will be written.
270func (b *Builder) PrependUOffsetT(off UOffsetT) {
271	b.Prep(SizeUOffsetT, 0) // Ensure alignment is already done.
272	if !(off <= b.Offset()) {
273		panic("unreachable: off <= b.Offset()")
274	}
275	off2 := b.Offset() - off + UOffsetT(SizeUOffsetT)
276	b.PlaceUOffsetT(off2)
277}
278
279// StartVector initializes bookkeeping for writing a new vector.
280//
281// A vector has the following format:
282//   <UOffsetT: number of elements in this vector>
283//   <T: data>+, where T is the type of elements of this vector.
284func (b *Builder) StartVector(elemSize, numElems, alignment int) UOffsetT {
285	b.assertNotNested()
286	b.nested = true
287	b.Prep(SizeUint32, elemSize*numElems)
288	b.Prep(alignment, elemSize*numElems) // Just in case alignment > int.
289	return b.Offset()
290}
291
292// EndVector writes data necessary to finish vector construction.
293func (b *Builder) EndVector(vectorNumElems int) UOffsetT {
294	b.assertNested()
295
296	// we already made space for this, so write without PrependUint32
297	b.PlaceUOffsetT(UOffsetT(vectorNumElems))
298
299	b.nested = false
300	return b.Offset()
301}
302
303// CreateString writes a null-terminated string as a vector.
304func (b *Builder) CreateString(s string) UOffsetT {
305	b.assertNotNested()
306	b.nested = true
307
308	b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
309	b.PlaceByte(0)
310
311	l := UOffsetT(len(s))
312
313	b.head -= l
314	copy(b.Bytes[b.head:b.head+l], s)
315
316	return b.EndVector(len(s))
317}
318
319// CreateByteString writes a byte slice as a string (null-terminated).
320func (b *Builder) CreateByteString(s []byte) UOffsetT {
321	b.assertNotNested()
322	b.nested = true
323
324	b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
325	b.PlaceByte(0)
326
327	l := UOffsetT(len(s))
328
329	b.head -= l
330	copy(b.Bytes[b.head:b.head+l], s)
331
332	return b.EndVector(len(s))
333}
334
335// CreateByteVector writes a ubyte vector
336func (b *Builder) CreateByteVector(v []byte) UOffsetT {
337	b.assertNotNested()
338	b.nested = true
339
340	b.Prep(int(SizeUOffsetT), len(v)*SizeByte)
341
342	l := UOffsetT(len(v))
343
344	b.head -= l
345	copy(b.Bytes[b.head:b.head+l], v)
346
347	return b.EndVector(len(v))
348}
349
350func (b *Builder) assertNested() {
351	// If you get this assert, you're in an object while trying to write
352	// data that belongs outside of an object.
353	// To fix this, write non-inline data (like vectors) before creating
354	// objects.
355	if !b.nested {
356		panic("Incorrect creation order: must be inside object.")
357	}
358}
359
360func (b *Builder) assertNotNested() {
361	// If you hit this, you're trying to construct a Table/Vector/String
362	// during the construction of its parent table (between the MyTableBuilder
363	// and builder.Finish()).
364	// Move the creation of these sub-objects to above the MyTableBuilder to
365	// not get this assert.
366	// Ignoring this assert may appear to work in simple cases, but the reason
367	// it is here is that storing objects in-line may cause vtable offsets
368	// to not fit anymore. It also leads to vtable duplication.
369	if b.nested {
370		panic("Incorrect creation order: object must not be nested.")
371	}
372}
373
374func (b *Builder) assertFinished() {
375	// If you get this assert, you're attempting to get access a buffer
376	// which hasn't been finished yet. Be sure to call builder.Finish()
377	// with your root table.
378	// If you really need to access an unfinished buffer, use the Bytes
379	// buffer directly.
380	if !b.finished {
381		panic("Incorrect use of FinishedBytes(): must call 'Finish' first.")
382	}
383}
384
385// PrependBoolSlot prepends a bool onto the object at vtable slot `o`.
386// If value `x` equals default `d`, then the slot will be set to zero and no
387// other data will be written.
388func (b *Builder) PrependBoolSlot(o int, x, d bool) {
389	val := byte(0)
390	if x {
391		val = 1
392	}
393	def := byte(0)
394	if d {
395		def = 1
396	}
397	b.PrependByteSlot(o, val, def)
398}
399
400// PrependByteSlot prepends a byte onto the object at vtable slot `o`.
401// If value `x` equals default `d`, then the slot will be set to zero and no
402// other data will be written.
403func (b *Builder) PrependByteSlot(o int, x, d byte) {
404	if x != d {
405		b.PrependByte(x)
406		b.Slot(o)
407	}
408}
409
410// PrependUint8Slot prepends a uint8 onto the object at vtable slot `o`.
411// If value `x` equals default `d`, then the slot will be set to zero and no
412// other data will be written.
413func (b *Builder) PrependUint8Slot(o int, x, d uint8) {
414	if x != d {
415		b.PrependUint8(x)
416		b.Slot(o)
417	}
418}
419
420// PrependUint16Slot prepends a uint16 onto the object at vtable slot `o`.
421// If value `x` equals default `d`, then the slot will be set to zero and no
422// other data will be written.
423func (b *Builder) PrependUint16Slot(o int, x, d uint16) {
424	if x != d {
425		b.PrependUint16(x)
426		b.Slot(o)
427	}
428}
429
430// PrependUint32Slot prepends a uint32 onto the object at vtable slot `o`.
431// If value `x` equals default `d`, then the slot will be set to zero and no
432// other data will be written.
433func (b *Builder) PrependUint32Slot(o int, x, d uint32) {
434	if x != d {
435		b.PrependUint32(x)
436		b.Slot(o)
437	}
438}
439
440// PrependUint64Slot prepends a uint64 onto the object at vtable slot `o`.
441// If value `x` equals default `d`, then the slot will be set to zero and no
442// other data will be written.
443func (b *Builder) PrependUint64Slot(o int, x, d uint64) {
444	if x != d {
445		b.PrependUint64(x)
446		b.Slot(o)
447	}
448}
449
450// PrependInt8Slot prepends a int8 onto the object at vtable slot `o`.
451// If value `x` equals default `d`, then the slot will be set to zero and no
452// other data will be written.
453func (b *Builder) PrependInt8Slot(o int, x, d int8) {
454	if x != d {
455		b.PrependInt8(x)
456		b.Slot(o)
457	}
458}
459
460// PrependInt16Slot prepends a int16 onto the object at vtable slot `o`.
461// If value `x` equals default `d`, then the slot will be set to zero and no
462// other data will be written.
463func (b *Builder) PrependInt16Slot(o int, x, d int16) {
464	if x != d {
465		b.PrependInt16(x)
466		b.Slot(o)
467	}
468}
469
470// PrependInt32Slot prepends a int32 onto the object at vtable slot `o`.
471// If value `x` equals default `d`, then the slot will be set to zero and no
472// other data will be written.
473func (b *Builder) PrependInt32Slot(o int, x, d int32) {
474	if x != d {
475		b.PrependInt32(x)
476		b.Slot(o)
477	}
478}
479
480// PrependInt64Slot prepends a int64 onto the object at vtable slot `o`.
481// If value `x` equals default `d`, then the slot will be set to zero and no
482// other data will be written.
483func (b *Builder) PrependInt64Slot(o int, x, d int64) {
484	if x != d {
485		b.PrependInt64(x)
486		b.Slot(o)
487	}
488}
489
490// PrependFloat32Slot prepends a float32 onto the object at vtable slot `o`.
491// If value `x` equals default `d`, then the slot will be set to zero and no
492// other data will be written.
493func (b *Builder) PrependFloat32Slot(o int, x, d float32) {
494	if x != d {
495		b.PrependFloat32(x)
496		b.Slot(o)
497	}
498}
499
500// PrependFloat64Slot prepends a float64 onto the object at vtable slot `o`.
501// If value `x` equals default `d`, then the slot will be set to zero and no
502// other data will be written.
503func (b *Builder) PrependFloat64Slot(o int, x, d float64) {
504	if x != d {
505		b.PrependFloat64(x)
506		b.Slot(o)
507	}
508}
509
510// PrependUOffsetTSlot prepends an UOffsetT onto the object at vtable slot `o`.
511// If value `x` equals default `d`, then the slot will be set to zero and no
512// other data will be written.
513func (b *Builder) PrependUOffsetTSlot(o int, x, d UOffsetT) {
514	if x != d {
515		b.PrependUOffsetT(x)
516		b.Slot(o)
517	}
518}
519
520// PrependStructSlot prepends a struct onto the object at vtable slot `o`.
521// Structs are stored inline, so nothing additional is being added.
522// In generated code, `d` is always 0.
523func (b *Builder) PrependStructSlot(voffset int, x, d UOffsetT) {
524	if x != d {
525		b.assertNested()
526		if x != b.Offset() {
527			panic("inline data write outside of object")
528		}
529		b.Slot(voffset)
530	}
531}
532
533// Slot sets the vtable key `voffset` to the current location in the buffer.
534func (b *Builder) Slot(slotnum int) {
535	b.vtable[slotnum] = UOffsetT(b.Offset())
536}
537
538// Finish finalizes a buffer, pointing to the given `rootTable`.
539func (b *Builder) Finish(rootTable UOffsetT) {
540	b.assertNotNested()
541	b.Prep(b.minalign, SizeUOffsetT)
542	b.PrependUOffsetT(rootTable)
543	b.finished = true
544}
545
546// vtableEqual compares an unwritten vtable to a written vtable.
547func vtableEqual(a []UOffsetT, objectStart UOffsetT, b []byte) bool {
548	if len(a)*SizeVOffsetT != len(b) {
549		return false
550	}
551
552	for i := 0; i < len(a); i++ {
553		x := GetVOffsetT(b[i*SizeVOffsetT : (i+1)*SizeVOffsetT])
554
555		// Skip vtable entries that indicate a default value.
556		if x == 0 && a[i] == 0 {
557			continue
558		}
559
560		y := SOffsetT(objectStart) - SOffsetT(a[i])
561		if SOffsetT(x) != y {
562			return false
563		}
564	}
565	return true
566}
567
568// PrependBool prepends a bool to the Builder buffer.
569// Aligns and checks for space.
570func (b *Builder) PrependBool(x bool) {
571	b.Prep(SizeBool, 0)
572	b.PlaceBool(x)
573}
574
575// PrependUint8 prepends a uint8 to the Builder buffer.
576// Aligns and checks for space.
577func (b *Builder) PrependUint8(x uint8) {
578	b.Prep(SizeUint8, 0)
579	b.PlaceUint8(x)
580}
581
582// PrependUint16 prepends a uint16 to the Builder buffer.
583// Aligns and checks for space.
584func (b *Builder) PrependUint16(x uint16) {
585	b.Prep(SizeUint16, 0)
586	b.PlaceUint16(x)
587}
588
589// PrependUint32 prepends a uint32 to the Builder buffer.
590// Aligns and checks for space.
591func (b *Builder) PrependUint32(x uint32) {
592	b.Prep(SizeUint32, 0)
593	b.PlaceUint32(x)
594}
595
596// PrependUint64 prepends a uint64 to the Builder buffer.
597// Aligns and checks for space.
598func (b *Builder) PrependUint64(x uint64) {
599	b.Prep(SizeUint64, 0)
600	b.PlaceUint64(x)
601}
602
603// PrependInt8 prepends a int8 to the Builder buffer.
604// Aligns and checks for space.
605func (b *Builder) PrependInt8(x int8) {
606	b.Prep(SizeInt8, 0)
607	b.PlaceInt8(x)
608}
609
610// PrependInt16 prepends a int16 to the Builder buffer.
611// Aligns and checks for space.
612func (b *Builder) PrependInt16(x int16) {
613	b.Prep(SizeInt16, 0)
614	b.PlaceInt16(x)
615}
616
617// PrependInt32 prepends a int32 to the Builder buffer.
618// Aligns and checks for space.
619func (b *Builder) PrependInt32(x int32) {
620	b.Prep(SizeInt32, 0)
621	b.PlaceInt32(x)
622}
623
624// PrependInt64 prepends a int64 to the Builder buffer.
625// Aligns and checks for space.
626func (b *Builder) PrependInt64(x int64) {
627	b.Prep(SizeInt64, 0)
628	b.PlaceInt64(x)
629}
630
631// PrependFloat32 prepends a float32 to the Builder buffer.
632// Aligns and checks for space.
633func (b *Builder) PrependFloat32(x float32) {
634	b.Prep(SizeFloat32, 0)
635	b.PlaceFloat32(x)
636}
637
638// PrependFloat64 prepends a float64 to the Builder buffer.
639// Aligns and checks for space.
640func (b *Builder) PrependFloat64(x float64) {
641	b.Prep(SizeFloat64, 0)
642	b.PlaceFloat64(x)
643}
644
645// PrependByte prepends a byte to the Builder buffer.
646// Aligns and checks for space.
647func (b *Builder) PrependByte(x byte) {
648	b.Prep(SizeByte, 0)
649	b.PlaceByte(x)
650}
651
652// PrependVOffsetT prepends a VOffsetT to the Builder buffer.
653// Aligns and checks for space.
654func (b *Builder) PrependVOffsetT(x VOffsetT) {
655	b.Prep(SizeVOffsetT, 0)
656	b.PlaceVOffsetT(x)
657}
658
659// PlaceBool prepends a bool to the Builder, without checking for space.
660func (b *Builder) PlaceBool(x bool) {
661	b.head -= UOffsetT(SizeBool)
662	WriteBool(b.Bytes[b.head:], x)
663}
664
665// PlaceUint8 prepends a uint8 to the Builder, without checking for space.
666func (b *Builder) PlaceUint8(x uint8) {
667	b.head -= UOffsetT(SizeUint8)
668	WriteUint8(b.Bytes[b.head:], x)
669}
670
671// PlaceUint16 prepends a uint16 to the Builder, without checking for space.
672func (b *Builder) PlaceUint16(x uint16) {
673	b.head -= UOffsetT(SizeUint16)
674	WriteUint16(b.Bytes[b.head:], x)
675}
676
677// PlaceUint32 prepends a uint32 to the Builder, without checking for space.
678func (b *Builder) PlaceUint32(x uint32) {
679	b.head -= UOffsetT(SizeUint32)
680	WriteUint32(b.Bytes[b.head:], x)
681}
682
683// PlaceUint64 prepends a uint64 to the Builder, without checking for space.
684func (b *Builder) PlaceUint64(x uint64) {
685	b.head -= UOffsetT(SizeUint64)
686	WriteUint64(b.Bytes[b.head:], x)
687}
688
689// PlaceInt8 prepends a int8 to the Builder, without checking for space.
690func (b *Builder) PlaceInt8(x int8) {
691	b.head -= UOffsetT(SizeInt8)
692	WriteInt8(b.Bytes[b.head:], x)
693}
694
695// PlaceInt16 prepends a int16 to the Builder, without checking for space.
696func (b *Builder) PlaceInt16(x int16) {
697	b.head -= UOffsetT(SizeInt16)
698	WriteInt16(b.Bytes[b.head:], x)
699}
700
701// PlaceInt32 prepends a int32 to the Builder, without checking for space.
702func (b *Builder) PlaceInt32(x int32) {
703	b.head -= UOffsetT(SizeInt32)
704	WriteInt32(b.Bytes[b.head:], x)
705}
706
707// PlaceInt64 prepends a int64 to the Builder, without checking for space.
708func (b *Builder) PlaceInt64(x int64) {
709	b.head -= UOffsetT(SizeInt64)
710	WriteInt64(b.Bytes[b.head:], x)
711}
712
713// PlaceFloat32 prepends a float32 to the Builder, without checking for space.
714func (b *Builder) PlaceFloat32(x float32) {
715	b.head -= UOffsetT(SizeFloat32)
716	WriteFloat32(b.Bytes[b.head:], x)
717}
718
719// PlaceFloat64 prepends a float64 to the Builder, without checking for space.
720func (b *Builder) PlaceFloat64(x float64) {
721	b.head -= UOffsetT(SizeFloat64)
722	WriteFloat64(b.Bytes[b.head:], x)
723}
724
725// PlaceByte prepends a byte to the Builder, without checking for space.
726func (b *Builder) PlaceByte(x byte) {
727	b.head -= UOffsetT(SizeByte)
728	WriteByte(b.Bytes[b.head:], x)
729}
730
731// PlaceVOffsetT prepends a VOffsetT to the Builder, without checking for space.
732func (b *Builder) PlaceVOffsetT(x VOffsetT) {
733	b.head -= UOffsetT(SizeVOffsetT)
734	WriteVOffsetT(b.Bytes[b.head:], x)
735}
736
737// PlaceSOffsetT prepends a SOffsetT to the Builder, without checking for space.
738func (b *Builder) PlaceSOffsetT(x SOffsetT) {
739	b.head -= UOffsetT(SizeSOffsetT)
740	WriteSOffsetT(b.Bytes[b.head:], x)
741}
742
743// PlaceUOffsetT prepends a UOffsetT to the Builder, without checking for space.
744func (b *Builder) PlaceUOffsetT(x UOffsetT) {
745	b.head -= UOffsetT(SizeUOffsetT)
746	WriteUOffsetT(b.Bytes[b.head:], x)
747}
748