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. 14 15from . import number_types as N 16from .number_types import (UOffsetTFlags, SOffsetTFlags, VOffsetTFlags) 17 18from . import encode 19from . import packer 20 21from . import compat 22from .compat import range_func 23from .compat import memoryview_type 24from .compat import import_numpy, NumpyRequiredForThisFeature 25 26import warnings 27 28np = import_numpy() 29## @file 30## @addtogroup flatbuffers_python_api 31## @{ 32 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 41 42 43class IsNotNestedError(RuntimeError): 44 """ 45 Error caused by using a Builder to write Object data when not inside 46 an Object. 47 """ 48 pass 49 50 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 57 58 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 65 66 67class BuilderSizeError(RuntimeError): 68 """ 69 Error caused by causing a Builder to exceed the hardcoded limit of 2 70 gigabytes. 71 """ 72 pass 73 74class BuilderNotFinishedError(RuntimeError): 75 """ 76 Error caused by not calling `Finish` before calling `Output`. 77 """ 78 pass 79 80class EndVectorLengthMismatched(RuntimeError): 81 """ 82 The number of elements passed to EndVector does not match the number 83 specified in StartVector. 84 """ 85 pass 86 87 88# VtableMetadataFields is the count of metadata fields in each vtable. 89VtableMetadataFields = 2 90## @endcond 91 92class Builder(object): 93 """ A Builder is used to construct one or more FlatBuffers. 94 95 Typically, Builder objects will be used from code generated by the `flatc` 96 compiler. 97 98 A Builder constructs byte buffers in a last-first manner for simplicity and 99 performance during reading. 100 101 Internally, a Builder is a state machine for creating FlatBuffer objects. 102 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. 107 108 Attributes: 109 Bytes: The internal `bytearray` for the Builder. 110 finished: A boolean determining if the Builder has been finalized. 111 """ 112 113 ## @cond FLATBUFFERS_INTENRAL 114 __slots__ = ("Bytes", "current_vtable", "head", "minalign", "objectEnd", 115 "vtables", "nested", "forceDefaults", "finished", "vectorNumElems", 116 "sharedStrings") 117 118 """Maximum buffer size constant, in bytes. 119 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 125 126 def __init__(self, initialSize=1024): 127 """Initializes a Builder of size `initial_size`. 128 129 The internal buffer is grown as needed. 130 """ 131 132 if not (0 <= initialSize <= Builder.MAX_BUFFER_SIZE): 133 msg = "flatbuffers: Cannot create Builder larger than 2 gigabytes." 134 raise BuilderSizeError(msg) 135 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 148 149 def Clear(self) -> None: 150 ## @cond FLATBUFFERS_INTERNAL 151 self.current_vtable = None 152 self.head = UOffsetTFlags.py_type(len(self.Bytes)) 153 self.minalign = 1 154 self.objectEnd = None 155 self.vtables = {} 156 self.nested = False 157 self.forceDefaults = False 158 self.sharedStrings = {} 159 self.vectorNumElems = None 160 ## @endcond 161 self.finished = False 162 163 def Output(self): 164 """Return the portion of the buffer that has been used for writing data. 165 166 This is the typical way to access the FlatBuffer data inside the 167 builder. If you try to access `Builder.Bytes` directly, you would need 168 to manually index it with `Head()`, since the buffer is constructed 169 backwards. 170 171 It raises BuilderNotFinishedError if the buffer has not been finished 172 with `Finish`. 173 """ 174 175 if not self.finished: 176 raise BuilderNotFinishedError() 177 178 return self.Bytes[self.Head():] 179 180 ## @cond FLATBUFFERS_INTERNAL 181 def StartObject(self, numfields): 182 """StartObject initializes bookkeeping for writing a new object.""" 183 184 self.assertNotNested() 185 186 # use 32-bit offsets so that arithmetic doesn't overflow. 187 self.current_vtable = [0 for _ in range_func(numfields)] 188 self.objectEnd = self.Offset() 189 self.nested = True 190 191 def WriteVtable(self): 192 """ 193 WriteVtable serializes the vtable for the current object, if needed. 194 195 Before writing out the vtable, this checks pre-existing vtables for 196 equality to this one. If an equal vtable is found, point the object to 197 the existing vtable and return. 198 199 Because vtable values are sensitive to alignment of object data, not 200 all logically-equal vtables will be deduplicated. 201 202 A vtable has the following format: 203 <VOffsetT: size of the vtable in bytes, including this value> 204 <VOffsetT: size of the object in bytes, including the vtable offset> 205 <VOffsetT: offset for a field> * N, where N is the number of fields 206 in the schema for this type. Includes deprecated fields. 207 Thus, a vtable is made of 2 + N elements, each VOffsetT bytes wide. 208 209 An object has the following format: 210 <SOffsetT: offset to this object's vtable (may be negative)> 211 <byte: data>+ 212 """ 213 214 # Prepend a zero scalar to the object. Later in this function we'll 215 # write an offset here that points to the object's vtable: 216 self.PrependSOffsetTRelative(0) 217 218 objectOffset = self.Offset() 219 220 vtKey = [] 221 trim = True 222 for elem in reversed(self.current_vtable): 223 if elem == 0: 224 if trim: 225 continue 226 else: 227 elem = objectOffset - elem 228 trim = False 229 230 vtKey.append(elem) 231 232 vtKey = tuple(vtKey) 233 vt2Offset = self.vtables.get(vtKey) 234 if vt2Offset is None: 235 # Did not find a vtable, so write this one to the buffer. 236 237 # Write out the current vtable in reverse , because 238 # serialization occurs in last-first order: 239 i = len(self.current_vtable) - 1 240 trailing = 0 241 trim = True 242 while i >= 0: 243 off = 0 244 elem = self.current_vtable[i] 245 i -= 1 246 247 if elem == 0: 248 if trim: 249 trailing += 1 250 continue 251 else: 252 # Forward reference to field; 253 # use 32bit number to ensure no overflow: 254 off = objectOffset - elem 255 trim = False 256 257 self.PrependVOffsetT(off) 258 259 # The two metadata fields are written last. 260 261 # First, store the object bytesize: 262 objectSize = UOffsetTFlags.py_type(objectOffset - self.objectEnd) 263 self.PrependVOffsetT(VOffsetTFlags.py_type(objectSize)) 264 265 # Second, store the vtable bytesize: 266 vBytes = len(self.current_vtable) - trailing + VtableMetadataFields 267 vBytes *= N.VOffsetTFlags.bytewidth 268 self.PrependVOffsetT(VOffsetTFlags.py_type(vBytes)) 269 270 # Next, write the offset to the new vtable in the 271 # already-allocated SOffsetT at the beginning of this object: 272 objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset) 273 encode.Write(packer.soffset, self.Bytes, objectStart, 274 SOffsetTFlags.py_type(self.Offset() - objectOffset)) 275 276 # Finally, store this vtable in memory for future 277 # deduplication: 278 self.vtables[vtKey] = self.Offset() 279 else: 280 # Found a duplicate vtable. 281 objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset) 282 self.head = UOffsetTFlags.py_type(objectStart) 283 284 # Write the offset to the found vtable in the 285 # already-allocated SOffsetT at the beginning of this object: 286 encode.Write(packer.soffset, self.Bytes, self.Head(), 287 SOffsetTFlags.py_type(vt2Offset - objectOffset)) 288 289 self.current_vtable = None 290 return objectOffset 291 292 def EndObject(self): 293 """EndObject writes data necessary to finish object construction.""" 294 self.assertNested() 295 self.nested = False 296 return self.WriteVtable() 297 298 def growByteBuffer(self): 299 """Doubles the size of the byteslice, and copies the old data towards 300 the end of the new buffer (since we build the buffer backwards).""" 301 if len(self.Bytes) == Builder.MAX_BUFFER_SIZE: 302 msg = "flatbuffers: cannot grow buffer beyond 2 gigabytes" 303 raise BuilderSizeError(msg) 304 305 newSize = min(len(self.Bytes) * 2, Builder.MAX_BUFFER_SIZE) 306 if newSize == 0: 307 newSize = 1 308 bytes2 = bytearray(newSize) 309 bytes2[newSize-len(self.Bytes):] = self.Bytes 310 self.Bytes = bytes2 311 ## @endcond 312 313 def Head(self): 314 """Get the start of useful data in the underlying byte buffer. 315 316 Note: unlike other functions, this value is interpreted as from the 317 left. 318 """ 319 ## @cond FLATBUFFERS_INTERNAL 320 return self.head 321 ## @endcond 322 323 ## @cond FLATBUFFERS_INTERNAL 324 def Offset(self): 325 """Offset relative to the end of the buffer.""" 326 return UOffsetTFlags.py_type(len(self.Bytes) - self.Head()) 327 328 def Pad(self, n): 329 """Pad places zeros at the current offset.""" 330 for i in range_func(n): 331 self.Place(0, N.Uint8Flags) 332 333 def Prep(self, size, additionalBytes): 334 """ 335 Prep prepares to write an element of `size` after `additional_bytes` 336 have been written, e.g. if you write a string, you need to align 337 such the int length field is aligned to SizeInt32, and the string 338 data follows it directly. 339 If all you need to do is align, `additionalBytes` will be 0. 340 """ 341 342 # Track the biggest thing we've ever aligned to. 343 if size > self.minalign: 344 self.minalign = size 345 346 # Find the amount of alignment needed such that `size` is properly 347 # aligned after `additionalBytes`: 348 alignSize = (~(len(self.Bytes) - self.Head() + additionalBytes)) + 1 349 alignSize &= (size - 1) 350 351 # Reallocate the buffer if needed: 352 while self.Head() < alignSize+size+additionalBytes: 353 oldBufSize = len(self.Bytes) 354 self.growByteBuffer() 355 updated_head = self.head + len(self.Bytes) - oldBufSize 356 self.head = UOffsetTFlags.py_type(updated_head) 357 self.Pad(alignSize) 358 359 def PrependSOffsetTRelative(self, off): 360 """ 361 PrependSOffsetTRelative prepends an SOffsetT, relative to where it 362 will be written. 363 """ 364 365 # Ensure alignment is already done: 366 self.Prep(N.SOffsetTFlags.bytewidth, 0) 367 if not (off <= self.Offset()): 368 msg = "flatbuffers: Offset arithmetic error." 369 raise OffsetArithmeticError(msg) 370 off2 = self.Offset() - off + N.SOffsetTFlags.bytewidth 371 self.PlaceSOffsetT(off2) 372 ## @endcond 373 374 def PrependUOffsetTRelative(self, off): 375 """Prepends an unsigned offset into vector data, relative to where it 376 will be written. 377 """ 378 379 # Ensure alignment is already done: 380 self.Prep(N.UOffsetTFlags.bytewidth, 0) 381 if not (off <= self.Offset()): 382 msg = "flatbuffers: Offset arithmetic error." 383 raise OffsetArithmeticError(msg) 384 off2 = self.Offset() - off + N.UOffsetTFlags.bytewidth 385 self.PlaceUOffsetT(off2) 386 387 ## @cond FLATBUFFERS_INTERNAL 388 def StartVector(self, elemSize, numElems, alignment): 389 """ 390 StartVector initializes bookkeeping for writing a new vector. 391 392 A vector has the following format: 393 - <UOffsetT: number of elements in this vector> 394 - <T: data>+, where T is the type of elements of this vector. 395 """ 396 397 self.assertNotNested() 398 self.nested = True 399 self.vectorNumElems = numElems 400 self.Prep(N.Uint32Flags.bytewidth, elemSize*numElems) 401 self.Prep(alignment, elemSize*numElems) # In case alignment > int. 402 return self.Offset() 403 ## @endcond 404 405 def EndVector(self, numElems = None): 406 """EndVector writes data necessary to finish vector construction.""" 407 408 self.assertNested() 409 ## @cond FLATBUFFERS_INTERNAL 410 self.nested = False 411 ## @endcond 412 413 if numElems: 414 warnings.warn("numElems is deprecated.", 415 DeprecationWarning, stacklevel=2) 416 if numElems != self.vectorNumElems: 417 raise EndVectorLengthMismatched(); 418 419 # we already made space for this, so write without PrependUint32 420 self.PlaceUOffsetT(self.vectorNumElems) 421 self.vectorNumElems = None 422 return self.Offset() 423 424 def CreateSharedString(self, s, encoding='utf-8', errors='strict'): 425 """ 426 CreateSharedString checks if the string is already written to the buffer 427 before calling CreateString. 428 """ 429 430 if s in self.sharedStrings: 431 return self.sharedStrings[s] 432 433 off = self.CreateString(s, encoding, errors) 434 self.sharedStrings[s] = off 435 436 return off 437 438 def CreateString(self, s, encoding='utf-8', errors='strict'): 439 """CreateString writes a null-terminated byte string as a vector.""" 440 441 self.assertNotNested() 442 ## @cond FLATBUFFERS_INTERNAL 443 self.nested = True 444 ## @endcond 445 446 if isinstance(s, compat.string_types): 447 x = s.encode(encoding, errors) 448 elif isinstance(s, compat.binary_types): 449 x = s 450 else: 451 raise TypeError("non-string passed to CreateString") 452 453 self.Prep(N.UOffsetTFlags.bytewidth, (len(x)+1)*N.Uint8Flags.bytewidth) 454 self.Place(0, N.Uint8Flags) 455 456 l = UOffsetTFlags.py_type(len(s)) 457 ## @cond FLATBUFFERS_INTERNAL 458 self.head = UOffsetTFlags.py_type(self.Head() - l) 459 ## @endcond 460 self.Bytes[self.Head():self.Head()+l] = x 461 462 self.vectorNumElems = len(x) 463 return self.EndVector() 464 465 def CreateByteVector(self, x): 466 """CreateString writes a byte vector.""" 467 468 self.assertNotNested() 469 ## @cond FLATBUFFERS_INTERNAL 470 self.nested = True 471 ## @endcond 472 473 if not isinstance(x, compat.binary_types): 474 raise TypeError("non-byte vector passed to CreateByteVector") 475 476 self.Prep(N.UOffsetTFlags.bytewidth, len(x)*N.Uint8Flags.bytewidth) 477 478 l = UOffsetTFlags.py_type(len(x)) 479 ## @cond FLATBUFFERS_INTERNAL 480 self.head = UOffsetTFlags.py_type(self.Head() - l) 481 ## @endcond 482 self.Bytes[self.Head():self.Head()+l] = x 483 484 self.vectorNumElems = len(x) 485 return self.EndVector() 486 487 def CreateNumpyVector(self, x): 488 """CreateNumpyVector writes a numpy array into the buffer.""" 489 490 if np is None: 491 # Numpy is required for this feature 492 raise NumpyRequiredForThisFeature("Numpy was not found.") 493 494 if not isinstance(x, np.ndarray): 495 raise TypeError("non-numpy-ndarray passed to CreateNumpyVector") 496 497 if x.dtype.kind not in ['b', 'i', 'u', 'f']: 498 raise TypeError("numpy-ndarray holds elements of unsupported datatype") 499 500 if x.ndim > 1: 501 raise TypeError("multidimensional-ndarray passed to CreateNumpyVector") 502 503 self.StartVector(x.itemsize, x.size, x.dtype.alignment) 504 505 # Ensure little endian byte ordering 506 if x.dtype.str[0] == "<": 507 x_lend = x 508 else: 509 x_lend = x.byteswap(inplace=False) 510 511 # Calculate total length 512 l = UOffsetTFlags.py_type(x_lend.itemsize * x_lend.size) 513 ## @cond FLATBUFFERS_INTERNAL 514 self.head = UOffsetTFlags.py_type(self.Head() - l) 515 ## @endcond 516 517 # tobytes ensures c_contiguous ordering 518 self.Bytes[self.Head():self.Head()+l] = x_lend.tobytes(order='C') 519 520 self.vectorNumElems = x.size 521 return self.EndVector() 522 523 ## @cond FLATBUFFERS_INTERNAL 524 def assertNested(self): 525 """ 526 Check that we are in the process of building an object. 527 """ 528 529 if not self.nested: 530 raise IsNotNestedError() 531 532 def assertNotNested(self): 533 """ 534 Check that no other objects are being built while making this 535 object. If not, raise an exception. 536 """ 537 538 if self.nested: 539 raise IsNestedError() 540 541 def assertStructIsInline(self, obj): 542 """ 543 Structs are always stored inline, so need to be created right 544 where they are used. You'll get this error if you created it 545 elsewhere. 546 """ 547 548 N.enforce_number(obj, N.UOffsetTFlags) 549 if obj != self.Offset(): 550 msg = ("flatbuffers: Tried to write a Struct at an Offset that " 551 "is different from the current Offset of the Builder.") 552 raise StructIsNotInlineError(msg) 553 554 def Slot(self, slotnum): 555 """ 556 Slot sets the vtable key `voffset` to the current location in the 557 buffer. 558 559 """ 560 self.assertNested() 561 self.current_vtable[slotnum] = self.Offset() 562 ## @endcond 563 564 def __Finish(self, rootTable, sizePrefix, file_identifier=None): 565 """Finish finalizes a buffer, pointing to the given `rootTable`.""" 566 N.enforce_number(rootTable, N.UOffsetTFlags) 567 568 prepSize = N.UOffsetTFlags.bytewidth 569 if file_identifier is not None: 570 prepSize += N.Int32Flags.bytewidth 571 if sizePrefix: 572 prepSize += N.Int32Flags.bytewidth 573 self.Prep(self.minalign, prepSize) 574 575 if file_identifier is not None: 576 self.Prep(N.UOffsetTFlags.bytewidth, encode.FILE_IDENTIFIER_LENGTH) 577 578 # Convert bytes object file_identifier to an array of 4 8-bit integers, 579 # and use big-endian to enforce size compliance. 580 # https://docs.python.org/2/library/struct.html#format-characters 581 file_identifier = N.struct.unpack(">BBBB", file_identifier) 582 for i in range(encode.FILE_IDENTIFIER_LENGTH-1, -1, -1): 583 # Place the bytes of the file_identifer in reverse order: 584 self.Place(file_identifier[i], N.Uint8Flags) 585 586 self.PrependUOffsetTRelative(rootTable) 587 if sizePrefix: 588 size = len(self.Bytes) - self.Head() 589 N.enforce_number(size, N.Int32Flags) 590 self.PrependInt32(size) 591 self.finished = True 592 return self.Head() 593 594 def Finish(self, rootTable, file_identifier=None): 595 """Finish finalizes a buffer, pointing to the given `rootTable`.""" 596 return self.__Finish(rootTable, False, file_identifier=file_identifier) 597 598 def FinishSizePrefixed(self, rootTable, file_identifier=None): 599 """ 600 Finish finalizes a buffer, pointing to the given `rootTable`, 601 with the size prefixed. 602 """ 603 return self.__Finish(rootTable, True, file_identifier=file_identifier) 604 605 ## @cond FLATBUFFERS_INTERNAL 606 def Prepend(self, flags, off): 607 self.Prep(flags.bytewidth, 0) 608 self.Place(off, flags) 609 610 def PrependSlot(self, flags, o, x, d): 611 if x is not None: 612 N.enforce_number(x, flags) 613 if d is not None: 614 N.enforce_number(d, flags) 615 if x != d or (self.forceDefaults and d is not None): 616 self.Prepend(flags, x) 617 self.Slot(o) 618 619 def PrependBoolSlot(self, *args): self.PrependSlot(N.BoolFlags, *args) 620 621 def PrependByteSlot(self, *args): self.PrependSlot(N.Uint8Flags, *args) 622 623 def PrependUint8Slot(self, *args): self.PrependSlot(N.Uint8Flags, *args) 624 625 def PrependUint16Slot(self, *args): self.PrependSlot(N.Uint16Flags, *args) 626 627 def PrependUint32Slot(self, *args): self.PrependSlot(N.Uint32Flags, *args) 628 629 def PrependUint64Slot(self, *args): self.PrependSlot(N.Uint64Flags, *args) 630 631 def PrependInt8Slot(self, *args): self.PrependSlot(N.Int8Flags, *args) 632 633 def PrependInt16Slot(self, *args): self.PrependSlot(N.Int16Flags, *args) 634 635 def PrependInt32Slot(self, *args): self.PrependSlot(N.Int32Flags, *args) 636 637 def PrependInt64Slot(self, *args): self.PrependSlot(N.Int64Flags, *args) 638 639 def PrependFloat32Slot(self, *args): self.PrependSlot(N.Float32Flags, 640 *args) 641 642 def PrependFloat64Slot(self, *args): self.PrependSlot(N.Float64Flags, 643 *args) 644 645 def PrependUOffsetTRelativeSlot(self, o, x, d): 646 """ 647 PrependUOffsetTRelativeSlot prepends an UOffsetT onto the object at 648 vtable slot `o`. If value `x` equals default `d`, then the slot will 649 be set to zero and no other data will be written. 650 """ 651 652 if x != d or self.forceDefaults: 653 self.PrependUOffsetTRelative(x) 654 self.Slot(o) 655 656 def PrependStructSlot(self, v, x, d): 657 """ 658 PrependStructSlot prepends a struct onto the object at vtable slot `o`. 659 Structs are stored inline, so nothing additional is being added. 660 In generated code, `d` is always 0. 661 """ 662 663 N.enforce_number(d, N.UOffsetTFlags) 664 if x != d: 665 self.assertStructIsInline(x) 666 self.Slot(v) 667 668 ## @endcond 669 670 def PrependBool(self, x): 671 """Prepend a `bool` to the Builder buffer. 672 673 Note: aligns and checks for space. 674 """ 675 self.Prepend(N.BoolFlags, x) 676 677 def PrependByte(self, x): 678 """Prepend a `byte` to the Builder buffer. 679 680 Note: aligns and checks for space. 681 """ 682 self.Prepend(N.Uint8Flags, x) 683 684 def PrependUint8(self, x): 685 """Prepend an `uint8` to the Builder buffer. 686 687 Note: aligns and checks for space. 688 """ 689 self.Prepend(N.Uint8Flags, x) 690 691 def PrependUint16(self, x): 692 """Prepend an `uint16` to the Builder buffer. 693 694 Note: aligns and checks for space. 695 """ 696 self.Prepend(N.Uint16Flags, x) 697 698 def PrependUint32(self, x): 699 """Prepend an `uint32` to the Builder buffer. 700 701 Note: aligns and checks for space. 702 """ 703 self.Prepend(N.Uint32Flags, x) 704 705 def PrependUint64(self, x): 706 """Prepend an `uint64` to the Builder buffer. 707 708 Note: aligns and checks for space. 709 """ 710 self.Prepend(N.Uint64Flags, x) 711 712 def PrependInt8(self, x): 713 """Prepend an `int8` to the Builder buffer. 714 715 Note: aligns and checks for space. 716 """ 717 self.Prepend(N.Int8Flags, x) 718 719 def PrependInt16(self, x): 720 """Prepend an `int16` to the Builder buffer. 721 722 Note: aligns and checks for space. 723 """ 724 self.Prepend(N.Int16Flags, x) 725 726 def PrependInt32(self, x): 727 """Prepend an `int32` to the Builder buffer. 728 729 Note: aligns and checks for space. 730 """ 731 self.Prepend(N.Int32Flags, x) 732 733 def PrependInt64(self, x): 734 """Prepend an `int64` to the Builder buffer. 735 736 Note: aligns and checks for space. 737 """ 738 self.Prepend(N.Int64Flags, x) 739 740 def PrependFloat32(self, x): 741 """Prepend a `float32` to the Builder buffer. 742 743 Note: aligns and checks for space. 744 """ 745 self.Prepend(N.Float32Flags, x) 746 747 def PrependFloat64(self, x): 748 """Prepend a `float64` to the Builder buffer. 749 750 Note: aligns and checks for space. 751 """ 752 self.Prepend(N.Float64Flags, x) 753 754 def ForceDefaults(self, forceDefaults): 755 """ 756 In order to save space, fields that are set to their default value 757 don't get serialized into the buffer. Forcing defaults provides a 758 way to manually disable this optimization. When set to `True`, will 759 always serialize default values. 760 """ 761 self.forceDefaults = forceDefaults 762 763############################################################## 764 765 ## @cond FLATBUFFERS_INTERNAL 766 def PrependVOffsetT(self, x): self.Prepend(N.VOffsetTFlags, x) 767 768 def Place(self, x, flags): 769 """ 770 Place prepends a value specified by `flags` to the Builder, 771 without checking for available space. 772 """ 773 774 N.enforce_number(x, flags) 775 self.head = self.head - flags.bytewidth 776 encode.Write(flags.packer_type, self.Bytes, self.Head(), x) 777 778 def PlaceVOffsetT(self, x): 779 """PlaceVOffsetT prepends a VOffsetT to the Builder, without checking 780 for space. 781 """ 782 N.enforce_number(x, N.VOffsetTFlags) 783 self.head = self.head - N.VOffsetTFlags.bytewidth 784 encode.Write(packer.voffset, self.Bytes, self.Head(), x) 785 786 def PlaceSOffsetT(self, x): 787 """PlaceSOffsetT prepends a SOffsetT to the Builder, without checking 788 for space. 789 """ 790 N.enforce_number(x, N.SOffsetTFlags) 791 self.head = self.head - N.SOffsetTFlags.bytewidth 792 encode.Write(packer.soffset, self.Bytes, self.Head(), x) 793 794 def PlaceUOffsetT(self, x): 795 """PlaceUOffsetT prepends a UOffsetT to the Builder, without checking 796 for space. 797 """ 798 N.enforce_number(x, N.UOffsetTFlags) 799 self.head = self.head - N.UOffsetTFlags.bytewidth 800 encode.Write(packer.uoffset, self.Bytes, self.Head(), x) 801 ## @endcond 802 803## @cond FLATBUFFERS_INTERNAL 804def vtableEqual(a, objectStart, b): 805 """vtableEqual compares an unwritten vtable to a written vtable.""" 806 807 N.enforce_number(objectStart, N.UOffsetTFlags) 808 809 if len(a) * N.VOffsetTFlags.bytewidth != len(b): 810 return False 811 812 for i, elem in enumerate(a): 813 x = encode.Get(packer.voffset, b, i * N.VOffsetTFlags.bytewidth) 814 815 # Skip vtable entries that indicate a default value. 816 if x == 0 and elem == 0: 817 pass 818 else: 819 y = objectStart - elem 820 if x != y: 821 return False 822 return True 823## @endcond 824## @} 825