blob: 423620b9faf1e45563d0054cab33dc4c1e02f40c [file] [log] [blame]
rw74d5f372014-07-11 16:12:35 -07001package 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 []byte
10
11 minalign int
12 vtable []UOffsetT
13 objectEnd UOffsetT
14 vtables []UOffsetT
15 head UOffsetT
16}
17
18// NewBuilder initializes a Builder of size `initial_size`.
19// The internal buffer is grown as needed.
20func NewBuilder(initialSize int) *Builder {
21 if initialSize <= 0 {
22 initialSize = 0
23 }
24
25 b := &Builder{}
26 b.Bytes = make([]byte, initialSize)
27 b.head = UOffsetT(initialSize)
28 b.minalign = 1
29 b.vtables = make([]UOffsetT, 0, 16) // sensible default capacity
30
31 return b
32}
33
34// StartObject initializes bookkeeping for writing a new object.
35func (b *Builder) StartObject(numfields int) {
36 b.notNested()
37 // use 32-bit offsets so that arithmetic doesn't overflow.
38 b.vtable = make([]UOffsetT, numfields)
39 b.objectEnd = b.Offset()
40 b.minalign = 1
41}
42
43// WriteVtable serializes the vtable for the current object, if applicable.
44//
45// Before writing out the vtable, this checks pre-existing vtables for equality
46// to this one. If an equal vtable is found, point the object to the existing
47// vtable and return.
48//
49// Because vtable values are sensitive to alignment of object data, not all
50// logically-equal vtables will be deduplicated.
51//
52// A vtable has the following format:
53// <VOffsetT: size of the vtable in bytes, including this value>
54// <VOffsetT: size of the object in bytes, including the vtable offset>
55// <VOffsetT: offset for a field> * N, where N is the number of fields in
56// the schema for this type. Includes deprecated fields.
57// Thus, a vtable is made of 2 + N elements, each SizeVOffsetT bytes wide.
58//
59// An object has the following format:
60// <SOffsetT: offset to this object's vtable (may be negative)>
61// <byte: data>+
62func (b *Builder) WriteVtable() (n UOffsetT) {
63 // Prepend a zero scalar to the object. Later in this function we'll
64 // write an offset here that points to the object's vtable:
65 b.PrependSOffsetT(0)
66
67 objectOffset := b.Offset()
68 existingVtable := UOffsetT(0)
69
70 // Search backwards through existing vtables, because similar vtables
71 // are likely to have been recently appended. See
72 // BenchmarkVtableDeduplication for a case in which this heuristic
73 // saves about 30% of the time used in writing objects with duplicate
74 // tables.
75 for i := len(b.vtables) - 1; i >= 0; i-- {
76 // Find the other vtable, which is associated with `i`:
77 vt2Offset := b.vtables[i]
78 vt2Start := len(b.Bytes) - int(vt2Offset)
79 vt2Len := GetVOffsetT(b.Bytes[vt2Start:])
80
81 metadata := VtableMetadataFields * SizeVOffsetT
82 vt2End := vt2Start + int(vt2Len)
83 vt2 := b.Bytes[vt2Start+metadata : vt2End]
84
85 // Compare the other vtable to the one under consideration.
86 // If they are equal, store the offset and break:
87 if vtableEqual(b.vtable, objectOffset, vt2) {
88 existingVtable = vt2Offset
89 break
90 }
91 }
92
93 if existingVtable == 0 {
94 // Did not find a vtable, so write this one to the buffer.
95
96 // Write out the current vtable in reverse , because
97 // serialization occurs in last-first order:
98 for i := len(b.vtable) - 1; i >= 0; i-- {
99 var off UOffsetT
100 if b.vtable[i] != 0 {
101 // Forward reference to field;
102 // use 32bit number to ensure no overflow:
103 off = objectOffset - b.vtable[i]
104 }
105
106 b.PrependVOffsetT(VOffsetT(off))
107 }
108
109 // The two metadata fields are written last.
110
111 // First, store the object bytesize:
112 objectSize := objectOffset - b.objectEnd
113 b.PrependVOffsetT(VOffsetT(objectSize))
114
115 // Second, store the vtable bytesize:
116 vBytes := (len(b.vtable) + VtableMetadataFields) * SizeVOffsetT
117 b.PrependVOffsetT(VOffsetT(vBytes))
118
119 // Next, write the offset to the new vtable in the
120 // already-allocated SOffsetT at the beginning of this object:
121 objectStart := SOffsetT(len(b.Bytes)) - SOffsetT(objectOffset)
122 WriteSOffsetT(b.Bytes[objectStart:],
123 SOffsetT(b.Offset())-SOffsetT(objectOffset))
124
125 // Finally, store this vtable in memory for future
126 // deduplication:
127 b.vtables = append(b.vtables, b.Offset())
128 } else {
129 // Found a duplicate vtable.
130
131 objectStart := SOffsetT(len(b.Bytes)) - SOffsetT(objectOffset)
132 b.head = UOffsetT(objectStart)
133
134 // Write the offset to the found vtable in the
135 // already-allocated SOffsetT at the beginning of this object:
136 WriteSOffsetT(b.Bytes[b.head:],
137 SOffsetT(existingVtable)-SOffsetT(objectOffset))
138 }
139
140 b.vtable = nil
141 return objectOffset
142}
143
144// EndObject writes data necessary to finish object construction.
145func (b *Builder) EndObject() UOffsetT {
146 if b.vtable == nil {
147 panic("not in object")
148 }
149 return b.WriteVtable()
150}
151
152// Doubles the size of the byteslice, and copies the old data towards the
153// end of the new byteslice (since we build the buffer backwards).
154func (b *Builder) growByteBuffer() {
155 if (len(b.Bytes) & 0xC0000000) != 0 {
156 panic("cannot grow buffer beyond 2 gigabytes")
157 }
158 newSize := len(b.Bytes) * 2
159 if newSize == 0 {
160 newSize = 1
161 }
162 bytes2 := make([]byte, newSize)
163 copy(bytes2[newSize-len(b.Bytes):], b.Bytes)
164 b.Bytes = bytes2
165}
166
167// Head gives the start of useful data in the underlying byte buffer.
168// Note: unlike other functions, this value is interpreted as from the left.
169func (b *Builder) Head() UOffsetT {
170 return b.head
171}
172
173// Offset relative to the end of the buffer.
174func (b *Builder) Offset() UOffsetT {
175 return UOffsetT(len(b.Bytes)) - b.head
176}
177
178// Pad places zeros at the current offset.
179func (b *Builder) Pad(n int) {
180 for i := 0; i < n; i++ {
181 b.PlaceByte(0)
182 }
183}
184
185// Prep prepares to write an element of `size` after `additional_bytes`
186// have been written, e.g. if you write a string, you need to align such
187// the int length field is aligned to SizeInt32, and the string data follows it
188// directly.
189// If all you need to do is align, `additionalBytes` will be 0.
190func (b *Builder) Prep(size, additionalBytes int) {
191 // Track the biggest thing we've ever aligned to.
192 if size > b.minalign {
193 b.minalign = size
194 }
195 // Find the amount of alignment needed such that `size` is properly
196 // aligned after `additionalBytes`:
197 alignSize := (^(len(b.Bytes) - int(b.Head()) + additionalBytes)) + 1
198 alignSize &= (size - 1)
199
200 // Reallocate the buffer if needed:
201 for int(b.head) < alignSize+size+additionalBytes {
202 oldBufSize := len(b.Bytes)
203 b.growByteBuffer()
204 b.head += UOffsetT(len(b.Bytes) - oldBufSize)
205 }
206 b.Pad(alignSize)
207}
208
209// PrependSOffsetT prepends an SOffsetT, relative to where it will be written.
210func (b *Builder) PrependSOffsetT(off SOffsetT) {
211 b.Prep(SizeSOffsetT, 0) // Ensure alignment is already done.
212 if !(UOffsetT(off) <= b.Offset()) {
213 panic("unreachable: off <= b.Offset()")
214 }
215 off2 := SOffsetT(b.Offset()) - off + SOffsetT(SizeSOffsetT)
216 b.PlaceSOffsetT(off2)
217}
218
219// PrependUOffsetT prepends an UOffsetT, relative to where it will be written.
220func (b *Builder) PrependUOffsetT(off UOffsetT) {
221 b.Prep(SizeUOffsetT, 0) // Ensure alignment is already done.
222 if !(off <= b.Offset()) {
223 panic("unreachable: off <= b.Offset()")
224 }
225 off2 := b.Offset() - off + UOffsetT(SizeUOffsetT)
226 b.PlaceUOffsetT(off2)
227}
228
229// StartVector initializes bookkeeping for writing a new vector.
230//
231// A vector has the following format:
232// <UOffsetT: number of elements in this vector>
233// <T: data>+, where T is the type of elements of this vector.
234func (b *Builder) StartVector(elemSize, numElems int) UOffsetT {
235 b.notNested()
236 b.Prep(SizeUint32, elemSize*numElems)
237 return b.Offset()
238}
239
240// EndVector writes data necessary to finish vector construction.
241func (b *Builder) EndVector(vectorNumElems int) UOffsetT {
242 // we already made space for this, so write without PrependUint32
243 b.PlaceUOffsetT(UOffsetT(vectorNumElems))
244 return b.Offset()
245}
246
247// CreateString writes a null-terminated string as a vector.
248func (b *Builder) CreateString(s string) UOffsetT {
249 b.Prep(int(SizeUOffsetT), (len(s)+1)*SizeByte)
250 b.PlaceByte(0)
251
252 x := []byte(s)
253 l := UOffsetT(len(x))
254
255 b.head -= l
256 copy(b.Bytes[b.head:b.head+l], x)
257
258 return b.EndVector(len(x))
259}
260
261func (b *Builder) notNested() {
262 // Check that no other objects are being built while making this
263 // object. If not, panic:
264 if b.vtable != nil {
265 panic("non-inline data write inside of object")
266 }
267}
268
269func (b *Builder) nested(obj UOffsetT) {
270 // Structs are always stored inline, so need to be created right
271 // where they are used. You'll get this panic if you created it
272 // elsewhere:
273 if obj != b.Offset() {
274 panic("inline data write outside of object")
275 }
276}
277
278// PrependBoolSlot prepends a bool onto the object at vtable slot `o`.
279// If value `x` equals default `d`, then the slot will be set to zero and no
280// other data will be written.
281func (b *Builder) PrependBoolSlot(o int, x, d bool) {
282 val := byte(0)
283 if x {
284 val = 1
285 }
286 def := byte(0)
287 if d {
288 def = 1
289 }
290 b.PrependByteSlot(o, val, def)
291}
292
293// PrependByteSlot prepends a byte onto the object at vtable slot `o`.
294// If value `x` equals default `d`, then the slot will be set to zero and no
295// other data will be written.
296func (b *Builder) PrependByteSlot(o int, x, d byte) {
297 if x != d {
298 b.PrependByte(x)
299 b.Slot(o)
300 }
301}
302
303// PrependUint8Slot prepends a uint8 onto the object at vtable slot `o`.
304// If value `x` equals default `d`, then the slot will be set to zero and no
305// other data will be written.
306func (b *Builder) PrependUint8Slot(o int, x, d uint8) {
307 if x != d {
308 b.PrependUint8(x)
309 b.Slot(o)
310 }
311}
312
313// PrependUint16Slot prepends a uint16 onto the object at vtable slot `o`.
314// If value `x` equals default `d`, then the slot will be set to zero and no
315// other data will be written.
316func (b *Builder) PrependUint16Slot(o int, x, d uint16) {
317 if x != d {
318 b.PrependUint16(x)
319 b.Slot(o)
320 }
321}
322
323// PrependUint32Slot prepends a uint32 onto the object at vtable slot `o`.
324// If value `x` equals default `d`, then the slot will be set to zero and no
325// other data will be written.
326func (b *Builder) PrependUint32Slot(o int, x, d uint32) {
327 if x != d {
328 b.PrependUint32(x)
329 b.Slot(o)
330 }
331}
332
333// PrependUint64Slot prepends a uint64 onto the object at vtable slot `o`.
334// If value `x` equals default `d`, then the slot will be set to zero and no
335// other data will be written.
336func (b *Builder) PrependUint64Slot(o int, x, d uint64) {
337 if x != d {
338 b.PrependUint64(x)
339 b.Slot(o)
340 }
341}
342
343// PrependInt8Slot prepends a int8 onto the object at vtable slot `o`.
344// If value `x` equals default `d`, then the slot will be set to zero and no
345// other data will be written.
346func (b *Builder) PrependInt8Slot(o int, x, d int8) {
347 if x != d {
348 b.PrependInt8(x)
349 b.Slot(o)
350 }
351}
352
353// PrependInt16Slot prepends a int16 onto the object at vtable slot `o`.
354// If value `x` equals default `d`, then the slot will be set to zero and no
355// other data will be written.
356func (b *Builder) PrependInt16Slot(o int, x, d int16) {
357 if x != d {
358 b.PrependInt16(x)
359 b.Slot(o)
360 }
361}
362
363// PrependInt32Slot prepends a int32 onto the object at vtable slot `o`.
364// If value `x` equals default `d`, then the slot will be set to zero and no
365// other data will be written.
366func (b *Builder) PrependInt32Slot(o int, x, d int32) {
367 if x != d {
368 b.PrependInt32(x)
369 b.Slot(o)
370 }
371}
372
373// PrependInt64Slot prepends a int64 onto the object at vtable slot `o`.
374// If value `x` equals default `d`, then the slot will be set to zero and no
375// other data will be written.
376func (b *Builder) PrependInt64Slot(o int, x, d int64) {
377 if x != d {
378 b.PrependInt64(x)
379 b.Slot(o)
380 }
381}
382
383// PrependFloat32Slot prepends a float32 onto the object at vtable slot `o`.
384// If value `x` equals default `d`, then the slot will be set to zero and no
385// other data will be written.
386func (b *Builder) PrependFloat32Slot(o int, x, d float32) {
387 if x != d {
388 b.PrependFloat32(x)
389 b.Slot(o)
390 }
391}
392
393// PrependFloat64Slot prepends a float64 onto the object at vtable slot `o`.
394// If value `x` equals default `d`, then the slot will be set to zero and no
395// other data will be written.
396func (b *Builder) PrependFloat64Slot(o int, x, d float64) {
397 if x != d {
398 b.PrependFloat64(x)
399 b.Slot(o)
400 }
401}
402
403// PrependUOffsetTSlot prepends an UOffsetT onto the object at vtable slot `o`.
404// If value `x` equals default `d`, then the slot will be set to zero and no
405// other data will be written.
406func (b *Builder) PrependUOffsetTSlot(o int, x, d UOffsetT) {
407 if x != d {
408 b.PrependUOffsetT(x)
409 b.Slot(o)
410 }
411}
412
413// PrependStructSlot prepends a struct onto the object at vtable slot `o`.
414// Structs are stored inline, so nothing additional is being added.
415// In generated code, `d` is always 0.
416func (b *Builder) PrependStructSlot(voffset int, x, d UOffsetT) {
417 if x != d {
418 b.nested(x)
419 b.Slot(voffset)
420 }
421}
422
423// Slot sets the vtable key `voffset` to the current location in the buffer.
424func (b *Builder) Slot(slotnum int) {
425 b.vtable[slotnum] = UOffsetT(b.Offset())
426}
427
428// Finish finalizes a buffer, pointing to the given `rootTable`.
429func (b *Builder) Finish(rootTable UOffsetT) {
430 b.Prep(b.minalign, SizeUOffsetT)
431 b.PrependUOffsetT(rootTable)
432}
433
434// vtableEqual compares an unwritten vtable to a written vtable.
435func vtableEqual(a []UOffsetT, objectStart UOffsetT, b []byte) bool {
436 if len(a)*SizeVOffsetT != len(b) {
437 return false
438 }
439
440 for i := 0; i < len(a); i++ {
441 x := GetVOffsetT(b[i*SizeVOffsetT : (i+1)*SizeVOffsetT])
442
443 // Skip vtable entries that indicate a default value.
444 if x == 0 && a[i] == 0 {
445 continue
446 }
447
448 y := SOffsetT(objectStart) - SOffsetT(a[i])
449 if SOffsetT(x) != y {
450 return false
451 }
452 }
453 return true
454}
455
456// PrependBool prepends a bool to the Builder buffer.
457// Aligns and checks for space.
458func (b *Builder) PrependBool(x bool) {
459 b.Prep(SizeBool, 0)
460 b.PlaceBool(x)
461}
462
463// PrependUint8 prepends a uint8 to the Builder buffer.
464// Aligns and checks for space.
465func (b *Builder) PrependUint8(x uint8) {
466 b.Prep(SizeUint8, 0)
467 b.PlaceUint8(x)
468}
469
470// PrependUint16 prepends a uint16 to the Builder buffer.
471// Aligns and checks for space.
472func (b *Builder) PrependUint16(x uint16) {
473 b.Prep(SizeUint16, 0)
474 b.PlaceUint16(x)
475}
476
477// PrependUint32 prepends a uint32 to the Builder buffer.
478// Aligns and checks for space.
479func (b *Builder) PrependUint32(x uint32) {
480 b.Prep(SizeUint32, 0)
481 b.PlaceUint32(x)
482}
483
484// PrependUint64 prepends a uint64 to the Builder buffer.
485// Aligns and checks for space.
486func (b *Builder) PrependUint64(x uint64) {
487 b.Prep(SizeUint64, 0)
488 b.PlaceUint64(x)
489}
490
491// PrependInt8 prepends a int8 to the Builder buffer.
492// Aligns and checks for space.
493func (b *Builder) PrependInt8(x int8) {
494 b.Prep(SizeInt8, 0)
495 b.PlaceInt8(x)
496}
497
498// PrependInt16 prepends a int16 to the Builder buffer.
499// Aligns and checks for space.
500func (b *Builder) PrependInt16(x int16) {
501 b.Prep(SizeInt16, 0)
502 b.PlaceInt16(x)
503}
504
505// PrependInt32 prepends a int32 to the Builder buffer.
506// Aligns and checks for space.
507func (b *Builder) PrependInt32(x int32) {
508 b.Prep(SizeInt32, 0)
509 b.PlaceInt32(x)
510}
511
512// PrependInt64 prepends a int64 to the Builder buffer.
513// Aligns and checks for space.
514func (b *Builder) PrependInt64(x int64) {
515 b.Prep(SizeInt64, 0)
516 b.PlaceInt64(x)
517}
518
519// PrependFloat32 prepends a float32 to the Builder buffer.
520// Aligns and checks for space.
521func (b *Builder) PrependFloat32(x float32) {
522 b.Prep(SizeFloat32, 0)
523 b.PlaceFloat32(x)
524}
525
526// PrependFloat64 prepends a float64 to the Builder buffer.
527// Aligns and checks for space.
528func (b *Builder) PrependFloat64(x float64) {
529 b.Prep(SizeFloat64, 0)
530 b.PlaceFloat64(x)
531}
532
533// PrependByte prepends a byte to the Builder buffer.
534// Aligns and checks for space.
535func (b *Builder) PrependByte(x byte) {
536 b.Prep(SizeByte, 0)
537 b.PlaceByte(x)
538}
539
540// PrependVOffsetT prepends a VOffsetT to the Builder buffer.
541// Aligns and checks for space.
542func (b *Builder) PrependVOffsetT(x VOffsetT) {
543 b.Prep(SizeVOffsetT, 0)
544 b.PlaceVOffsetT(x)
545}
546
547// PlaceBool prepends a bool to the Builder, without checking for space.
548func (b *Builder) PlaceBool(x bool) {
549 b.head -= UOffsetT(SizeBool)
550 WriteBool(b.Bytes[b.head:], x)
551}
552
553// PlaceUint8 prepends a uint8 to the Builder, without checking for space.
554func (b *Builder) PlaceUint8(x uint8) {
555 b.head -= UOffsetT(SizeUint8)
556 WriteUint8(b.Bytes[b.head:], x)
557}
558
559// PlaceUint16 prepends a uint16 to the Builder, without checking for space.
560func (b *Builder) PlaceUint16(x uint16) {
561 b.head -= UOffsetT(SizeUint16)
562 WriteUint16(b.Bytes[b.head:], x)
563}
564
565// PlaceUint32 prepends a uint32 to the Builder, without checking for space.
566func (b *Builder) PlaceUint32(x uint32) {
567 b.head -= UOffsetT(SizeUint32)
568 WriteUint32(b.Bytes[b.head:], x)
569}
570
571// PlaceUint64 prepends a uint64 to the Builder, without checking for space.
572func (b *Builder) PlaceUint64(x uint64) {
573 b.head -= UOffsetT(SizeUint64)
574 WriteUint64(b.Bytes[b.head:], x)
575}
576
577// PlaceInt8 prepends a int8 to the Builder, without checking for space.
578func (b *Builder) PlaceInt8(x int8) {
579 b.head -= UOffsetT(SizeInt8)
580 WriteInt8(b.Bytes[b.head:], x)
581}
582
583// PlaceInt16 prepends a int16 to the Builder, without checking for space.
584func (b *Builder) PlaceInt16(x int16) {
585 b.head -= UOffsetT(SizeInt16)
586 WriteInt16(b.Bytes[b.head:], x)
587}
588
589// PlaceInt32 prepends a int32 to the Builder, without checking for space.
590func (b *Builder) PlaceInt32(x int32) {
591 b.head -= UOffsetT(SizeInt32)
592 WriteInt32(b.Bytes[b.head:], x)
593}
594
595// PlaceInt64 prepends a int64 to the Builder, without checking for space.
596func (b *Builder) PlaceInt64(x int64) {
597 b.head -= UOffsetT(SizeInt64)
598 WriteInt64(b.Bytes[b.head:], x)
599}
600
601// PlaceFloat32 prepends a float32 to the Builder, without checking for space.
602func (b *Builder) PlaceFloat32(x float32) {
603 b.head -= UOffsetT(SizeFloat32)
604 WriteFloat32(b.Bytes[b.head:], x)
605}
606
607// PlaceFloat64 prepends a float64 to the Builder, without checking for space.
608func (b *Builder) PlaceFloat64(x float64) {
609 b.head -= UOffsetT(SizeFloat64)
610 WriteFloat64(b.Bytes[b.head:], x)
611}
612
613// PlaceByte prepends a byte to the Builder, without checking for space.
614func (b *Builder) PlaceByte(x byte) {
615 b.head -= UOffsetT(SizeByte)
616 WriteByte(b.Bytes[b.head:], x)
617}
618
619// PlaceVOffsetT prepends a VOffsetT to the Builder, without checking for space.
620func (b *Builder) PlaceVOffsetT(x VOffsetT) {
621 b.head -= UOffsetT(SizeVOffsetT)
622 WriteVOffsetT(b.Bytes[b.head:], x)
623}
624
625// PlaceSOffsetT prepends a SOffsetT to the Builder, without checking for space.
626func (b *Builder) PlaceSOffsetT(x SOffsetT) {
627 b.head -= UOffsetT(SizeSOffsetT)
628 WriteSOffsetT(b.Bytes[b.head:], x)
629}
630
631// PlaceUOffsetT prepends a UOffsetT to the Builder, without checking for space.
632func (b *Builder) PlaceUOffsetT(x UOffsetT) {
633 b.head -= UOffsetT(SizeUOffsetT)
634 WriteUOffsetT(b.Bytes[b.head:], x)
635}