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