builder.go raw

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