Squashed 'third_party/flatbuffers/' content from commit acc9990ab
Change-Id: I48550d40d78fea996ebe74e9723a5d1f910de491
git-subtree-dir: third_party/flatbuffers
git-subtree-split: acc9990abd2206491480291b0f85f925110102ea
diff --git a/python/flatbuffers/builder.py b/python/flatbuffers/builder.py
new file mode 100644
index 0000000..d04ee85
--- /dev/null
+++ b/python/flatbuffers/builder.py
@@ -0,0 +1,755 @@
+# 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
+## @}