Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/flatbuffers/builder.py: 27%
331 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-03 07:57 +0000
1# Copyright 2014 Google Inc. All rights reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7# http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
15from . import number_types as N
16from .number_types import (UOffsetTFlags, SOffsetTFlags, VOffsetTFlags)
18from . import encode
19from . import packer
21from . import compat
22from .compat import range_func
23from .compat import memoryview_type
24from .compat import import_numpy, NumpyRequiredForThisFeature
26import warnings
28np = import_numpy()
29## @file
30## @addtogroup flatbuffers_python_api
31## @{
33## @cond FLATBUFFERS_INTERNAL
34class OffsetArithmeticError(RuntimeError):
35 """
36 Error caused by an Offset arithmetic error. Probably caused by bad
37 writing of fields. This is considered an unreachable situation in
38 normal circumstances.
39 """
40 pass
43class IsNotNestedError(RuntimeError):
44 """
45 Error caused by using a Builder to write Object data when not inside
46 an Object.
47 """
48 pass
51class IsNestedError(RuntimeError):
52 """
53 Error caused by using a Builder to begin an Object when an Object is
54 already being built.
55 """
56 pass
59class StructIsNotInlineError(RuntimeError):
60 """
61 Error caused by using a Builder to write a Struct at a location that
62 is not the current Offset.
63 """
64 pass
67class BuilderSizeError(RuntimeError):
68 """
69 Error caused by causing a Builder to exceed the hardcoded limit of 2
70 gigabytes.
71 """
72 pass
74class BuilderNotFinishedError(RuntimeError):
75 """
76 Error caused by not calling `Finish` before calling `Output`.
77 """
78 pass
80class EndVectorLengthMismatched(RuntimeError):
81 """
82 The number of elements passed to EndVector does not match the number
83 specified in StartVector.
84 """
85 pass
88# VtableMetadataFields is the count of metadata fields in each vtable.
89VtableMetadataFields = 2
90## @endcond
92class Builder(object):
93 """ A Builder is used to construct one or more FlatBuffers.
95 Typically, Builder objects will be used from code generated by the `flatc`
96 compiler.
98 A Builder constructs byte buffers in a last-first manner for simplicity and
99 performance during reading.
101 Internally, a Builder is a state machine for creating FlatBuffer objects.
103 It holds the following internal state:
104 - Bytes: an array of bytes.
105 - current_vtable: a list of integers.
106 - vtables: a hash of vtable entries.
108 Attributes:
109 Bytes: The internal `bytearray` for the Builder.
110 finished: A boolean determining if the Builder has been finalized.
111 """
113 ## @cond FLATBUFFERS_INTENRAL
114 __slots__ = ("Bytes", "current_vtable", "head", "minalign", "objectEnd",
115 "vtables", "nested", "forceDefaults", "finished", "vectorNumElems",
116 "sharedStrings")
118 """Maximum buffer size constant, in bytes.
120 Builder will never allow it's buffer grow over this size.
121 Currently equals 2Gb.
122 """
123 MAX_BUFFER_SIZE = 2**31
124 ## @endcond
126 def __init__(self, initialSize=1024):
127 """Initializes a Builder of size `initial_size`.
129 The internal buffer is grown as needed.
130 """
132 if not (0 <= initialSize <= Builder.MAX_BUFFER_SIZE):
133 msg = "flatbuffers: Cannot create Builder larger than 2 gigabytes."
134 raise BuilderSizeError(msg)
136 self.Bytes = bytearray(initialSize)
137 ## @cond FLATBUFFERS_INTERNAL
138 self.current_vtable = None
139 self.head = UOffsetTFlags.py_type(initialSize)
140 self.minalign = 1
141 self.objectEnd = None
142 self.vtables = {}
143 self.nested = False
144 self.forceDefaults = False
145 self.sharedStrings = {}
146 ## @endcond
147 self.finished = False
149 def Output(self):
150 """Return the portion of the buffer that has been used for writing data.
152 This is the typical way to access the FlatBuffer data inside the
153 builder. If you try to access `Builder.Bytes` directly, you would need
154 to manually index it with `Head()`, since the buffer is constructed
155 backwards.
157 It raises BuilderNotFinishedError if the buffer has not been finished
158 with `Finish`.
159 """
161 if not self.finished:
162 raise BuilderNotFinishedError()
164 return self.Bytes[self.Head():]
166 ## @cond FLATBUFFERS_INTERNAL
167 def StartObject(self, numfields):
168 """StartObject initializes bookkeeping for writing a new object."""
170 self.assertNotNested()
172 # use 32-bit offsets so that arithmetic doesn't overflow.
173 self.current_vtable = [0 for _ in range_func(numfields)]
174 self.objectEnd = self.Offset()
175 self.nested = True
177 def WriteVtable(self):
178 """
179 WriteVtable serializes the vtable for the current object, if needed.
181 Before writing out the vtable, this checks pre-existing vtables for
182 equality to this one. If an equal vtable is found, point the object to
183 the existing vtable and return.
185 Because vtable values are sensitive to alignment of object data, not
186 all logically-equal vtables will be deduplicated.
188 A vtable has the following format:
189 <VOffsetT: size of the vtable in bytes, including this value>
190 <VOffsetT: size of the object in bytes, including the vtable offset>
191 <VOffsetT: offset for a field> * N, where N is the number of fields
192 in the schema for this type. Includes deprecated fields.
193 Thus, a vtable is made of 2 + N elements, each VOffsetT bytes wide.
195 An object has the following format:
196 <SOffsetT: offset to this object's vtable (may be negative)>
197 <byte: data>+
198 """
200 # Prepend a zero scalar to the object. Later in this function we'll
201 # write an offset here that points to the object's vtable:
202 self.PrependSOffsetTRelative(0)
204 objectOffset = self.Offset()
206 vtKey = []
207 trim = True
208 for elem in reversed(self.current_vtable):
209 if elem == 0:
210 if trim:
211 continue
212 else:
213 elem = objectOffset - elem
214 trim = False
216 vtKey.append(elem)
218 vtKey = tuple(vtKey)
219 vt2Offset = self.vtables.get(vtKey)
220 if vt2Offset is None:
221 # Did not find a vtable, so write this one to the buffer.
223 # Write out the current vtable in reverse , because
224 # serialization occurs in last-first order:
225 i = len(self.current_vtable) - 1
226 trailing = 0
227 trim = True
228 while i >= 0:
229 off = 0
230 elem = self.current_vtable[i]
231 i -= 1
233 if elem == 0:
234 if trim:
235 trailing += 1
236 continue
237 else:
238 # Forward reference to field;
239 # use 32bit number to ensure no overflow:
240 off = objectOffset - elem
241 trim = False
243 self.PrependVOffsetT(off)
245 # The two metadata fields are written last.
247 # First, store the object bytesize:
248 objectSize = UOffsetTFlags.py_type(objectOffset - self.objectEnd)
249 self.PrependVOffsetT(VOffsetTFlags.py_type(objectSize))
251 # Second, store the vtable bytesize:
252 vBytes = len(self.current_vtable) - trailing + VtableMetadataFields
253 vBytes *= N.VOffsetTFlags.bytewidth
254 self.PrependVOffsetT(VOffsetTFlags.py_type(vBytes))
256 # Next, write the offset to the new vtable in the
257 # already-allocated SOffsetT at the beginning of this object:
258 objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset)
259 encode.Write(packer.soffset, self.Bytes, objectStart,
260 SOffsetTFlags.py_type(self.Offset() - objectOffset))
262 # Finally, store this vtable in memory for future
263 # deduplication:
264 self.vtables[vtKey] = self.Offset()
265 else:
266 # Found a duplicate vtable.
267 objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset)
268 self.head = UOffsetTFlags.py_type(objectStart)
270 # Write the offset to the found vtable in the
271 # already-allocated SOffsetT at the beginning of this object:
272 encode.Write(packer.soffset, self.Bytes, self.Head(),
273 SOffsetTFlags.py_type(vt2Offset - objectOffset))
275 self.current_vtable = None
276 return objectOffset
278 def EndObject(self):
279 """EndObject writes data necessary to finish object construction."""
280 self.assertNested()
281 self.nested = False
282 return self.WriteVtable()
284 def growByteBuffer(self):
285 """Doubles the size of the byteslice, and copies the old data towards
286 the end of the new buffer (since we build the buffer backwards)."""
287 if len(self.Bytes) == Builder.MAX_BUFFER_SIZE:
288 msg = "flatbuffers: cannot grow buffer beyond 2 gigabytes"
289 raise BuilderSizeError(msg)
291 newSize = min(len(self.Bytes) * 2, Builder.MAX_BUFFER_SIZE)
292 if newSize == 0:
293 newSize = 1
294 bytes2 = bytearray(newSize)
295 bytes2[newSize-len(self.Bytes):] = self.Bytes
296 self.Bytes = bytes2
297 ## @endcond
299 def Head(self):
300 """Get the start of useful data in the underlying byte buffer.
302 Note: unlike other functions, this value is interpreted as from the
303 left.
304 """
305 ## @cond FLATBUFFERS_INTERNAL
306 return self.head
307 ## @endcond
309 ## @cond FLATBUFFERS_INTERNAL
310 def Offset(self):
311 """Offset relative to the end of the buffer."""
312 return UOffsetTFlags.py_type(len(self.Bytes) - self.Head())
314 def Pad(self, n):
315 """Pad places zeros at the current offset."""
316 for i in range_func(n):
317 self.Place(0, N.Uint8Flags)
319 def Prep(self, size, additionalBytes):
320 """
321 Prep prepares to write an element of `size` after `additional_bytes`
322 have been written, e.g. if you write a string, you need to align
323 such the int length field is aligned to SizeInt32, and the string
324 data follows it directly.
325 If all you need to do is align, `additionalBytes` will be 0.
326 """
328 # Track the biggest thing we've ever aligned to.
329 if size > self.minalign:
330 self.minalign = size
332 # Find the amount of alignment needed such that `size` is properly
333 # aligned after `additionalBytes`:
334 alignSize = (~(len(self.Bytes) - self.Head() + additionalBytes)) + 1
335 alignSize &= (size - 1)
337 # Reallocate the buffer if needed:
338 while self.Head() < alignSize+size+additionalBytes:
339 oldBufSize = len(self.Bytes)
340 self.growByteBuffer()
341 updated_head = self.head + len(self.Bytes) - oldBufSize
342 self.head = UOffsetTFlags.py_type(updated_head)
343 self.Pad(alignSize)
345 def PrependSOffsetTRelative(self, off):
346 """
347 PrependSOffsetTRelative prepends an SOffsetT, relative to where it
348 will be written.
349 """
351 # Ensure alignment is already done:
352 self.Prep(N.SOffsetTFlags.bytewidth, 0)
353 if not (off <= self.Offset()):
354 msg = "flatbuffers: Offset arithmetic error."
355 raise OffsetArithmeticError(msg)
356 off2 = self.Offset() - off + N.SOffsetTFlags.bytewidth
357 self.PlaceSOffsetT(off2)
358 ## @endcond
360 def PrependUOffsetTRelative(self, off):
361 """Prepends an unsigned offset into vector data, relative to where it
362 will be written.
363 """
365 # Ensure alignment is already done:
366 self.Prep(N.UOffsetTFlags.bytewidth, 0)
367 if not (off <= self.Offset()):
368 msg = "flatbuffers: Offset arithmetic error."
369 raise OffsetArithmeticError(msg)
370 off2 = self.Offset() - off + N.UOffsetTFlags.bytewidth
371 self.PlaceUOffsetT(off2)
373 ## @cond FLATBUFFERS_INTERNAL
374 def StartVector(self, elemSize, numElems, alignment):
375 """
376 StartVector initializes bookkeeping for writing a new vector.
378 A vector has the following format:
379 - <UOffsetT: number of elements in this vector>
380 - <T: data>+, where T is the type of elements of this vector.
381 """
383 self.assertNotNested()
384 self.nested = True
385 self.vectorNumElems = numElems
386 self.Prep(N.Uint32Flags.bytewidth, elemSize*numElems)
387 self.Prep(alignment, elemSize*numElems) # In case alignment > int.
388 return self.Offset()
389 ## @endcond
391 def EndVector(self, numElems = None):
392 """EndVector writes data necessary to finish vector construction."""
394 self.assertNested()
395 ## @cond FLATBUFFERS_INTERNAL
396 self.nested = False
397 ## @endcond
399 if numElems:
400 warnings.warn("numElems is deprecated.",
401 DeprecationWarning, stacklevel=2)
402 if numElems != self.vectorNumElems:
403 raise EndVectorLengthMismatched();
405 # we already made space for this, so write without PrependUint32
406 self.PlaceUOffsetT(self.vectorNumElems)
407 self.vectorNumElems = None
408 return self.Offset()
410 def CreateSharedString(self, s, encoding='utf-8', errors='strict'):
411 """
412 CreateSharedString checks if the string is already written to the buffer
413 before calling CreateString.
414 """
416 if s in self.sharedStrings:
417 return self.sharedStrings[s]
419 off = self.CreateString(s, encoding, errors)
420 self.sharedStrings[s] = off
422 return off
424 def CreateString(self, s, encoding='utf-8', errors='strict'):
425 """CreateString writes a null-terminated byte string as a vector."""
427 self.assertNotNested()
428 ## @cond FLATBUFFERS_INTERNAL
429 self.nested = True
430 ## @endcond
432 if isinstance(s, compat.string_types):
433 x = s.encode(encoding, errors)
434 elif isinstance(s, compat.binary_types):
435 x = s
436 else:
437 raise TypeError("non-string passed to CreateString")
439 self.Prep(N.UOffsetTFlags.bytewidth, (len(x)+1)*N.Uint8Flags.bytewidth)
440 self.Place(0, N.Uint8Flags)
442 l = UOffsetTFlags.py_type(len(s))
443 ## @cond FLATBUFFERS_INTERNAL
444 self.head = UOffsetTFlags.py_type(self.Head() - l)
445 ## @endcond
446 self.Bytes[self.Head():self.Head()+l] = x
448 self.vectorNumElems = len(x)
449 return self.EndVector()
451 def CreateByteVector(self, x):
452 """CreateString writes a byte vector."""
454 self.assertNotNested()
455 ## @cond FLATBUFFERS_INTERNAL
456 self.nested = True
457 ## @endcond
459 if not isinstance(x, compat.binary_types):
460 raise TypeError("non-byte vector passed to CreateByteVector")
462 self.Prep(N.UOffsetTFlags.bytewidth, len(x)*N.Uint8Flags.bytewidth)
464 l = UOffsetTFlags.py_type(len(x))
465 ## @cond FLATBUFFERS_INTERNAL
466 self.head = UOffsetTFlags.py_type(self.Head() - l)
467 ## @endcond
468 self.Bytes[self.Head():self.Head()+l] = x
470 self.vectorNumElems = len(x)
471 return self.EndVector()
473 def CreateNumpyVector(self, x):
474 """CreateNumpyVector writes a numpy array into the buffer."""
476 if np is None:
477 # Numpy is required for this feature
478 raise NumpyRequiredForThisFeature("Numpy was not found.")
480 if not isinstance(x, np.ndarray):
481 raise TypeError("non-numpy-ndarray passed to CreateNumpyVector")
483 if x.dtype.kind not in ['b', 'i', 'u', 'f']:
484 raise TypeError("numpy-ndarray holds elements of unsupported datatype")
486 if x.ndim > 1:
487 raise TypeError("multidimensional-ndarray passed to CreateNumpyVector")
489 self.StartVector(x.itemsize, x.size, x.dtype.alignment)
491 # Ensure little endian byte ordering
492 if x.dtype.str[0] == "<":
493 x_lend = x
494 else:
495 x_lend = x.byteswap(inplace=False)
497 # Calculate total length
498 l = UOffsetTFlags.py_type(x_lend.itemsize * x_lend.size)
499 ## @cond FLATBUFFERS_INTERNAL
500 self.head = UOffsetTFlags.py_type(self.Head() - l)
501 ## @endcond
503 # tobytes ensures c_contiguous ordering
504 self.Bytes[self.Head():self.Head()+l] = x_lend.tobytes(order='C')
506 self.vectorNumElems = x.size
507 return self.EndVector()
509 ## @cond FLATBUFFERS_INTERNAL
510 def assertNested(self):
511 """
512 Check that we are in the process of building an object.
513 """
515 if not self.nested:
516 raise IsNotNestedError()
518 def assertNotNested(self):
519 """
520 Check that no other objects are being built while making this
521 object. If not, raise an exception.
522 """
524 if self.nested:
525 raise IsNestedError()
527 def assertStructIsInline(self, obj):
528 """
529 Structs are always stored inline, so need to be created right
530 where they are used. You'll get this error if you created it
531 elsewhere.
532 """
534 N.enforce_number(obj, N.UOffsetTFlags)
535 if obj != self.Offset():
536 msg = ("flatbuffers: Tried to write a Struct at an Offset that "
537 "is different from the current Offset of the Builder.")
538 raise StructIsNotInlineError(msg)
540 def Slot(self, slotnum):
541 """
542 Slot sets the vtable key `voffset` to the current location in the
543 buffer.
545 """
546 self.assertNested()
547 self.current_vtable[slotnum] = self.Offset()
548 ## @endcond
550 def __Finish(self, rootTable, sizePrefix, file_identifier=None):
551 """Finish finalizes a buffer, pointing to the given `rootTable`."""
552 N.enforce_number(rootTable, N.UOffsetTFlags)
554 prepSize = N.UOffsetTFlags.bytewidth
555 if file_identifier is not None:
556 prepSize += N.Int32Flags.bytewidth
557 if sizePrefix:
558 prepSize += N.Int32Flags.bytewidth
559 self.Prep(self.minalign, prepSize)
561 if file_identifier is not None:
562 self.Prep(N.UOffsetTFlags.bytewidth, encode.FILE_IDENTIFIER_LENGTH)
564 # Convert bytes object file_identifier to an array of 4 8-bit integers,
565 # and use big-endian to enforce size compliance.
566 # https://docs.python.org/2/library/struct.html#format-characters
567 file_identifier = N.struct.unpack(">BBBB", file_identifier)
568 for i in range(encode.FILE_IDENTIFIER_LENGTH-1, -1, -1):
569 # Place the bytes of the file_identifer in reverse order:
570 self.Place(file_identifier[i], N.Uint8Flags)
572 self.PrependUOffsetTRelative(rootTable)
573 if sizePrefix:
574 size = len(self.Bytes) - self.Head()
575 N.enforce_number(size, N.Int32Flags)
576 self.PrependInt32(size)
577 self.finished = True
578 return self.Head()
580 def Finish(self, rootTable, file_identifier=None):
581 """Finish finalizes a buffer, pointing to the given `rootTable`."""
582 return self.__Finish(rootTable, False, file_identifier=file_identifier)
584 def FinishSizePrefixed(self, rootTable, file_identifier=None):
585 """
586 Finish finalizes a buffer, pointing to the given `rootTable`,
587 with the size prefixed.
588 """
589 return self.__Finish(rootTable, True, file_identifier=file_identifier)
591 ## @cond FLATBUFFERS_INTERNAL
592 def Prepend(self, flags, off):
593 self.Prep(flags.bytewidth, 0)
594 self.Place(off, flags)
596 def PrependSlot(self, flags, o, x, d):
597 if x is not None:
598 N.enforce_number(x, flags)
599 if d is not None:
600 N.enforce_number(d, flags)
601 if x != d or (self.forceDefaults and d is not None):
602 self.Prepend(flags, x)
603 self.Slot(o)
605 def PrependBoolSlot(self, *args): self.PrependSlot(N.BoolFlags, *args)
607 def PrependByteSlot(self, *args): self.PrependSlot(N.Uint8Flags, *args)
609 def PrependUint8Slot(self, *args): self.PrependSlot(N.Uint8Flags, *args)
611 def PrependUint16Slot(self, *args): self.PrependSlot(N.Uint16Flags, *args)
613 def PrependUint32Slot(self, *args): self.PrependSlot(N.Uint32Flags, *args)
615 def PrependUint64Slot(self, *args): self.PrependSlot(N.Uint64Flags, *args)
617 def PrependInt8Slot(self, *args): self.PrependSlot(N.Int8Flags, *args)
619 def PrependInt16Slot(self, *args): self.PrependSlot(N.Int16Flags, *args)
621 def PrependInt32Slot(self, *args): self.PrependSlot(N.Int32Flags, *args)
623 def PrependInt64Slot(self, *args): self.PrependSlot(N.Int64Flags, *args)
625 def PrependFloat32Slot(self, *args): self.PrependSlot(N.Float32Flags,
626 *args)
628 def PrependFloat64Slot(self, *args): self.PrependSlot(N.Float64Flags,
629 *args)
631 def PrependUOffsetTRelativeSlot(self, o, x, d):
632 """
633 PrependUOffsetTRelativeSlot prepends an UOffsetT onto the object at
634 vtable slot `o`. If value `x` equals default `d`, then the slot will
635 be set to zero and no other data will be written.
636 """
638 if x != d or self.forceDefaults:
639 self.PrependUOffsetTRelative(x)
640 self.Slot(o)
642 def PrependStructSlot(self, v, x, d):
643 """
644 PrependStructSlot prepends a struct onto the object at vtable slot `o`.
645 Structs are stored inline, so nothing additional is being added.
646 In generated code, `d` is always 0.
647 """
649 N.enforce_number(d, N.UOffsetTFlags)
650 if x != d:
651 self.assertStructIsInline(x)
652 self.Slot(v)
654 ## @endcond
656 def PrependBool(self, x):
657 """Prepend a `bool` to the Builder buffer.
659 Note: aligns and checks for space.
660 """
661 self.Prepend(N.BoolFlags, x)
663 def PrependByte(self, x):
664 """Prepend a `byte` to the Builder buffer.
666 Note: aligns and checks for space.
667 """
668 self.Prepend(N.Uint8Flags, x)
670 def PrependUint8(self, x):
671 """Prepend an `uint8` to the Builder buffer.
673 Note: aligns and checks for space.
674 """
675 self.Prepend(N.Uint8Flags, x)
677 def PrependUint16(self, x):
678 """Prepend an `uint16` to the Builder buffer.
680 Note: aligns and checks for space.
681 """
682 self.Prepend(N.Uint16Flags, x)
684 def PrependUint32(self, x):
685 """Prepend an `uint32` to the Builder buffer.
687 Note: aligns and checks for space.
688 """
689 self.Prepend(N.Uint32Flags, x)
691 def PrependUint64(self, x):
692 """Prepend an `uint64` to the Builder buffer.
694 Note: aligns and checks for space.
695 """
696 self.Prepend(N.Uint64Flags, x)
698 def PrependInt8(self, x):
699 """Prepend an `int8` to the Builder buffer.
701 Note: aligns and checks for space.
702 """
703 self.Prepend(N.Int8Flags, x)
705 def PrependInt16(self, x):
706 """Prepend an `int16` to the Builder buffer.
708 Note: aligns and checks for space.
709 """
710 self.Prepend(N.Int16Flags, x)
712 def PrependInt32(self, x):
713 """Prepend an `int32` to the Builder buffer.
715 Note: aligns and checks for space.
716 """
717 self.Prepend(N.Int32Flags, x)
719 def PrependInt64(self, x):
720 """Prepend an `int64` to the Builder buffer.
722 Note: aligns and checks for space.
723 """
724 self.Prepend(N.Int64Flags, x)
726 def PrependFloat32(self, x):
727 """Prepend a `float32` to the Builder buffer.
729 Note: aligns and checks for space.
730 """
731 self.Prepend(N.Float32Flags, x)
733 def PrependFloat64(self, x):
734 """Prepend a `float64` to the Builder buffer.
736 Note: aligns and checks for space.
737 """
738 self.Prepend(N.Float64Flags, x)
740 def ForceDefaults(self, forceDefaults):
741 """
742 In order to save space, fields that are set to their default value
743 don't get serialized into the buffer. Forcing defaults provides a
744 way to manually disable this optimization. When set to `True`, will
745 always serialize default values.
746 """
747 self.forceDefaults = forceDefaults
749##############################################################
751 ## @cond FLATBUFFERS_INTERNAL
752 def PrependVOffsetT(self, x): self.Prepend(N.VOffsetTFlags, x)
754 def Place(self, x, flags):
755 """
756 Place prepends a value specified by `flags` to the Builder,
757 without checking for available space.
758 """
760 N.enforce_number(x, flags)
761 self.head = self.head - flags.bytewidth
762 encode.Write(flags.packer_type, self.Bytes, self.Head(), x)
764 def PlaceVOffsetT(self, x):
765 """PlaceVOffsetT prepends a VOffsetT to the Builder, without checking
766 for space.
767 """
768 N.enforce_number(x, N.VOffsetTFlags)
769 self.head = self.head - N.VOffsetTFlags.bytewidth
770 encode.Write(packer.voffset, self.Bytes, self.Head(), x)
772 def PlaceSOffsetT(self, x):
773 """PlaceSOffsetT prepends a SOffsetT to the Builder, without checking
774 for space.
775 """
776 N.enforce_number(x, N.SOffsetTFlags)
777 self.head = self.head - N.SOffsetTFlags.bytewidth
778 encode.Write(packer.soffset, self.Bytes, self.Head(), x)
780 def PlaceUOffsetT(self, x):
781 """PlaceUOffsetT prepends a UOffsetT to the Builder, without checking
782 for space.
783 """
784 N.enforce_number(x, N.UOffsetTFlags)
785 self.head = self.head - N.UOffsetTFlags.bytewidth
786 encode.Write(packer.uoffset, self.Bytes, self.Head(), x)
787 ## @endcond
789## @cond FLATBUFFERS_INTERNAL
790def vtableEqual(a, objectStart, b):
791 """vtableEqual compares an unwritten vtable to a written vtable."""
793 N.enforce_number(objectStart, N.UOffsetTFlags)
795 if len(a) * N.VOffsetTFlags.bytewidth != len(b):
796 return False
798 for i, elem in enumerate(a):
799 x = encode.Get(packer.voffset, b, i * N.VOffsetTFlags.bytewidth)
801 # Skip vtable entries that indicate a default value.
802 if x == 0 and elem == 0:
803 pass
804 else:
805 y = objectStart - elem
806 if x != y:
807 return False
808 return True
809## @endcond
810## @}