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