| # Copyright 2014 Google Inc. All rights reserved. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| from . import number_types as N |
| from .number_types import (UOffsetTFlags, SOffsetTFlags, VOffsetTFlags) |
| |
| from . import encode |
| from . import packer |
| |
| from . import compat |
| from .compat import range_func |
| from .compat import memoryview_type |
| from .compat import import_numpy, NumpyRequiredForThisFeature |
| |
| np = import_numpy() |
| ## @file |
| ## @addtogroup flatbuffers_python_api |
| ## @{ |
| |
| ## @cond FLATBUFFERS_INTERNAL |
| class OffsetArithmeticError(RuntimeError): |
| """ |
| Error caused by an Offset arithmetic error. Probably caused by bad |
| writing of fields. This is considered an unreachable situation in |
| normal circumstances. |
| """ |
| pass |
| |
| |
| class IsNotNestedError(RuntimeError): |
| """ |
| Error caused by using a Builder to write Object data when not inside |
| an Object. |
| """ |
| pass |
| |
| |
| class IsNestedError(RuntimeError): |
| """ |
| Error caused by using a Builder to begin an Object when an Object is |
| already being built. |
| """ |
| pass |
| |
| |
| class StructIsNotInlineError(RuntimeError): |
| """ |
| Error caused by using a Builder to write a Struct at a location that |
| is not the current Offset. |
| """ |
| pass |
| |
| |
| class BuilderSizeError(RuntimeError): |
| """ |
| Error caused by causing a Builder to exceed the hardcoded limit of 2 |
| gigabytes. |
| """ |
| pass |
| |
| class BuilderNotFinishedError(RuntimeError): |
| """ |
| Error caused by not calling `Finish` before calling `Output`. |
| """ |
| pass |
| |
| |
| # VtableMetadataFields is the count of metadata fields in each vtable. |
| VtableMetadataFields = 2 |
| ## @endcond |
| |
| class Builder(object): |
| """ A Builder is used to construct one or more FlatBuffers. |
| |
| Typically, Builder objects will be used from code generated by the `flatc` |
| compiler. |
| |
| A Builder constructs byte buffers in a last-first manner for simplicity and |
| performance during reading. |
| |
| Internally, a Builder is a state machine for creating FlatBuffer objects. |
| |
| It holds the following internal state: |
| - Bytes: an array of bytes. |
| - current_vtable: a list of integers. |
| - vtables: a hash of vtable entries. |
| |
| Attributes: |
| Bytes: The internal `bytearray` for the Builder. |
| finished: A boolean determining if the Builder has been finalized. |
| """ |
| |
| ## @cond FLATBUFFERS_INTENRAL |
| __slots__ = ("Bytes", "current_vtable", "head", "minalign", "objectEnd", |
| "vtables", "nested", "finished") |
| |
| """Maximum buffer size constant, in bytes. |
| |
| Builder will never allow it's buffer grow over this size. |
| Currently equals 2Gb. |
| """ |
| MAX_BUFFER_SIZE = 2**31 |
| ## @endcond |
| |
| def __init__(self, initialSize): |
| """Initializes a Builder of size `initial_size`. |
| |
| The internal buffer is grown as needed. |
| """ |
| |
| if not (0 <= initialSize <= Builder.MAX_BUFFER_SIZE): |
| msg = "flatbuffers: Cannot create Builder larger than 2 gigabytes." |
| raise BuilderSizeError(msg) |
| |
| self.Bytes = bytearray(initialSize) |
| ## @cond FLATBUFFERS_INTERNAL |
| self.current_vtable = None |
| self.head = UOffsetTFlags.py_type(initialSize) |
| self.minalign = 1 |
| self.objectEnd = None |
| self.vtables = {} |
| self.nested = False |
| ## @endcond |
| self.finished = False |
| |
| |
| def Output(self): |
| """Return the portion of the buffer that has been used for writing data. |
| |
| This is the typical way to access the FlatBuffer data inside the |
| builder. If you try to access `Builder.Bytes` directly, you would need |
| to manually index it with `Head()`, since the buffer is constructed |
| backwards. |
| |
| It raises BuilderNotFinishedError if the buffer has not been finished |
| with `Finish`. |
| """ |
| |
| if not self.finished: |
| raise BuilderNotFinishedError() |
| |
| return self.Bytes[self.Head():] |
| |
| ## @cond FLATBUFFERS_INTERNAL |
| def StartObject(self, numfields): |
| """StartObject initializes bookkeeping for writing a new object.""" |
| |
| self.assertNotNested() |
| |
| # use 32-bit offsets so that arithmetic doesn't overflow. |
| self.current_vtable = [0 for _ in range_func(numfields)] |
| self.objectEnd = self.Offset() |
| self.nested = True |
| |
| def WriteVtable(self): |
| """ |
| WriteVtable serializes the vtable for the current object, if needed. |
| |
| Before writing out the vtable, this checks pre-existing vtables for |
| equality to this one. If an equal vtable is found, point the object to |
| the existing vtable and return. |
| |
| Because vtable values are sensitive to alignment of object data, not |
| all logically-equal vtables will be deduplicated. |
| |
| A vtable has the following format: |
| <VOffsetT: size of the vtable in bytes, including this value> |
| <VOffsetT: size of the object in bytes, including the vtable offset> |
| <VOffsetT: offset for a field> * N, where N is the number of fields |
| in the schema for this type. Includes deprecated fields. |
| Thus, a vtable is made of 2 + N elements, each VOffsetT bytes wide. |
| |
| An object has the following format: |
| <SOffsetT: offset to this object's vtable (may be negative)> |
| <byte: data>+ |
| """ |
| |
| # Prepend a zero scalar to the object. Later in this function we'll |
| # write an offset here that points to the object's vtable: |
| self.PrependSOffsetTRelative(0) |
| |
| objectOffset = self.Offset() |
| |
| vtKey = [] |
| trim = True |
| for elem in reversed(self.current_vtable): |
| if elem == 0: |
| if trim: |
| continue |
| else: |
| elem = objectOffset - elem |
| trim = False |
| |
| vtKey.append(elem) |
| |
| vtKey = tuple(vtKey) |
| vt2Offset = self.vtables.get(vtKey) |
| if vt2Offset is None: |
| # Did not find a vtable, so write this one to the buffer. |
| |
| # Write out the current vtable in reverse , because |
| # serialization occurs in last-first order: |
| i = len(self.current_vtable) - 1 |
| trailing = 0 |
| trim = True |
| while i >= 0: |
| off = 0 |
| elem = self.current_vtable[i] |
| i -= 1 |
| |
| if elem == 0: |
| if trim: |
| trailing += 1 |
| continue |
| else: |
| # Forward reference to field; |
| # use 32bit number to ensure no overflow: |
| off = objectOffset - elem |
| trim = False |
| |
| self.PrependVOffsetT(off) |
| |
| # The two metadata fields are written last. |
| |
| # First, store the object bytesize: |
| objectSize = UOffsetTFlags.py_type(objectOffset - self.objectEnd) |
| self.PrependVOffsetT(VOffsetTFlags.py_type(objectSize)) |
| |
| # Second, store the vtable bytesize: |
| vBytes = len(self.current_vtable) - trailing + VtableMetadataFields |
| vBytes *= N.VOffsetTFlags.bytewidth |
| self.PrependVOffsetT(VOffsetTFlags.py_type(vBytes)) |
| |
| # Next, write the offset to the new vtable in the |
| # already-allocated SOffsetT at the beginning of this object: |
| objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset) |
| encode.Write(packer.soffset, self.Bytes, objectStart, |
| SOffsetTFlags.py_type(self.Offset() - objectOffset)) |
| |
| # Finally, store this vtable in memory for future |
| # deduplication: |
| self.vtables[vtKey] = self.Offset() |
| else: |
| # Found a duplicate vtable. |
| objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset) |
| self.head = UOffsetTFlags.py_type(objectStart) |
| |
| # Write the offset to the found vtable in the |
| # already-allocated SOffsetT at the beginning of this object: |
| encode.Write(packer.soffset, self.Bytes, self.Head(), |
| SOffsetTFlags.py_type(vt2Offset - objectOffset)) |
| |
| self.current_vtable = None |
| return objectOffset |
| |
| def EndObject(self): |
| """EndObject writes data necessary to finish object construction.""" |
| self.assertNested() |
| self.nested = False |
| return self.WriteVtable() |
| |
| def growByteBuffer(self): |
| """Doubles the size of the byteslice, and copies the old data towards |
| the end of the new buffer (since we build the buffer backwards).""" |
| if len(self.Bytes) == Builder.MAX_BUFFER_SIZE: |
| msg = "flatbuffers: cannot grow buffer beyond 2 gigabytes" |
| raise BuilderSizeError(msg) |
| |
| newSize = min(len(self.Bytes) * 2, Builder.MAX_BUFFER_SIZE) |
| if newSize == 0: |
| newSize = 1 |
| bytes2 = bytearray(newSize) |
| bytes2[newSize-len(self.Bytes):] = self.Bytes |
| self.Bytes = bytes2 |
| ## @endcond |
| |
| def Head(self): |
| """Get the start of useful data in the underlying byte buffer. |
| |
| Note: unlike other functions, this value is interpreted as from the |
| left. |
| """ |
| ## @cond FLATBUFFERS_INTERNAL |
| return self.head |
| ## @endcond |
| |
| ## @cond FLATBUFFERS_INTERNAL |
| def Offset(self): |
| """Offset relative to the end of the buffer.""" |
| return UOffsetTFlags.py_type(len(self.Bytes) - self.Head()) |
| |
| def Pad(self, n): |
| """Pad places zeros at the current offset.""" |
| for i in range_func(n): |
| self.Place(0, N.Uint8Flags) |
| |
| def Prep(self, size, additionalBytes): |
| """ |
| Prep prepares to write an element of `size` after `additional_bytes` |
| have been written, e.g. if you write a string, you need to align |
| such the int length field is aligned to SizeInt32, and the string |
| data follows it directly. |
| If all you need to do is align, `additionalBytes` will be 0. |
| """ |
| |
| # Track the biggest thing we've ever aligned to. |
| if size > self.minalign: |
| self.minalign = size |
| |
| # Find the amount of alignment needed such that `size` is properly |
| # aligned after `additionalBytes`: |
| alignSize = (~(len(self.Bytes) - self.Head() + additionalBytes)) + 1 |
| alignSize &= (size - 1) |
| |
| # Reallocate the buffer if needed: |
| while self.Head() < alignSize+size+additionalBytes: |
| oldBufSize = len(self.Bytes) |
| self.growByteBuffer() |
| updated_head = self.head + len(self.Bytes) - oldBufSize |
| self.head = UOffsetTFlags.py_type(updated_head) |
| self.Pad(alignSize) |
| |
| def PrependSOffsetTRelative(self, off): |
| """ |
| PrependSOffsetTRelative prepends an SOffsetT, relative to where it |
| will be written. |
| """ |
| |
| # Ensure alignment is already done: |
| self.Prep(N.SOffsetTFlags.bytewidth, 0) |
| if not (off <= self.Offset()): |
| msg = "flatbuffers: Offset arithmetic error." |
| raise OffsetArithmeticError(msg) |
| off2 = self.Offset() - off + N.SOffsetTFlags.bytewidth |
| self.PlaceSOffsetT(off2) |
| ## @endcond |
| |
| def PrependUOffsetTRelative(self, off): |
| """Prepends an unsigned offset into vector data, relative to where it |
| will be written. |
| """ |
| |
| # Ensure alignment is already done: |
| self.Prep(N.UOffsetTFlags.bytewidth, 0) |
| if not (off <= self.Offset()): |
| msg = "flatbuffers: Offset arithmetic error." |
| raise OffsetArithmeticError(msg) |
| off2 = self.Offset() - off + N.UOffsetTFlags.bytewidth |
| self.PlaceUOffsetT(off2) |
| |
| ## @cond FLATBUFFERS_INTERNAL |
| def StartVector(self, elemSize, numElems, alignment): |
| """ |
| StartVector initializes bookkeeping for writing a new vector. |
| |
| A vector has the following format: |
| - <UOffsetT: number of elements in this vector> |
| - <T: data>+, where T is the type of elements of this vector. |
| """ |
| |
| self.assertNotNested() |
| self.nested = True |
| self.Prep(N.Uint32Flags.bytewidth, elemSize*numElems) |
| self.Prep(alignment, elemSize*numElems) # In case alignment > int. |
| return self.Offset() |
| ## @endcond |
| |
| def EndVector(self, vectorNumElems): |
| """EndVector writes data necessary to finish vector construction.""" |
| |
| self.assertNested() |
| ## @cond FLATBUFFERS_INTERNAL |
| self.nested = False |
| ## @endcond |
| # we already made space for this, so write without PrependUint32 |
| self.PlaceUOffsetT(vectorNumElems) |
| return self.Offset() |
| |
| def CreateString(self, s, encoding='utf-8', errors='strict'): |
| """CreateString writes a null-terminated byte string as a vector.""" |
| |
| self.assertNotNested() |
| ## @cond FLATBUFFERS_INTERNAL |
| self.nested = True |
| ## @endcond |
| |
| if isinstance(s, compat.string_types): |
| x = s.encode(encoding, errors) |
| elif isinstance(s, compat.binary_types): |
| x = s |
| else: |
| raise TypeError("non-string passed to CreateString") |
| |
| self.Prep(N.UOffsetTFlags.bytewidth, (len(x)+1)*N.Uint8Flags.bytewidth) |
| self.Place(0, N.Uint8Flags) |
| |
| l = UOffsetTFlags.py_type(len(s)) |
| ## @cond FLATBUFFERS_INTERNAL |
| self.head = UOffsetTFlags.py_type(self.Head() - l) |
| ## @endcond |
| self.Bytes[self.Head():self.Head()+l] = x |
| |
| return self.EndVector(len(x)) |
| |
| def CreateByteVector(self, x): |
| """CreateString writes a byte vector.""" |
| |
| self.assertNotNested() |
| ## @cond FLATBUFFERS_INTERNAL |
| self.nested = True |
| ## @endcond |
| |
| if not isinstance(x, compat.binary_types): |
| raise TypeError("non-byte vector passed to CreateByteVector") |
| |
| self.Prep(N.UOffsetTFlags.bytewidth, len(x)*N.Uint8Flags.bytewidth) |
| |
| l = UOffsetTFlags.py_type(len(x)) |
| ## @cond FLATBUFFERS_INTERNAL |
| self.head = UOffsetTFlags.py_type(self.Head() - l) |
| ## @endcond |
| self.Bytes[self.Head():self.Head()+l] = x |
| |
| return self.EndVector(len(x)) |
| |
| def CreateNumpyVector(self, x): |
| """CreateNumpyVector writes a numpy array into the buffer.""" |
| |
| if np is None: |
| # Numpy is required for this feature |
| raise NumpyRequiredForThisFeature("Numpy was not found.") |
| |
| if not isinstance(x, np.ndarray): |
| raise TypeError("non-numpy-ndarray passed to CreateNumpyVector") |
| |
| if x.dtype.kind not in ['b', 'i', 'u', 'f']: |
| raise TypeError("numpy-ndarray holds elements of unsupported datatype") |
| |
| if x.ndim > 1: |
| raise TypeError("multidimensional-ndarray passed to CreateNumpyVector") |
| |
| self.StartVector(x.itemsize, x.size, x.dtype.alignment) |
| |
| # Ensure little endian byte ordering |
| if x.dtype.str[0] == "<": |
| x_lend = x |
| else: |
| x_lend = x.byteswap(inplace=False) |
| |
| # Calculate total length |
| l = UOffsetTFlags.py_type(x_lend.itemsize * x_lend.size) |
| ## @cond FLATBUFFERS_INTERNAL |
| self.head = UOffsetTFlags.py_type(self.Head() - l) |
| ## @endcond |
| |
| # tobytes ensures c_contiguous ordering |
| self.Bytes[self.Head():self.Head()+l] = x_lend.tobytes(order='C') |
| |
| return self.EndVector(x.size) |
| |
| ## @cond FLATBUFFERS_INTERNAL |
| def assertNested(self): |
| """ |
| Check that we are in the process of building an object. |
| """ |
| |
| if not self.nested: |
| raise IsNotNestedError() |
| |
| def assertNotNested(self): |
| """ |
| Check that no other objects are being built while making this |
| object. If not, raise an exception. |
| """ |
| |
| if self.nested: |
| raise IsNestedError() |
| |
| def assertStructIsInline(self, obj): |
| """ |
| Structs are always stored inline, so need to be created right |
| where they are used. You'll get this error if you created it |
| elsewhere. |
| """ |
| |
| N.enforce_number(obj, N.UOffsetTFlags) |
| if obj != self.Offset(): |
| msg = ("flatbuffers: Tried to write a Struct at an Offset that " |
| "is different from the current Offset of the Builder.") |
| raise StructIsNotInlineError(msg) |
| |
| def Slot(self, slotnum): |
| """ |
| Slot sets the vtable key `voffset` to the current location in the |
| buffer. |
| |
| """ |
| self.assertNested() |
| self.current_vtable[slotnum] = self.Offset() |
| ## @endcond |
| |
| def __Finish(self, rootTable, sizePrefix, file_identifier=None): |
| """Finish finalizes a buffer, pointing to the given `rootTable`.""" |
| N.enforce_number(rootTable, N.UOffsetTFlags) |
| |
| if file_identifier is not None: |
| self.Prep(N.UOffsetTFlags.bytewidth, N.Uint8Flags.bytewidth*4) |
| |
| # Convert bytes object file_identifier to an array of 4 8-bit integers, |
| # and use big-endian to enforce size compliance. |
| # https://docs.python.org/2/library/struct.html#format-characters |
| file_identifier = N.struct.unpack(">BBBB", file_identifier) |
| for i in range(encode.FILE_IDENTIFIER_LENGTH-1, -1, -1): |
| # Place the bytes of the file_identifer in reverse order: |
| self.Place(file_identifier[i], N.Uint8Flags) |
| |
| self.PrependUOffsetTRelative(rootTable) |
| if sizePrefix: |
| size = len(self.Bytes) - self.Head() |
| N.enforce_number(size, N.Int32Flags) |
| self.PrependInt32(size) |
| self.finished = True |
| return self.Head() |
| |
| def Finish(self, rootTable, file_identifier=None): |
| """Finish finalizes a buffer, pointing to the given `rootTable`.""" |
| return self.__Finish(rootTable, False, file_identifier=file_identifier) |
| |
| def FinishSizePrefixed(self, rootTable, file_identifier=None): |
| """ |
| Finish finalizes a buffer, pointing to the given `rootTable`, |
| with the size prefixed. |
| """ |
| return self.__Finish(rootTable, True, file_identifier=file_identifier) |
| |
| ## @cond FLATBUFFERS_INTERNAL |
| def Prepend(self, flags, off): |
| self.Prep(flags.bytewidth, 0) |
| self.Place(off, flags) |
| |
| def PrependSlot(self, flags, o, x, d): |
| N.enforce_number(x, flags) |
| N.enforce_number(d, flags) |
| if x != d: |
| self.Prepend(flags, x) |
| self.Slot(o) |
| |
| def PrependBoolSlot(self, *args): self.PrependSlot(N.BoolFlags, *args) |
| |
| def PrependByteSlot(self, *args): self.PrependSlot(N.Uint8Flags, *args) |
| |
| def PrependUint8Slot(self, *args): self.PrependSlot(N.Uint8Flags, *args) |
| |
| def PrependUint16Slot(self, *args): self.PrependSlot(N.Uint16Flags, *args) |
| |
| def PrependUint32Slot(self, *args): self.PrependSlot(N.Uint32Flags, *args) |
| |
| def PrependUint64Slot(self, *args): self.PrependSlot(N.Uint64Flags, *args) |
| |
| def PrependInt8Slot(self, *args): self.PrependSlot(N.Int8Flags, *args) |
| |
| def PrependInt16Slot(self, *args): self.PrependSlot(N.Int16Flags, *args) |
| |
| def PrependInt32Slot(self, *args): self.PrependSlot(N.Int32Flags, *args) |
| |
| def PrependInt64Slot(self, *args): self.PrependSlot(N.Int64Flags, *args) |
| |
| def PrependFloat32Slot(self, *args): self.PrependSlot(N.Float32Flags, |
| *args) |
| |
| def PrependFloat64Slot(self, *args): self.PrependSlot(N.Float64Flags, |
| *args) |
| |
| def PrependUOffsetTRelativeSlot(self, o, x, d): |
| """ |
| PrependUOffsetTRelativeSlot prepends an UOffsetT onto the object at |
| vtable slot `o`. If value `x` equals default `d`, then the slot will |
| be set to zero and no other data will be written. |
| """ |
| |
| if x != d: |
| self.PrependUOffsetTRelative(x) |
| self.Slot(o) |
| |
| def PrependStructSlot(self, v, x, d): |
| """ |
| PrependStructSlot prepends a struct onto the object at vtable slot `o`. |
| Structs are stored inline, so nothing additional is being added. |
| In generated code, `d` is always 0. |
| """ |
| |
| N.enforce_number(d, N.UOffsetTFlags) |
| if x != d: |
| self.assertStructIsInline(x) |
| self.Slot(v) |
| |
| ## @endcond |
| |
| def PrependBool(self, x): |
| """Prepend a `bool` to the Builder buffer. |
| |
| Note: aligns and checks for space. |
| """ |
| self.Prepend(N.BoolFlags, x) |
| |
| def PrependByte(self, x): |
| """Prepend a `byte` to the Builder buffer. |
| |
| Note: aligns and checks for space. |
| """ |
| self.Prepend(N.Uint8Flags, x) |
| |
| def PrependUint8(self, x): |
| """Prepend an `uint8` to the Builder buffer. |
| |
| Note: aligns and checks for space. |
| """ |
| self.Prepend(N.Uint8Flags, x) |
| |
| def PrependUint16(self, x): |
| """Prepend an `uint16` to the Builder buffer. |
| |
| Note: aligns and checks for space. |
| """ |
| self.Prepend(N.Uint16Flags, x) |
| |
| def PrependUint32(self, x): |
| """Prepend an `uint32` to the Builder buffer. |
| |
| Note: aligns and checks for space. |
| """ |
| self.Prepend(N.Uint32Flags, x) |
| |
| def PrependUint64(self, x): |
| """Prepend an `uint64` to the Builder buffer. |
| |
| Note: aligns and checks for space. |
| """ |
| self.Prepend(N.Uint64Flags, x) |
| |
| def PrependInt8(self, x): |
| """Prepend an `int8` to the Builder buffer. |
| |
| Note: aligns and checks for space. |
| """ |
| self.Prepend(N.Int8Flags, x) |
| |
| def PrependInt16(self, x): |
| """Prepend an `int16` to the Builder buffer. |
| |
| Note: aligns and checks for space. |
| """ |
| self.Prepend(N.Int16Flags, x) |
| |
| def PrependInt32(self, x): |
| """Prepend an `int32` to the Builder buffer. |
| |
| Note: aligns and checks for space. |
| """ |
| self.Prepend(N.Int32Flags, x) |
| |
| def PrependInt64(self, x): |
| """Prepend an `int64` to the Builder buffer. |
| |
| Note: aligns and checks for space. |
| """ |
| self.Prepend(N.Int64Flags, x) |
| |
| def PrependFloat32(self, x): |
| """Prepend a `float32` to the Builder buffer. |
| |
| Note: aligns and checks for space. |
| """ |
| self.Prepend(N.Float32Flags, x) |
| |
| def PrependFloat64(self, x): |
| """Prepend a `float64` to the Builder buffer. |
| |
| Note: aligns and checks for space. |
| """ |
| self.Prepend(N.Float64Flags, x) |
| |
| ############################################################## |
| |
| ## @cond FLATBUFFERS_INTERNAL |
| def PrependVOffsetT(self, x): self.Prepend(N.VOffsetTFlags, x) |
| |
| def Place(self, x, flags): |
| """ |
| Place prepends a value specified by `flags` to the Builder, |
| without checking for available space. |
| """ |
| |
| N.enforce_number(x, flags) |
| self.head = self.head - flags.bytewidth |
| encode.Write(flags.packer_type, self.Bytes, self.Head(), x) |
| |
| def PlaceVOffsetT(self, x): |
| """PlaceVOffsetT prepends a VOffsetT to the Builder, without checking |
| for space. |
| """ |
| N.enforce_number(x, N.VOffsetTFlags) |
| self.head = self.head - N.VOffsetTFlags.bytewidth |
| encode.Write(packer.voffset, self.Bytes, self.Head(), x) |
| |
| def PlaceSOffsetT(self, x): |
| """PlaceSOffsetT prepends a SOffsetT to the Builder, without checking |
| for space. |
| """ |
| N.enforce_number(x, N.SOffsetTFlags) |
| self.head = self.head - N.SOffsetTFlags.bytewidth |
| encode.Write(packer.soffset, self.Bytes, self.Head(), x) |
| |
| def PlaceUOffsetT(self, x): |
| """PlaceUOffsetT prepends a UOffsetT to the Builder, without checking |
| for space. |
| """ |
| N.enforce_number(x, N.UOffsetTFlags) |
| self.head = self.head - N.UOffsetTFlags.bytewidth |
| encode.Write(packer.uoffset, self.Bytes, self.Head(), x) |
| ## @endcond |
| |
| ## @cond FLATBUFFERS_INTERNAL |
| def vtableEqual(a, objectStart, b): |
| """vtableEqual compares an unwritten vtable to a written vtable.""" |
| |
| N.enforce_number(objectStart, N.UOffsetTFlags) |
| |
| if len(a) * N.VOffsetTFlags.bytewidth != len(b): |
| return False |
| |
| for i, elem in enumerate(a): |
| x = encode.Get(packer.voffset, b, i * N.VOffsetTFlags.bytewidth) |
| |
| # Skip vtable entries that indicate a default value. |
| if x == 0 and elem == 0: |
| pass |
| else: |
| y = objectStart - elem |
| if x != y: |
| return False |
| return True |
| ## @endcond |
| ## @} |