...

Source file src/github.com/google/flatbuffers/go/builder.go

Documentation: github.com/google/flatbuffers/go

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

View as plain text