From 44c5285f28ef4584f8236e109557551d69c8c5a6 Mon Sep 17 00:00:00 2001 From: Joachim Stolberg Date: Sat, 30 Jun 2018 13:48:48 +0200 Subject: [PATCH] data structures improvements --- safer_lua/data_struct.lua | 201 +++++++++++++++++++++++++------------- safer_lua/scanner.lua | 2 + sl_controller/server.lua | 31 ++++-- 3 files changed, 155 insertions(+), 79 deletions(-) diff --git a/safer_lua/data_struct.lua b/safer_lua/data_struct.lua index bb9fdd2..4584254 100644 --- a/safer_lua/data_struct.lua +++ b/safer_lua/data_struct.lua @@ -27,7 +27,7 @@ safer_lua.DataStructHelp = [[ a.insert(5,7) --> {1,8,3,4,7,6} a.remove(3) --> {1,8,4,7,6} a.insert(1, "hello") --> {"hello",1,8,4,7,6} - a.size() --> function returns 10 + a.size() --> function returns 6 Unlike arrays, which are indexed by a range of numbers, 'stores' are indexed by keys: @@ -37,7 +37,7 @@ safer_lua.DataStructHelp = [[ s.get("val") --> returns 12 s.set(0, "hello") --> {val = 12, [0] = "hello"} s.del("val") --> {[0] = "hello"} - s.size() --> function returns 6 + s.size() --> function returns 1 A 'set' is an unordered collection with no duplicate elements. @@ -48,7 +48,7 @@ safer_lua.DataStructHelp = [[ s.add("Susi") --> {Lucy = true, Susi = true} s.has("Susi") --> function returns `true` s.has("Mike") --> function returns `false` - s.size() --> function returns 11 + s.size() --> function returns 2 ]] local function var_count(v) @@ -61,7 +61,7 @@ local function var_count(v) elseif type(v) == "string" then return #v elseif type(v) == "table" then - return v.size() + return v.memsize() else return nil end @@ -70,11 +70,12 @@ end function safer_lua.Store() - local new_t = {__data__ = {}} + local new_t = {} local mt = {} - -- `all` will represent the number of both - local Count = 0 + local MemSize = 0 + local Size = 0 + local Data = {} mt.__newindex = function(t, k, v) return end @@ -82,39 +83,55 @@ function safer_lua.Store() new_t.set = function(k,v) if type(k) == "number" then - Count = Count - mt.count(rawget(new_t.__data__, k)) - Count = Count + mt.count(v) - rawset(new_t.__data__,k,v) - elseif type(k) == "string" then - if rawget(new_t.__data__, k) then -- has entry? - Count = Count - mt.count(rawget(new_t.__data__, k)) + if rawget(Data, k) then -- has entry? + MemSize = MemSize - mt.count(rawget(Data, k)) else - Count = Count + mt.count(k) + Size = Size + 1 end - Count = Count + mt.count(v) - rawset(new_t.__data__,k,v) + MemSize = MemSize + mt.count(v) + rawset(Data, k, v) + elseif type(k) == "string" then + if rawget(Data, k) then -- has entry? + MemSize = MemSize - mt.count(rawget(Data, k)) + else + MemSize = MemSize + mt.count(k) + Size = Size + 1 + end + MemSize = MemSize + mt.count(v) + rawset(Data, k, v) end end new_t.get = function(k) - return rawget(new_t.__data__, k) + return rawget(Data, k) end new_t.del = function(k) - Count = Count - mt.count(k) - Count = Count - mt.count(rawget(new_t.__data__, k)) - rawset(new_t.__data__,k,nil) + if rawget(Data, k) then -- has entry? + MemSize = MemSize - mt.count(k) + MemSize = MemSize - mt.count(rawget(Data, k)) + rawset(Data, k, nil) + Size = Size - 1 + end end - new_t.size = function(t) - return Count + new_t.memsize = function(t) + return MemSize end - new_t.dump = function(size) - size = size or 200 - local s = dump(new_t.__data__) - if #s > size then s = s:sub(1, size).."..." end - return s + new_t.size = function(t) + return Size + end + + new_t.__dump = function() + -- remove the not serializable meta data + return {Type = "Store", Size = Size, MemSize = MemSize, Data = Data} + end + + new_t.__load = function(size, memsize, data) + Size = size + MemSize = memsize + Data = data end return setmetatable(new_t, mt) @@ -123,11 +140,11 @@ end function safer_lua.Array(...) - local new_t = {__data__ = {}} + local new_t = {} local mt = {} - -- `all` will represent the number of both - local Count = 0 + local MemSize = 0 + local Data = {} mt.__newindex = function(t, k, v) return end @@ -137,45 +154,56 @@ function safer_lua.Array(...) local v = select(idx,...) local cnt = mt.count(v) if cnt then - Count = Count + cnt - rawset(new_t.__data__,idx, v) + MemSize = MemSize + cnt + rawset(Data, idx, v) end end new_t.add = function(v) - Count = Count + mt.count(v) - local i = #new_t.__data__ + 1 - table.insert(new_t.__data__,i,v) + MemSize = MemSize + mt.count(v) + local i = #Data + 1 + table.insert(Data, i, v) end new_t.set = function(i,v) - i = math.min(#new_t.__data__, i) - Count = Count - mt.count(rawget(new_t.__data__, i)) - Count = Count + mt.count(v) - rawset(new_t.__data__,i,v) + i = math.min(#Data, i) + MemSize = MemSize - mt.count(rawget(Data, i)) + MemSize = MemSize + mt.count(v) + rawset(Data, i, v) + end + + new_t.get = function(i) + return Data[i] end new_t.insert = function(i, v) - Count = Count + mt.count(v) - i = math.min(#new_t.__data__, i) - table.insert(new_t.__data__,i,v) + MemSize = MemSize + mt.count(v) + i = math.min(#Data, i) + table.insert(Data, i, v) end new_t.remove = function(i) - local v = table.remove(new_t.__data__,i) - Count = Count - mt.count(v) + local v = table.remove(Data, i) + MemSize = MemSize - mt.count(v) return v end - new_t.size = function(t) - return Count + new_t.memsize = function(t) + return MemSize end - new_t.dump = function(size) - size = size or 200 - local s = dump(new_t.__data__) - if #s > size then s = s:sub(1, size).."..." end - return s + new_t.size = function(t) + return #Data + end + + new_t.__dump = function() + -- remove the not serializable meta data + return {Type = "Array", MemSize = MemSize, Data = Data} + end + + new_t.__load = function(memsize, data) + MemSize = memsize + Data = data end return setmetatable(new_t, mt) @@ -184,11 +212,12 @@ end function safer_lua.Set(...) - local new_t = {__data__ = {}} + local new_t = {} local mt = {} - -- `all` will represent the number of both - local Count = 0 + local MemSize = 0 + local Size = 0 + local Data = {} mt.__newindex = function(t, k, v) return end @@ -198,35 +227,69 @@ function safer_lua.Set(...) local v = select(idx,...) local cnt = mt.count(v) if cnt then - Count = Count + cnt - rawset(new_t.__data__,v, true) + MemSize = MemSize + cnt + Size = Size + 1 + rawset(Data, v, true) end end new_t.add = function(k) - Count = Count + mt.count(k) - rawset(new_t.__data__,k, true) + MemSize = MemSize + mt.count(k) + rawset(Data, k, true) + Size = Size + 1 end new_t.del = function(k) - Count = Count - mt.count(k) - rawset(new_t.__data__,k, nil) + MemSize = MemSize - mt.count(k) + rawset(Data, k, nil) + Size = Size - 1 end new_t.has = function(k) - return rawget(new_t.__data__, k) == true + return rawget(Data, k) == true end - new_t.size = function(t) - return Count + new_t.memsize = function(t) + return MemSize end - new_t.dump = function(size) - size = size or 200 - local s = dump(new_t.__data__) - if #s > size then s = s:sub(1, size).."..." end - return s + new_t.size = function(t) + return Size end - + + new_t.__dump = function() + -- remove the not serializable meta data + return {Type = "Set", Size = Size, MemSize = MemSize, Data = Data} + end + + new_t.__load = function(size, memsize, data) + Size = size + MemSize = memsize + Data = data + end + return setmetatable(new_t, mt) end + + +-- remove the not serializable meta data +function safer_lua.datastruct_to_table(ds) + return ds.__dump() +end + +-- add the not serializable meta data again +function safer_lua.table_to_datastruct(tbl) + if tbl.Type == "Store" then + local s = safer_lua.Store() + s.__load(tbl.Size, tbl.MemSize, tbl.Data) + return s + elseif tbl.Type == "Set" then + local s = safer_lua.Set() + s.__load(tbl.Size, tbl.MemSize, tbl.Data) + return s + elseif tbl.Type == "Array" then + local a = safer_lua.Array() + a.__load(tbl.MemSize, tbl.Data) + return a + end +end \ No newline at end of file diff --git a/safer_lua/scanner.lua b/safer_lua/scanner.lua index 5676034..22460f4 100644 --- a/safer_lua/scanner.lua +++ b/safer_lua/scanner.lua @@ -81,6 +81,8 @@ local InvalidKeywords = { ["do"] = true, ["function"] = true, ["_G"] = true, + ["__load"] = true, + ["__dump"] = true, } local InvalidChars = { diff --git a/sl_controller/server.lua b/sl_controller/server.lua index be549ae..81d8daa 100644 --- a/sl_controller/server.lua +++ b/sl_controller/server.lua @@ -105,23 +105,34 @@ local function calc_size(v) return 0 elseif type(v) == "string" then return #v + elseif v.MemSize then + return v.MemSize else return nil end end -local function write_value(mem, key, value) +local function write_value(mem, key, item) if mem and mem.size < SERVER_CAPA then - if value == nil then + if mem.data[key] then mem.size = mem.size - calc_size(mem.data[key]) - else - mem.size = mem.size - calc_size(mem.data[key]) - mem.size = mem.size + calc_size(value) end - mem.data[key] = value + if type(item) == "table" then + item = safer_lua.datastruct_to_table(item) + end + mem.size = mem.size + calc_size(item) + mem.data[key] = item end end +local function read_value(mem, key) + local item = mem.data[key] + if type(item) == "table" then + item = safer_lua.table_to_datastruct(item) + end + return item +end + tubelib.register_node("sl_controller:server", {}, { on_recv_message = function(pos, topic, payload) local meta = minetest.get_meta(pos) @@ -129,7 +140,7 @@ tubelib.register_node("sl_controller:server", {}, { local number = meta:get_string("number") local mem = tubelib.get_data(number, "memory") or DEFAULT_MEM if topic == "read" then - return mem.data[payload] + return read_value(mem, payload) elseif topic == "write" then write_value(mem, payload.key, payload.value) tubelib.set_data(number, "memory", mem) @@ -157,7 +168,7 @@ sl_controller.register_function("server_read", { sl_controller.register_action("server_write", { cmnd = function(self, num, key, value) - if type(key) == "string" and type(value) == "string" or type(value) == "number" then + if type(key) == "string" then tubelib.send_message(num, self.meta.owner, nil, "write", {key=key, value=value}) else self.error("Invalid server_write parameter") @@ -165,8 +176,8 @@ sl_controller.register_action("server_write", { end, help = " $server_write(num, key, value)\n".. " Store a value on the server under the key 'key'.\n".. - " 'key' must be a string. 'value' can be\n".. - " either a number or a string.\n".. + " 'key' must be a string. 'value' can be either a\n".. + " number, string, boolean, nil or data structure.\n".. ' example: $server_write("0123", "state", state)' })