mirror of
https://github.com/google/flatbuffers.git
synced 2026-06-08 22:20:56 +00:00
Lua (5.3) Language addition (#4804)
* starting Lua port of python implmention. Syncing commit * Bulk of Lua module port from Python done. Not tested, only static analysis. Need to work on binary strings. Started work on flatc lua code generation * Fixed all the basic errors to produced a binary output from the builder, don't know if it is generated correctly, but it contains data, so that must be good * fixed binary set command that was extending the array improperly * continued improvement * Moved lua submodules down a directory so their names don't clash with potential other modules. Added compat module to provide Lua versioning logic * Successful sample port from Python * working on testing Lua code with formal tests * continued to work on tests and fixes to code to make tests pass * Added reading buffer test * Changed binaryarray implmentation to use a temporary table for storing data, and then serialize it to a string when requested. This double the rate of building flatbuffers compared to the string approach. * Didn't need encode module as it just added another layer of indirection that isn't need * profiled reading buffers, optimizations to increase read performance of monster data to ~7 monster / millisecond * Writing profiler improvments. Get about ~2 monsters/millisecond building rate * removed Numpy generation from Lua (came from the Python port) * math.pow is deprecated in Lua 5.3, so changed to ^ notation. Also added .bat script for starting Lua tests * adding results of generate_code.bat * simple edits for code review in PR. * There was a buffer overflow in inserting the keywords into the unorder set for both the Lua and Python code gens. Changed insertion to use iterators. * fixed spacing issue * basic documenation/tutorial updates. Updated sample_binary.lua to reflect the tutorial better * removed windows-specific build step in Lua tests
This commit is contained in:
committed by
Wouter van Oortmerssen
parent
8ea293b988
commit
ba5eb3b5cf
8
lua/flatbuffers.lua
Normal file
8
lua/flatbuffers.lua
Normal file
@@ -0,0 +1,8 @@
|
||||
local m = {}
|
||||
|
||||
m.Builder = require("flatbuffers.builder").New
|
||||
m.N = require("flatbuffers.numTypes")
|
||||
m.view = require("flatbuffers.view")
|
||||
m.binaryArray = require("flatbuffers.binaryarray")
|
||||
|
||||
return m
|
||||
123
lua/flatbuffers/binaryarray.lua
Normal file
123
lua/flatbuffers/binaryarray.lua
Normal file
@@ -0,0 +1,123 @@
|
||||
local m = {} -- the module table
|
||||
|
||||
local mt = {} -- the module metatable
|
||||
|
||||
-- given a binary array, set a metamethod to return its length
|
||||
-- (e.g., #binaryArray, calls this)
|
||||
function mt:__len()
|
||||
return self.size
|
||||
end
|
||||
|
||||
-- Create a new binary array of an initial size
|
||||
function m.New(sizeOrString)
|
||||
-- the array storage itself
|
||||
local o = {}
|
||||
|
||||
if type(sizeOrString) == "string" then
|
||||
o.str = sizeOrString
|
||||
o.size = #sizeOrString
|
||||
elseif type(sizeOrString) == "number" then
|
||||
o.data = {}
|
||||
o.size = sizeOrString
|
||||
else
|
||||
error("Expect a integer size value or string to construct a binary array")
|
||||
end
|
||||
-- set the inheritance
|
||||
setmetatable(o, {__index = mt, __len = mt.__len})
|
||||
return o
|
||||
end
|
||||
|
||||
-- Get a slice of the binary array from start to end position
|
||||
function mt:Slice(startPos, endPos)
|
||||
startPos = startPos or 0
|
||||
endPos = endPos or self.size
|
||||
local d = self.data
|
||||
if d then
|
||||
-- if the self.data is defined, we are building the buffer
|
||||
-- in a Lua table
|
||||
|
||||
-- new table to store the slice components
|
||||
local b = {}
|
||||
|
||||
-- starting with the startPos, put all
|
||||
-- values into the new table to be concat later
|
||||
-- updated the startPos based on the size of the
|
||||
-- value
|
||||
while startPos < endPos do
|
||||
local v = d[startPos] or '/0'
|
||||
table.insert(b, v)
|
||||
startPos = startPos + #v
|
||||
end
|
||||
|
||||
-- combine the table of strings into one string
|
||||
-- this is faster than doing a bunch of concats by themselves
|
||||
return table.concat(b)
|
||||
else
|
||||
-- n.b start/endPos are 0-based incoming, so need to convert
|
||||
-- correctly. in python a slice includes start -> end - 1
|
||||
return self.str:sub(startPos+1, endPos)
|
||||
end
|
||||
end
|
||||
|
||||
-- Grow the binary array to a new size, placing the exisiting data
|
||||
-- at then end of the new array
|
||||
function mt:Grow(newsize)
|
||||
-- the new table to store the data
|
||||
local newT = {}
|
||||
|
||||
-- the offset to be applied to existing entries
|
||||
local offset = newsize - self.size
|
||||
|
||||
-- loop over all the current entries and
|
||||
-- add them to the new table at the correct
|
||||
-- offset location
|
||||
local d = self.data
|
||||
for i,data in pairs(d) do
|
||||
newT[i + offset] = data
|
||||
end
|
||||
|
||||
-- update this storage with the new table and size
|
||||
self.data = newT
|
||||
self.size = newsize
|
||||
end
|
||||
|
||||
-- memorization for padding strings
|
||||
local pads = {}
|
||||
|
||||
-- pad the binary with n \0 bytes at the starting position
|
||||
function mt:Pad(n, startPos)
|
||||
-- use memorization to avoid creating a bunch of strings
|
||||
-- all the time
|
||||
local s = pads[n]
|
||||
if not s then
|
||||
s = string.rep('\0', n)
|
||||
pads[n] = s
|
||||
end
|
||||
|
||||
-- store the padding string at the start position in the
|
||||
-- Lua table
|
||||
self.data[startPos] = s
|
||||
end
|
||||
|
||||
-- Sets the binary array value at the specified position
|
||||
function mt:Set(value, position)
|
||||
self.data[position] = value
|
||||
end
|
||||
|
||||
-- locals for slightly faster access
|
||||
local sunpack = string.unpack
|
||||
local spack = string.pack
|
||||
|
||||
-- Pack the data into a binary representation
|
||||
function m.Pack(fmt, ...)
|
||||
return spack(fmt, ...)
|
||||
end
|
||||
|
||||
-- Unpack the data from a binary representation in
|
||||
-- a Lua value
|
||||
function m.Unpack(fmt, s, pos)
|
||||
return sunpack(fmt, s.str, pos + 1)
|
||||
end
|
||||
|
||||
-- Return the binary array module
|
||||
return m
|
||||
368
lua/flatbuffers/builder.lua
Normal file
368
lua/flatbuffers/builder.lua
Normal file
@@ -0,0 +1,368 @@
|
||||
local N = require("flatbuffers.numTypes")
|
||||
local ba = require("flatbuffers.binaryarray")
|
||||
local compat = require("flatbuffers.compat")
|
||||
|
||||
local m = {}
|
||||
|
||||
local mt = {}
|
||||
|
||||
-- get locals for faster access
|
||||
local VOffsetT = N.VOffsetT
|
||||
local UOffsetT = N.UOffsetT
|
||||
local SOffsetT = N.SOffsetT
|
||||
local Bool = N.Bool
|
||||
local Uint8 = N.Uint8
|
||||
local Uint16 = N.Uint16
|
||||
local Uint32 = N.Uint32
|
||||
local Uint64 = N.Uint64
|
||||
local Int8 = N.Int8
|
||||
local Int16 = N.Int16
|
||||
local Int32 = N.Int32
|
||||
local Int64 = N.Int64
|
||||
local Float32 = N.Float32
|
||||
local Float64 = N.Float64
|
||||
|
||||
local MAX_BUFFER_SIZE = 0x80000000 -- 2 GB
|
||||
local VtableMetadataFields = 2
|
||||
|
||||
local getAlignSize = compat.GetAlignSize
|
||||
|
||||
local function vtableEqual(a, objectStart, b)
|
||||
UOffsetT:EnforceNumber(objectStart)
|
||||
if (#a * VOffsetT.bytewidth) ~= #b then
|
||||
return false
|
||||
end
|
||||
|
||||
for i, elem in ipairs(a) do
|
||||
local x = VOffsetT:Unpack(b, i * VOffsetT.bytewidth)
|
||||
if x ~= 0 or elem ~= 0 then
|
||||
local y = objectStart - elem
|
||||
if x ~= y then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function m.New(initialSize)
|
||||
assert(0 <= initialSize and initialSize < MAX_BUFFER_SIZE)
|
||||
local o =
|
||||
{
|
||||
finished = false,
|
||||
bytes = ba.New(initialSize),
|
||||
nested = false,
|
||||
head = initialSize,
|
||||
minalign = 1,
|
||||
vtables = {}
|
||||
}
|
||||
setmetatable(o, {__index = mt})
|
||||
return o
|
||||
end
|
||||
|
||||
function mt:Output(full)
|
||||
assert(self.finished, "Builder Not Finished")
|
||||
if full then
|
||||
return self.bytes:Slice()
|
||||
else
|
||||
return self.bytes:Slice(self.head)
|
||||
end
|
||||
end
|
||||
|
||||
function mt:StartObject(numFields)
|
||||
assert(not self.nested)
|
||||
|
||||
local vtable = {}
|
||||
|
||||
for _=1,numFields do
|
||||
table.insert(vtable, 0)
|
||||
end
|
||||
|
||||
self.currentVTable = vtable
|
||||
self.objectEnd = self:Offset()
|
||||
self.minalign = 1
|
||||
self.nested = true
|
||||
end
|
||||
|
||||
function mt:WriteVtable()
|
||||
self:PrependSOffsetTRelative(0)
|
||||
local objectOffset = self:Offset()
|
||||
|
||||
local exisitingVTable
|
||||
local i = #self.vtables
|
||||
while i >= 1 do
|
||||
if self.vtables[i] == 0 then
|
||||
table.remove(self.vtables,i)
|
||||
end
|
||||
i = i - 1
|
||||
end
|
||||
|
||||
while i >= 1 do
|
||||
|
||||
local vt2Offset = self.vtables[i]
|
||||
local vt2Start = #self.bytes - vt2Offset
|
||||
local vt2len = VOffsetT:Unpack(self.bytes, vt2Start)
|
||||
|
||||
local metadata = VtableMetadataFields * VOffsetT.bytewidth
|
||||
local vt2End = vt2Start + vt2Len
|
||||
local vt2 = self.bytes:Slice(vt2Start+metadata,vt2End)
|
||||
|
||||
if vtableEqual(self.currentVTable, objectOffset, vt2) then
|
||||
exisitingVTable = vt2Offset
|
||||
break
|
||||
end
|
||||
|
||||
i = i - 1
|
||||
end
|
||||
|
||||
if not exisitingVTable then
|
||||
i = #self.currentVTable
|
||||
while i >= 1 do
|
||||
local off = 0
|
||||
local a = self.currentVTable[i]
|
||||
if a and a ~= 0 then
|
||||
off = objectOffset - a
|
||||
end
|
||||
self:PrependVOffsetT(off)
|
||||
|
||||
i = i - 1
|
||||
end
|
||||
|
||||
local objectSize = objectOffset - self.objectEnd
|
||||
self:PrependVOffsetT(objectSize)
|
||||
|
||||
local vBytes = #self.currentVTable + VtableMetadataFields
|
||||
vBytes = vBytes * VOffsetT.bytewidth
|
||||
self:PrependVOffsetT(vBytes)
|
||||
|
||||
local objectStart = #self.bytes - objectOffset
|
||||
self.bytes:Set(SOffsetT:Pack(self:Offset() - objectOffset),objectStart)
|
||||
|
||||
table.insert(self.vtables, self:Offset())
|
||||
else
|
||||
local objectStart = #self.bytes - objectOffset
|
||||
self.head = objectStart
|
||||
self.bytes:Set(SOffsetT:Pack(exisitingVTable - objectOffset),self.head)
|
||||
end
|
||||
|
||||
self.currentVTable = nil
|
||||
return objectOffset
|
||||
end
|
||||
|
||||
function mt:EndObject()
|
||||
assert(self.nested)
|
||||
self.nested = false
|
||||
return self:WriteVtable()
|
||||
end
|
||||
|
||||
local function growByteBuffer(self, desiredSize)
|
||||
local s = #self.bytes
|
||||
assert(s < MAX_BUFFER_SIZE, "Flat Buffers cannot grow buffer beyond 2 gigabytes")
|
||||
local newsize = s
|
||||
repeat
|
||||
newsize = math.min(newsize * 2, MAX_BUFFER_SIZE)
|
||||
if newsize == 0 then newsize = 1 end
|
||||
until newsize > desiredSize
|
||||
|
||||
self.bytes:Grow(newsize)
|
||||
end
|
||||
|
||||
function mt:Head()
|
||||
return self.head
|
||||
end
|
||||
|
||||
function mt:Offset()
|
||||
return #self.bytes - self.head
|
||||
end
|
||||
|
||||
function mt:Pad(n)
|
||||
if n > 0 then
|
||||
-- pads are 8-bit, so skip the bytewidth lookup
|
||||
local h = self.head - n -- UInt8
|
||||
self.head = h
|
||||
self.bytes:Pad(n, h)
|
||||
end
|
||||
end
|
||||
|
||||
function mt:Prep(size, additionalBytes)
|
||||
if size > self.minalign then
|
||||
self.minalign = size
|
||||
end
|
||||
|
||||
local h = self.head
|
||||
|
||||
local k = #self.bytes - h + additionalBytes
|
||||
local alignsize = ((~k) + 1) & (size - 1) -- getAlignSize(k, size)
|
||||
|
||||
local desiredSize = alignsize + size + additionalBytes
|
||||
|
||||
while self.head < desiredSize do
|
||||
local oldBufSize = #self.bytes
|
||||
growByteBuffer(self, desiredSize)
|
||||
local updatedHead = self.head + #self.bytes - oldBufSize
|
||||
self.head = updatedHead
|
||||
end
|
||||
|
||||
self:Pad(alignsize)
|
||||
end
|
||||
|
||||
function mt:PrependSOffsetTRelative(off)
|
||||
self:Prep(SOffsetT.bytewidth, 0)
|
||||
assert(off <= self:Offset(), "Offset arithmetic error")
|
||||
local off2 = self:Offset() - off + SOffsetT.bytewidth
|
||||
self:Place(off2, SOffsetT)
|
||||
end
|
||||
|
||||
function mt:PrependUOffsetTRelative(off)
|
||||
self:Prep(UOffsetT.bytewidth, 0)
|
||||
local soffset = self:Offset()
|
||||
if off <= soffset then
|
||||
local off2 = soffset - off + UOffsetT.bytewidth
|
||||
self:Place(off2, UOffsetT)
|
||||
else
|
||||
error("Offset arithmetic error")
|
||||
end
|
||||
end
|
||||
|
||||
function mt:StartVector(elemSize, numElements, alignment)
|
||||
assert(not self.nested)
|
||||
self.nested = true
|
||||
self:Prep(Uint32.bytewidth, elemSize * numElements)
|
||||
self:Prep(alignment, elemSize * numElements)
|
||||
return self:Offset()
|
||||
end
|
||||
|
||||
function mt:EndVector(vectorNumElements)
|
||||
assert(self.nested)
|
||||
self.nested = false
|
||||
self:Place(vectorNumElements, UOffsetT)
|
||||
return self:Offset()
|
||||
end
|
||||
|
||||
function mt:CreateString(s)
|
||||
assert(not self.nested)
|
||||
self.nested = true
|
||||
|
||||
assert(type(s) == "string")
|
||||
|
||||
self:Prep(UOffsetT.bytewidth, (#s + 1)*Uint8.bytewidth)
|
||||
self:Place(0, Uint8)
|
||||
|
||||
local l = #s
|
||||
self.head = self.head - l
|
||||
|
||||
self.bytes:Set(s, self.head, self.head + l)
|
||||
|
||||
return self:EndVector(#s)
|
||||
end
|
||||
|
||||
function mt:CreateByteVector(x)
|
||||
assert(not self.nested)
|
||||
self.nested = true
|
||||
self:Prep(UOffsetT.bytewidth, #x*Uint8.bytewidth)
|
||||
|
||||
local l = #x
|
||||
self.head = self.head - l
|
||||
|
||||
self.bytes:Set(x, self.head, self.head + l)
|
||||
|
||||
return self:EndVector(#x)
|
||||
end
|
||||
|
||||
function mt:Slot(slotnum)
|
||||
assert(self.nested)
|
||||
-- n.b. slot number is 0-based
|
||||
self.currentVTable[slotnum + 1] = self:Offset()
|
||||
end
|
||||
|
||||
local function finish(self, rootTable, sizePrefix)
|
||||
UOffsetT:EnforceNumber(rootTable)
|
||||
local prepSize = UOffsetT.bytewidth
|
||||
if sizePrefix then
|
||||
prepSize = prepSize + Int32.bytewidth
|
||||
end
|
||||
|
||||
self:Prep(self.minalign, prepSize)
|
||||
self:PrependUOffsetTRelative(rootTable)
|
||||
if sizePrefix then
|
||||
local size = #self.bytes - self.head
|
||||
Int32:EnforceNumber(size)
|
||||
self:PrependInt32(size)
|
||||
end
|
||||
self.finished = true
|
||||
return self.head
|
||||
end
|
||||
|
||||
function mt:Finish(rootTable)
|
||||
return finish(self, rootTable, false)
|
||||
end
|
||||
|
||||
function mt:FinishSizePrefixed(rootTable)
|
||||
return finish(self, rootTable, true)
|
||||
end
|
||||
|
||||
function mt:Prepend(flags, off)
|
||||
self:Prep(flags.bytewidth, 0)
|
||||
self:Place(off, flags)
|
||||
end
|
||||
|
||||
function mt:PrependSlot(flags, o, x, d)
|
||||
flags:EnforceNumber(x)
|
||||
flags:EnforceNumber(d)
|
||||
if x ~= d then
|
||||
self:Prepend(flags, x)
|
||||
self:Slot(o)
|
||||
end
|
||||
end
|
||||
|
||||
function mt:PrependBoolSlot(...) self:PrependSlot(Bool, ...) end
|
||||
function mt:PrependByteSlot(...) self:PrependSlot(Uint8, ...) end
|
||||
function mt:PrependUint8Slot(...) self:PrependSlot(Uint8, ...) end
|
||||
function mt:PrependUint16Slot(...) self:PrependSlot(Uint16, ...) end
|
||||
function mt:PrependUint32Slot(...) self:PrependSlot(Uint32, ...) end
|
||||
function mt:PrependUint64Slot(...) self:PrependSlot(Uint64, ...) end
|
||||
function mt:PrependInt8Slot(...) self:PrependSlot(Int8, ...) end
|
||||
function mt:PrependInt16Slot(...) self:PrependSlot(Int16, ...) end
|
||||
function mt:PrependInt32Slot(...) self:PrependSlot(Int32, ...) end
|
||||
function mt:PrependInt64Slot(...) self:PrependSlot(Int64, ...) end
|
||||
function mt:PrependFloat32Slot(...) self:PrependSlot(Float32, ...) end
|
||||
function mt:PrependFloat64Slot(...) self:PrependSlot(Float64, ...) end
|
||||
|
||||
function mt:PrependUOffsetTRelativeSlot(o,x,d)
|
||||
if x~=d then
|
||||
self:PrependUOffsetTRelative(x)
|
||||
self:Slot(o)
|
||||
end
|
||||
end
|
||||
|
||||
function mt:PrependStructSlot(v,x,d)
|
||||
UOffsetT:EnforceNumber(d)
|
||||
if x~=d then
|
||||
UOffsetT:EnforceNumber(x)
|
||||
assert(x == self:Offset(), "Tried to write a Struct at an Offset that is different from the current Offset of the Builder.")
|
||||
self:Slot(v)
|
||||
end
|
||||
end
|
||||
|
||||
function mt:PrependBool(x) self:Prepend(Bool, x) end
|
||||
function mt:PrependByte(x) self:Prepend(Uint8, x) end
|
||||
function mt:PrependUint8(x) self:Prepend(Uint8, x) end
|
||||
function mt:PrependUint16(x) self:Prepend(Uint16, x) end
|
||||
function mt:PrependUint32(x) self:Prepend(Uint32, x) end
|
||||
function mt:PrependUint64(x) self:Prepend(Uint64, x) end
|
||||
function mt:PrependInt8(x) self:Prepend(Int8, x) end
|
||||
function mt:PrependInt16(x) self:Prepend(Int16, x) end
|
||||
function mt:PrependInt32(x) self:Prepend(Int32, x) end
|
||||
function mt:PrependInt64(x) self:Prepend(Int64, x) end
|
||||
function mt:PrependFloat32(x) self:Prepend(Float32, x) end
|
||||
function mt:PrependFloat64(x) self:Prepend(Float64, x) end
|
||||
function mt:PrependVOffsetT(x) self:Prepend(VOffsetT, x) end
|
||||
|
||||
function mt:Place(x, flags)
|
||||
local d = flags:EnforceNumberAndPack(x)
|
||||
local h = self.head - flags.bytewidth
|
||||
self.head = h
|
||||
self.bytes:Set(d, h)
|
||||
end
|
||||
|
||||
return m
|
||||
17
lua/flatbuffers/compat.lua
Normal file
17
lua/flatbuffers/compat.lua
Normal file
@@ -0,0 +1,17 @@
|
||||
local m = {}
|
||||
|
||||
local getAlignSize
|
||||
if _VERSION == "Lua 5.3" then
|
||||
getAlignSize = function(k, size)
|
||||
return ((~k) + 1) & (size - 1)
|
||||
end
|
||||
else
|
||||
getAlignSize = function(self, size, additionalBytes)
|
||||
local alignsize = bit32.bnot(#self.bytes-self:Head() + additionalBytes) + 1
|
||||
return bit32.band(alignsize,(size - 1))
|
||||
end
|
||||
end
|
||||
|
||||
m.GetAlignSize = getAlignSize
|
||||
|
||||
return m
|
||||
198
lua/flatbuffers/numTypes.lua
Normal file
198
lua/flatbuffers/numTypes.lua
Normal file
@@ -0,0 +1,198 @@
|
||||
local m = {}
|
||||
|
||||
local ba = require("flatbuffers.binaryarray")
|
||||
|
||||
local bpack = ba.Pack
|
||||
local bunpack = ba.Unpack
|
||||
|
||||
local type_mt = {}
|
||||
|
||||
function type_mt:Pack(value)
|
||||
return bpack(self.packFmt, value)
|
||||
end
|
||||
|
||||
function type_mt:Unpack(buf, pos)
|
||||
return bunpack(self.packFmt, buf, pos)
|
||||
end
|
||||
|
||||
function type_mt:ValidNumber(n)
|
||||
if not self.min_value and not self.max_value then return true end
|
||||
return self.min_value <= n and n <= self.max_value
|
||||
end
|
||||
|
||||
function type_mt:EnforceNumber(n)
|
||||
-- duplicate code since the overhead of function calls
|
||||
-- for such a popular method is time consuming
|
||||
if not self.min_value and not self.max_value then
|
||||
return
|
||||
end
|
||||
|
||||
if self.min_value <= n and n <= self.max_value then
|
||||
return
|
||||
end
|
||||
|
||||
error("Number is not in the valid range")
|
||||
end
|
||||
|
||||
function type_mt:EnforceNumberAndPack(n)
|
||||
return bpack(self.packFmt, n)
|
||||
end
|
||||
|
||||
function type_mt:ConvertType(n, otherType)
|
||||
assert(self.bytewidth == otherType.bytewidth, "Cannot convert between types of different widths")
|
||||
if self == otherType then
|
||||
return n
|
||||
end
|
||||
return otherType:Unpack(self:Pack(n))
|
||||
end
|
||||
|
||||
local bool_mt =
|
||||
{
|
||||
bytewidth = 1,
|
||||
min_value = false,
|
||||
max_value = true,
|
||||
lua_type = type(true),
|
||||
name = "bool",
|
||||
packFmt = "<b"
|
||||
}
|
||||
|
||||
local uint8_mt =
|
||||
{
|
||||
bytewidth = 1,
|
||||
min_value = 0,
|
||||
max_value = 2^8-1,
|
||||
lua_type = type(1),
|
||||
name = "uint8",
|
||||
packFmt = "<I1"
|
||||
}
|
||||
|
||||
local uint16_mt =
|
||||
{
|
||||
bytewidth = 2,
|
||||
min_value = 0,
|
||||
max_value = 2^16-1,
|
||||
lua_type = type(1),
|
||||
name = "uint16",
|
||||
packFmt = "<I2"
|
||||
}
|
||||
|
||||
local uint32_mt =
|
||||
{
|
||||
bytewidth = 4,
|
||||
min_value = 0,
|
||||
max_value = 2^32-1,
|
||||
lua_type = type(1),
|
||||
name = "uint32",
|
||||
packFmt = "<I4"
|
||||
}
|
||||
|
||||
local uint64_mt =
|
||||
{
|
||||
bytewidth = 8,
|
||||
min_value = 0,
|
||||
max_value = 2^64-1,
|
||||
lua_type = type(1),
|
||||
name = "uint64",
|
||||
packFmt = "<I8"
|
||||
}
|
||||
|
||||
local int8_mt =
|
||||
{
|
||||
bytewidth = 1,
|
||||
min_value = -2^7,
|
||||
max_value = 2^7-1,
|
||||
lua_type = type(1),
|
||||
name = "int8",
|
||||
packFmt = "<i1"
|
||||
}
|
||||
|
||||
local int16_mt =
|
||||
{
|
||||
bytewidth = 2,
|
||||
min_value = -2^15,
|
||||
max_value = 2^15-1,
|
||||
lua_type = type(1),
|
||||
name = "int16",
|
||||
packFmt = "<i2"
|
||||
}
|
||||
|
||||
local int32_mt =
|
||||
{
|
||||
bytewidth = 4,
|
||||
min_value = -2^15,
|
||||
max_value = 2^15-1,
|
||||
lua_type = type(1),
|
||||
name = "int32",
|
||||
packFmt = "<i4"
|
||||
}
|
||||
|
||||
local int64_mt =
|
||||
{
|
||||
bytewidth = 8,
|
||||
min_value = -2^63,
|
||||
max_value = 2^63-1,
|
||||
lua_type = type(1),
|
||||
name = "int64",
|
||||
packFmt = "<i8"
|
||||
}
|
||||
|
||||
local float32_mt =
|
||||
{
|
||||
bytewidth = 4,
|
||||
min_value = nil,
|
||||
max_value = nil,
|
||||
lua_type = type(1.0),
|
||||
name = "float32",
|
||||
packFmt = "<f"
|
||||
}
|
||||
|
||||
local float64_mt =
|
||||
{
|
||||
bytewidth = 8,
|
||||
min_value = nil,
|
||||
max_value = nil,
|
||||
lua_type = type(1.0),
|
||||
name = "float64",
|
||||
packFmt = "<d"
|
||||
}
|
||||
|
||||
-- register the base class
|
||||
setmetatable(bool_mt, {__index = type_mt})
|
||||
setmetatable(uint8_mt, {__index = type_mt})
|
||||
setmetatable(uint16_mt, {__index = type_mt})
|
||||
setmetatable(uint32_mt, {__index = type_mt})
|
||||
setmetatable(uint64_mt, {__index = type_mt})
|
||||
setmetatable(int8_mt, {__index = type_mt})
|
||||
setmetatable(int16_mt, {__index = type_mt})
|
||||
setmetatable(int32_mt, {__index = type_mt})
|
||||
setmetatable(int64_mt, {__index = type_mt})
|
||||
setmetatable(float32_mt, {__index = type_mt})
|
||||
setmetatable(float64_mt, {__index = type_mt})
|
||||
|
||||
|
||||
m.Bool = bool_mt
|
||||
m.Uint8 = uint8_mt
|
||||
m.Uint16 = uint16_mt
|
||||
m.Uint32 = uint32_mt
|
||||
m.Uint64 = uint64_mt
|
||||
m.Int8 = int8_mt
|
||||
m.Int16 = int16_mt
|
||||
m.Int32 = int32_mt
|
||||
m.Int64 = int64_mt
|
||||
m.Float32 = float32_mt
|
||||
m.Float64 = float64_mt
|
||||
|
||||
m.UOffsetT = uint32_mt
|
||||
m.VOffsetT = uint16_mt
|
||||
m.SOffsetT = int32_mt
|
||||
|
||||
function GenerateTypes(listOfTypes)
|
||||
for _,t in pairs(listOfTypes) do
|
||||
t.Pack = function(self, value) return bpack(self.packFmt, value) end
|
||||
t.Unpack = function(self, buf, pos) return bunpack(self.packFmt, buf, pos) end
|
||||
end
|
||||
end
|
||||
|
||||
GenerateTypes(m)
|
||||
|
||||
return m
|
||||
97
lua/flatbuffers/view.lua
Normal file
97
lua/flatbuffers/view.lua
Normal file
@@ -0,0 +1,97 @@
|
||||
local m = {}
|
||||
local mt = {}
|
||||
|
||||
local mt_name = "flatbuffers.view.mt"
|
||||
|
||||
local N = require("flatbuffers.numTypes")
|
||||
local binaryarray = require("flatbuffers.binaryarray")
|
||||
|
||||
function m.New(buf, pos)
|
||||
N.UOffsetT:EnforceNumber(pos)
|
||||
|
||||
-- need to convert from a string buffer into
|
||||
-- a binary array
|
||||
|
||||
local o = {
|
||||
bytes = type(buf) == "string" and binaryarray.New(buf) or buf,
|
||||
pos = pos
|
||||
}
|
||||
setmetatable(o, {__index = mt, __metatable = mt_name})
|
||||
return o
|
||||
end
|
||||
|
||||
function mt:Offset(vtableOffset)
|
||||
local vtable = self.pos - self:Get(N.SOffsetT, self.pos)
|
||||
local vtableEnd = self:Get(N.VOffsetT, vtable)
|
||||
if vtableOffset < vtableEnd then
|
||||
return self:Get(N.VOffsetT, vtable + vtableOffset)
|
||||
end
|
||||
return 0
|
||||
end
|
||||
|
||||
function mt:Indirect(off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
return off + N.UOffsetT:Unpack(self.bytes, off)
|
||||
end
|
||||
|
||||
function mt:String(off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
off = off + N.UOffsetT:Unpack(self.bytes, off)
|
||||
local start = off + N.UOffsetT.bytewidth
|
||||
local length = N.UOffsetT:Unpack(self.bytes, off)
|
||||
return self.bytes:Slice(start, start+length)
|
||||
end
|
||||
|
||||
function mt:VectorLen(off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
off = off + self.pos
|
||||
off = off + N.UOffsetT:Unpack(self.bytes, off)
|
||||
return N.UOffsetT:Unpack(self.bytes, off)
|
||||
end
|
||||
|
||||
function mt:Vector(off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
|
||||
off = off + self.pos
|
||||
local x = off + self:Get(N.UOffsetT, off)
|
||||
x = x + N.UOffsetT.bytewidth
|
||||
return x
|
||||
end
|
||||
|
||||
function mt:Union(t2, off)
|
||||
assert(getmetatable(t2) == mt_name)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
|
||||
off = off + self.pos
|
||||
t2.pos = off + self:Get(N.UOffsetT, off)
|
||||
t2.bytes = self.bytes
|
||||
end
|
||||
|
||||
function mt:Get(flags, off)
|
||||
N.UOffsetT:EnforceNumber(off)
|
||||
return flags:Unpack(self.bytes, off)
|
||||
end
|
||||
|
||||
function mt:GetSlot(slot, d, validatorFlags)
|
||||
N.VOffsetT:EnforceNumber(slot)
|
||||
if validatorFlags then
|
||||
validatorFlags:EnforceNumber(d)
|
||||
end
|
||||
local off = self:Offset(slot)
|
||||
if off == 0 then
|
||||
return d
|
||||
end
|
||||
return self:Get(validatorFlags, self.pos + off)
|
||||
end
|
||||
|
||||
function mt:GetVOffsetTSlot(slot, d)
|
||||
N.VOffsetT:EnforceNumber(slot)
|
||||
N.VOffsetT:EnforceNumber(d)
|
||||
local off = self:Offset(slot)
|
||||
if off == 0 then
|
||||
return d
|
||||
end
|
||||
return off
|
||||
end
|
||||
|
||||
return m
|
||||
Reference in New Issue
Block a user