From 4525cd9c5609f41e6f82f219a8dfef89d73e207e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BD=97=E6=B3=BD=E8=BD=A9?= Date: Sat, 8 May 2021 13:57:13 +0800 Subject: [PATCH] [Lua] manipulate byte array as string (#6624) * [Lua] manipulate byte array as string Sometimes it would be more effective than reading byte by byte * change according to the review * update --- lua/flatbuffers/view.lua | 11 ++++++++ src/idl_gen_lua.cpp | 16 ++++++++++++ tests/MyGame/Example/Monster.lua | 15 +++++++++++ tests/MyGame/Example/TypeAliases.lua | 3 +++ tests/luatest.lua | 39 ++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+) diff --git a/lua/flatbuffers/view.lua b/lua/flatbuffers/view.lua index 105e967d3..433f25c85 100644 --- a/lua/flatbuffers/view.lua +++ b/lua/flatbuffers/view.lua @@ -76,6 +76,17 @@ function mt:Vector(off) return off + self:Get(N.UOffsetT, off) + 4 end +function mt:VectorAsString(off, start, stop) + local o = self:Offset(off) + if o ~= 0 then + start = start or 1 + stop = stop or self:VectorLen(o) + local a = self:Vector(o) + start - 1 + return self.bytes:Slice(a, a + stop - start + 1) + end + return nil +end + function mt:Union(t2, off) assert(getmetatable(t2) == mt_name) enforceOffset(off) diff --git a/src/idl_gen_lua.cpp b/src/idl_gen_lua.cpp index e7e78343d..9efc435e2 100644 --- a/src/idl_gen_lua.cpp +++ b/src/idl_gen_lua.cpp @@ -339,6 +339,18 @@ class LuaGenerator : public BaseGenerator { code += EndFunc; } + // Access a byte/ubyte vector as a string + void AccessByteVectorAsString(const StructDef &struct_def, + const FieldDef &field, std::string *code_ptr) { + std::string &code = *code_ptr; + GenReceiver(struct_def, code_ptr); + code += MakeCamel(NormalizedName(field)); + code += "AsString(start, stop)\n"; + code += std::string(Indent) + "return " + SelfData + ":VectorAsString(" + + NumToString(field.value.offset) + ", start, stop)\n"; + code += EndFunc; + } + // Begin the creator function signature. void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) { std::string &code = *code_ptr; @@ -499,6 +511,10 @@ class LuaGenerator : public BaseGenerator { GetMemberOfVectorOfStruct(struct_def, field, code_ptr); } else { GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr); + if (vectortype.base_type == BASE_TYPE_CHAR || + vectortype.base_type == BASE_TYPE_UCHAR) { + AccessByteVectorAsString(struct_def, field, code_ptr); + } } break; } diff --git a/tests/MyGame/Example/Monster.lua b/tests/MyGame/Example/Monster.lua index fbd2c74ea..26b59d3b0 100644 --- a/tests/MyGame/Example/Monster.lua +++ b/tests/MyGame/Example/Monster.lua @@ -62,6 +62,9 @@ function Monster_mt:Inventory(j) end return 0 end +function Monster_mt:InventoryAsString(start, stop) + return self.view:VectorAsString(14, start, stop) +end function Monster_mt:InventoryLength() local o = self.view:Offset(14) if o ~= 0 then @@ -160,6 +163,9 @@ function Monster_mt:Testnestedflatbuffer(j) end return 0 end +function Monster_mt:TestnestedflatbufferAsString(start, stop) + return self.view:VectorAsString(30, start, stop) +end function Monster_mt:TestnestedflatbufferLength() local o = self.view:Offset(30) if o ~= 0 then @@ -315,6 +321,9 @@ function Monster_mt:Flex(j) end return 0 end +function Monster_mt:FlexAsString(start, stop) + return self.view:VectorAsString(64, start, stop) +end function Monster_mt:FlexLength() local o = self.view:Offset(64) if o ~= 0 then @@ -518,6 +527,9 @@ function Monster_mt:VectorOfEnums(j) end return 0 end +function Monster_mt:VectorOfEnumsAsString(start, stop) + return self.view:VectorAsString(98, start, stop) +end function Monster_mt:VectorOfEnumsLength() local o = self.view:Offset(98) if o ~= 0 then @@ -540,6 +552,9 @@ function Monster_mt:Testrequirednestedflatbuffer(j) end return 0 end +function Monster_mt:TestrequirednestedflatbufferAsString(start, stop) + return self.view:VectorAsString(102, start, stop) +end function Monster_mt:TestrequirednestedflatbufferLength() local o = self.view:Offset(102) if o ~= 0 then diff --git a/tests/MyGame/Example/TypeAliases.lua b/tests/MyGame/Example/TypeAliases.lua index 91c62c449..e9c680b1d 100644 --- a/tests/MyGame/Example/TypeAliases.lua +++ b/tests/MyGame/Example/TypeAliases.lua @@ -102,6 +102,9 @@ function TypeAliases_mt:V8(j) end return 0 end +function TypeAliases_mt:V8AsString(start, stop) + return self.view:VectorAsString(24, start, stop) +end function TypeAliases_mt:V8Length() local o = self.view:Offset(24) if o ~= 0 then diff --git a/tests/luatest.lua b/tests/luatest.lua index 26b0a98de..1a70f5ff4 100644 --- a/tests/luatest.lua +++ b/tests/luatest.lua @@ -282,6 +282,41 @@ local function getRootAs_canAcceptString() assert(mon:Hp() == 80, "Monster Hp is not 80") end +local function testAccessByteVectorAsString() + local f = assert(io.open('monsterdata_test.mon', 'rb')) + local wireData = f:read("*a") + f:close() + local mon = monster.GetRootAsMonster(wireData, 0) + -- the data of byte array Inventory is [0, 1, 2, 3, 4] + local s = mon:InventoryAsString(1, 3) + assert(#s == 3) + for i = 1, #s do + assert(string.byte(s, i) == i - 1) + end + + local s = mon:InventoryAsString(2, 5) + assert(#s == 4) + for i = 1, #s do + assert(string.byte(s, i) == i) + end + + local s = mon:InventoryAsString(5, 5) + assert(#s == 1) + assert(string.byte(s, 1) == 4) + + local s = mon:InventoryAsString(2) + assert(#s == 4) + for i = 1, #s do + assert(string.byte(s, i) == i) + end + + local s = mon:InventoryAsString() + assert(#s == 5) + for i = 1, #s do + assert(string.byte(s, i) == i - 1) + end +end + local tests = { { @@ -305,6 +340,10 @@ local tests = f = getRootAs_canAcceptString, d = "Tests that GetRootAs() generated methods accept strings" }, + { + f = testAccessByteVectorAsString, + d = "Access byte vector as string" + }, } local benchmarks =