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