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 encode 16from . import number_types as N 17 18 19class Table(object): 20 """Table wraps a byte slice and provides read access to its data. 21 22 The variable `Pos` indicates the root of the FlatBuffers object therein.""" 23 24 __slots__ = ("Bytes", "Pos") 25 26 def __init__(self, buf, pos): 27 N.enforce_number(pos, N.UOffsetTFlags) 28 29 self.Bytes = buf 30 self.Pos = pos 31 32 def Offset(self, vtableOffset): 33 """Offset provides access into the Table's vtable. 34 35 Deprecated fields are ignored by checking the vtable's length.""" 36 37 vtable = self.Pos - self.Get(N.SOffsetTFlags, self.Pos) 38 vtableEnd = self.Get(N.VOffsetTFlags, vtable) 39 if vtableOffset < vtableEnd: 40 return self.Get(N.VOffsetTFlags, vtable + vtableOffset) 41 return 0 42 43 def Indirect(self, off): 44 """Indirect retrieves the relative offset stored at `offset`.""" 45 N.enforce_number(off, N.UOffsetTFlags) 46 return off + encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off) 47 48 def String(self, off): 49 """String gets a string from data stored inside the flatbuffer.""" 50 N.enforce_number(off, N.UOffsetTFlags) 51 off += encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off) 52 start = off + N.UOffsetTFlags.bytewidth 53 length = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off) 54 return bytes(self.Bytes[start:start+length]) 55 56 def VectorLen(self, off): 57 """VectorLen retrieves the length of the vector whose offset is stored 58 at "off" in this object.""" 59 N.enforce_number(off, N.UOffsetTFlags) 60 61 off += self.Pos 62 off += encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off) 63 ret = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off) 64 return ret 65 66 def Vector(self, off): 67 """Vector retrieves the start of data of the vector whose offset is 68 stored at "off" in this object.""" 69 N.enforce_number(off, N.UOffsetTFlags) 70 71 off += self.Pos 72 x = off + self.Get(N.UOffsetTFlags, off) 73 # data starts after metadata containing the vector length 74 x += N.UOffsetTFlags.bytewidth 75 return x 76 77 def Union(self, t2, off): 78 """Union initializes any Table-derived type to point to the union at 79 the given offset.""" 80 assert type(t2) is Table 81 N.enforce_number(off, N.UOffsetTFlags) 82 83 off += self.Pos 84 t2.Pos = off + self.Get(N.UOffsetTFlags, off) 85 t2.Bytes = self.Bytes 86 87 def Get(self, flags, off): 88 """ 89 Get retrieves a value of the type specified by `flags` at the 90 given offset. 91 """ 92 N.enforce_number(off, N.UOffsetTFlags) 93 return flags.py_type(encode.Get(flags.packer_type, self.Bytes, off)) 94 95 def GetSlot(self, slot, d, validator_flags): 96 N.enforce_number(slot, N.VOffsetTFlags) 97 if validator_flags is not None: 98 N.enforce_number(d, validator_flags) 99 off = self.Offset(slot) 100 if off == 0: 101 return d 102 return self.Get(validator_flags, self.Pos + off) 103 104 def GetVectorAsNumpy(self, flags, off): 105 """ 106 GetVectorAsNumpy returns the vector that starts at `Vector(off)` 107 as a numpy array with the type specified by `flags`. The array is 108 a `view` into Bytes, so modifying the returned array will 109 modify Bytes in place. 110 """ 111 offset = self.Vector(off) 112 length = self.VectorLen(off) # TODO: length accounts for bytewidth, right? 113 numpy_dtype = N.to_numpy_type(flags) 114 return encode.GetVectorAsNumpy(numpy_dtype, self.Bytes, length, offset) 115 116 def GetVOffsetTSlot(self, slot, d): 117 """ 118 GetVOffsetTSlot retrieves the VOffsetT that the given vtable location 119 points to. If the vtable value is zero, the default value `d` 120 will be returned. 121 """ 122 123 N.enforce_number(slot, N.VOffsetTFlags) 124 N.enforce_number(d, N.VOffsetTFlags) 125 126 off = self.Offset(slot) 127 if off == 0: 128 return d 129 return off 130