Add Lua FlatbufferBuilder Clean() method to enable reuseable builders (#5606)
authorDerek Bailey <dbaileychess@gmail.com>
Mon, 4 Nov 2019 22:27:59 +0000 (14:27 -0800)
committerWouter van Oortmerssen <aardappel@gmail.com>
Mon, 4 Nov 2019 22:27:59 +0000 (14:27 -0800)
lua/flatbuffers/builder.lua
tests/luatest.lua

index 2fb2220..19f214d 100644 (file)
@@ -60,6 +60,23 @@ function m.New(initialSize)
     return o
 end
 
+-- Clears the builder and resets the state. It does not actually clear the backing binary array, it just reuses it as
+-- needed. This is a performant way to use the builder for multiple constructions without the overhead of multiple
+-- builder allocations.
+function mt:Clear()
+    self.finished = false
+    self.nested = false
+    self.minalign = 1
+    self.currentVTable = nil
+    self.objectEnd = nil
+    self.head = #self.bytes -- place the head at the end of the binary array
+
+    -- clear vtables instead of making a new table
+    local vtable = self.vtables
+    local vtableCount = #vtable
+    for i=1,vtableCount do vtable[i] = nil end
+end
+
 function mt:Output(full)
     assert(self.finished, "Builder Not Finished")
     if full then
index c85a4ec..04f185e 100644 (file)
@@ -81,8 +81,8 @@ local function checkReadBuffer(buf, offset, sizePrefix)
     assert(mon:Testempty() == nil)
 end
 
-local function generateMonster(sizePrefix)
-    local b = flatbuffers.Builder(0)
+local function generateMonster(sizePrefix, b)
+    b = b or flatbuffers.Builder(0)
     local str = b:CreateString("MyMonster")
     local test1 = b:CreateString("test1")
     local test2 = b:CreateString("test2")
@@ -156,6 +156,51 @@ local function sizePrefix(sizePrefix)
     checkReadBuffer(buf, offset, sizePrefix)
 end
 
+local function fbbClear()
+    -- Generate a builder that will be 'cleared' and reused to create two different objects.
+    local fbb = flatbuffers.Builder(0)
+
+    -- First use the builder to read the normal monster data and verify it works
+    local buf, offset = generateMonster(false, fbb)
+    checkReadBuffer(buf, offset, false)
+
+    -- Then clear the builder to be used again
+    fbb:Clear()
+
+    -- Storage for the built monsters
+    local monsters = {}
+    local lastBuf
+
+    -- Make another builder that will be use identically to the 'cleared' one so outputs can be compared. Build both the
+    -- Cleared builder and new builder in the exact same way, so we can compare their results
+    for i, builder in ipairs({fbb, flatbuffers.Builder(0)}) do
+        local strOffset = builder:CreateString("Hi there")
+        monster.Start(builder)
+        monster.AddPos(builder, vec3.CreateVec3(builder, 3.0, 2.0, 1.0, 17.0, 3, 100, 123))
+        monster.AddName(builder, strOffset)
+        monster.AddMana(builder, 123)
+        builder:Finish(monster.End(builder))
+        local buf = builder:Output(false)
+        if not lastBuf then
+            lastBuf = buf
+        else
+            -- the output, sized-buffer should be identical
+            assert(lastBuf == buf, "Monster output buffers are not identical")
+        end
+        monsters[i] = monster.GetRootAsMonster(flatbuffers.binaryArray.New(buf), 0)
+    end
+
+    -- Check that all the fields for the generated monsters are as we expect
+    for i, monster in ipairs(monsters) do
+        assert(monster:Name() == "Hi there", "Monster Name is not 'Hi There' for monster "..i)
+        -- HP is default to 100 in the schema, but we change it in generateMonster to 80, so this is a good test to
+        -- see if the cleared builder really clears the data.
+        assert(monster:Hp() == 100, "HP doesn't equal the default value for monster "..i)
+        assert(monster:Mana() == 123, "Monster Mana is not '123' for monster "..i)
+        assert(monster:Pos():X() == 3.0, "Monster vec3.X is not '3' for monster "..i)
+    end
+end
+
 local function testCanonicalData()
     local f = assert(io.open('monsterdata_test.mon', 'rb'))
     local wireData = f:read("*a")
@@ -219,6 +264,10 @@ local tests =
         d = "Test size prefix",
         args = {{true}, {false}}
     },
+    {
+        f = fbbClear,
+        d = "FlatBufferBuilder Clear",
+    },
     {   
         f = testCanonicalData, 
         d = "Tests Canonical flatbuffer file included in repo"