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