blob: 8d75700ce24d7ca3b52571c7c3e605d9990babde [file] [log] [blame]
Austin Schuhe89fa2d2019-08-14 20:24:23 -07001package 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}