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