data structures improvements

This commit is contained in:
Joachim Stolberg 2018-06-30 13:48:48 +02:00
parent b6325f9078
commit 44c5285f28
3 changed files with 155 additions and 79 deletions

@ -27,7 +27,7 @@ safer_lua.DataStructHelp = [[
a.insert(5,7) --> {1,8,3,4,7,6} a.insert(5,7) --> {1,8,3,4,7,6}
a.remove(3) --> {1,8,4,7,6} a.remove(3) --> {1,8,4,7,6}
a.insert(1, "hello") --> {"hello",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, Unlike arrays, which are indexed by a range of numbers,
'stores' are indexed by keys: 'stores' are indexed by keys:
@ -37,7 +37,7 @@ safer_lua.DataStructHelp = [[
s.get("val") --> returns 12 s.get("val") --> returns 12
s.set(0, "hello") --> {val = 12, [0] = "hello"} s.set(0, "hello") --> {val = 12, [0] = "hello"}
s.del("val") --> {[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 A 'set' is an unordered collection with no duplicate
elements. elements.
@ -48,7 +48,7 @@ safer_lua.DataStructHelp = [[
s.add("Susi") --> {Lucy = true, Susi = true} s.add("Susi") --> {Lucy = true, Susi = true}
s.has("Susi") --> function returns `true` s.has("Susi") --> function returns `true`
s.has("Mike") --> function returns `false` s.has("Mike") --> function returns `false`
s.size() --> function returns 11 s.size() --> function returns 2
]] ]]
local function var_count(v) local function var_count(v)
@ -61,7 +61,7 @@ local function var_count(v)
elseif type(v) == "string" then elseif type(v) == "string" then
return #v return #v
elseif type(v) == "table" then elseif type(v) == "table" then
return v.size() return v.memsize()
else else
return nil return nil
end end
@ -70,11 +70,12 @@ end
function safer_lua.Store() function safer_lua.Store()
local new_t = {__data__ = {}} local new_t = {}
local mt = {} local mt = {}
-- `all` will represent the number of both local MemSize = 0
local Count = 0 local Size = 0
local Data = {}
mt.__newindex = function(t, k, v) return end mt.__newindex = function(t, k, v) return end
@ -82,39 +83,55 @@ function safer_lua.Store()
new_t.set = function(k,v) new_t.set = function(k,v)
if type(k) == "number" then if type(k) == "number" then
Count = Count - mt.count(rawget(new_t.__data__, k)) if rawget(Data, k) then -- has entry?
Count = Count + mt.count(v) MemSize = MemSize - mt.count(rawget(Data, k))
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))
else else
Count = Count + mt.count(k) Size = Size + 1
end end
Count = Count + mt.count(v) MemSize = MemSize + mt.count(v)
rawset(new_t.__data__,k,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
end end
new_t.get = function(k) new_t.get = function(k)
return rawget(new_t.__data__, k) return rawget(Data, k)
end end
new_t.del = function(k) new_t.del = function(k)
Count = Count - mt.count(k) if rawget(Data, k) then -- has entry?
Count = Count - mt.count(rawget(new_t.__data__, k)) MemSize = MemSize - mt.count(k)
rawset(new_t.__data__,k,nil) MemSize = MemSize - mt.count(rawget(Data, k))
rawset(Data, k, nil)
Size = Size - 1
end
end end
new_t.size = function(t) new_t.memsize = function(t)
return Count return MemSize
end end
new_t.dump = function(size) new_t.size = function(t)
size = size or 200 return Size
local s = dump(new_t.__data__) end
if #s > size then s = s:sub(1, size).."..." end
return s 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 end
return setmetatable(new_t, mt) return setmetatable(new_t, mt)
@ -123,11 +140,11 @@ end
function safer_lua.Array(...) function safer_lua.Array(...)
local new_t = {__data__ = {}} local new_t = {}
local mt = {} local mt = {}
-- `all` will represent the number of both local MemSize = 0
local Count = 0 local Data = {}
mt.__newindex = function(t, k, v) return end mt.__newindex = function(t, k, v) return end
@ -137,45 +154,56 @@ function safer_lua.Array(...)
local v = select(idx,...) local v = select(idx,...)
local cnt = mt.count(v) local cnt = mt.count(v)
if cnt then if cnt then
Count = Count + cnt MemSize = MemSize + cnt
rawset(new_t.__data__,idx, v) rawset(Data, idx, v)
end end
end end
new_t.add = function(v) new_t.add = function(v)
Count = Count + mt.count(v) MemSize = MemSize + mt.count(v)
local i = #new_t.__data__ + 1 local i = #Data + 1
table.insert(new_t.__data__,i,v) table.insert(Data, i, v)
end end
new_t.set = function(i,v) new_t.set = function(i,v)
i = math.min(#new_t.__data__, i) i = math.min(#Data, i)
Count = Count - mt.count(rawget(new_t.__data__, i)) MemSize = MemSize - mt.count(rawget(Data, i))
Count = Count + mt.count(v) MemSize = MemSize + mt.count(v)
rawset(new_t.__data__,i,v) rawset(Data, i, v)
end
new_t.get = function(i)
return Data[i]
end end
new_t.insert = function(i, v) new_t.insert = function(i, v)
Count = Count + mt.count(v) MemSize = MemSize + mt.count(v)
i = math.min(#new_t.__data__, i) i = math.min(#Data, i)
table.insert(new_t.__data__,i,v) table.insert(Data, i, v)
end end
new_t.remove = function(i) new_t.remove = function(i)
local v = table.remove(new_t.__data__,i) local v = table.remove(Data, i)
Count = Count - mt.count(v) MemSize = MemSize - mt.count(v)
return v return v
end end
new_t.size = function(t) new_t.memsize = function(t)
return Count return MemSize
end end
new_t.dump = function(size) new_t.size = function(t)
size = size or 200 return #Data
local s = dump(new_t.__data__) end
if #s > size then s = s:sub(1, size).."..." end
return s 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 end
return setmetatable(new_t, mt) return setmetatable(new_t, mt)
@ -184,11 +212,12 @@ end
function safer_lua.Set(...) function safer_lua.Set(...)
local new_t = {__data__ = {}} local new_t = {}
local mt = {} local mt = {}
-- `all` will represent the number of both local MemSize = 0
local Count = 0 local Size = 0
local Data = {}
mt.__newindex = function(t, k, v) return end mt.__newindex = function(t, k, v) return end
@ -198,35 +227,69 @@ function safer_lua.Set(...)
local v = select(idx,...) local v = select(idx,...)
local cnt = mt.count(v) local cnt = mt.count(v)
if cnt then if cnt then
Count = Count + cnt MemSize = MemSize + cnt
rawset(new_t.__data__,v, true) Size = Size + 1
rawset(Data, v, true)
end end
end end
new_t.add = function(k) new_t.add = function(k)
Count = Count + mt.count(k) MemSize = MemSize + mt.count(k)
rawset(new_t.__data__,k, true) rawset(Data, k, true)
Size = Size + 1
end end
new_t.del = function(k) new_t.del = function(k)
Count = Count - mt.count(k) MemSize = MemSize - mt.count(k)
rawset(new_t.__data__,k, nil) rawset(Data, k, nil)
Size = Size - 1
end end
new_t.has = function(k) new_t.has = function(k)
return rawget(new_t.__data__, k) == true return rawget(Data, k) == true
end end
new_t.size = function(t) new_t.memsize = function(t)
return Count return MemSize
end end
new_t.dump = function(size) new_t.size = function(t)
size = size or 200 return Size
local s = dump(new_t.__data__)
if #s > size then s = s:sub(1, size).."..." end
return s
end 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) return setmetatable(new_t, mt)
end 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

@ -81,6 +81,8 @@ local InvalidKeywords = {
["do"] = true, ["do"] = true,
["function"] = true, ["function"] = true,
["_G"] = true, ["_G"] = true,
["__load"] = true,
["__dump"] = true,
} }
local InvalidChars = { local InvalidChars = {

@ -105,23 +105,34 @@ local function calc_size(v)
return 0 return 0
elseif type(v) == "string" then elseif type(v) == "string" then
return #v return #v
elseif v.MemSize then
return v.MemSize
else else
return nil return nil
end end
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 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]) 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 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
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", {}, { tubelib.register_node("sl_controller:server", {}, {
on_recv_message = function(pos, topic, payload) on_recv_message = function(pos, topic, payload)
local meta = minetest.get_meta(pos) local meta = minetest.get_meta(pos)
@ -129,7 +140,7 @@ tubelib.register_node("sl_controller:server", {}, {
local number = meta:get_string("number") local number = meta:get_string("number")
local mem = tubelib.get_data(number, "memory") or DEFAULT_MEM local mem = tubelib.get_data(number, "memory") or DEFAULT_MEM
if topic == "read" then if topic == "read" then
return mem.data[payload] return read_value(mem, payload)
elseif topic == "write" then elseif topic == "write" then
write_value(mem, payload.key, payload.value) write_value(mem, payload.key, payload.value)
tubelib.set_data(number, "memory", mem) tubelib.set_data(number, "memory", mem)
@ -157,7 +168,7 @@ sl_controller.register_function("server_read", {
sl_controller.register_action("server_write", { sl_controller.register_action("server_write", {
cmnd = function(self, num, key, value) 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}) tubelib.send_message(num, self.meta.owner, nil, "write", {key=key, value=value})
else else
self.error("Invalid server_write parameter") self.error("Invalid server_write parameter")
@ -165,8 +176,8 @@ sl_controller.register_action("server_write", {
end, end,
help = " $server_write(num, key, value)\n".. help = " $server_write(num, key, value)\n"..
" Store a value on the server under the key 'key'.\n".. " Store a value on the server under the key 'key'.\n"..
" 'key' must be a string. 'value' can be\n".. " 'key' must be a string. 'value' can be either a\n"..
" either a number or a string.\n".. " number, string, boolean, nil or data structure.\n"..
' example: $server_write("0123", "state", state)' ' example: $server_write("0123", "state", state)'
}) })