techpack/safer_lua/data_struct.lua

233 lines
4.9 KiB
Lua

--[[
SaferLua [safer_lua]
====================
Copyright (C) 2018 Joachim Stolberg
LGPLv2.1+
See LICENSE.txt for more information
data_struct.lua:
see https://github.com/joe7575/techpack/wiki/Data-Structures
]]--
safer_lua.DataStructHelp = [[
Data structures as a secure shell over the LUA table type.
see https://github.com/joe7575/techpack/wiki/Data-Structures
'Arrays' are lists of elements, which can be addressed
by means of an index:
a = Array(1,2,3,4) --> {1,2,3,4}
a.add(6) --> {1,2,3,4,6}
a.set(2, 8) --> {1,8,3,4,6}
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
Unlike arrays, which are indexed by a range of numbers,
'stores' are indexed by keys:
s = Store() --> {}
s.set("val", 12) --> {val = 12}
s.get("val") --> returns 12
s.set(0, "hello") --> {val = 12, [0] = "hello"}
s.del("val") --> {[0] = "hello"}
s.size() --> function returns 6
A 'set' is an unordered collection with no duplicate
elements.
s = Set("Tom", "Lucy")
--> {Tom = true, Lucy = true}
s.del("Tom") --> {Lucy = true}
s.add("Susi") --> {Lucy = true, Susi = true}
s.has("Susi") --> function returns `true`
s.has("Mike") --> function returns `false`
s.size() --> function returns 11
]]
local function var_count(v)
if type(v) == "number" then
return 1
elseif type(v) == "boolean" then
return 1
elseif v == nil then
return 0
elseif type(v) == "string" then
return #v
elseif type(v) == "table" then
return v.size()
else
return nil
end
end
function safer_lua.Store()
local new_t = {__data__ = {}}
local mt = {}
-- `all` will represent the number of both
local Count = 0
mt.__newindex = function(t, k, v) return end
mt.count = var_count
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))
else
Count = Count + mt.count(k)
end
Count = Count + mt.count(v)
rawset(new_t.__data__,k,v)
end
end
new_t.get = function(k)
return rawget(new_t.__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)
end
new_t.size = function(t)
return Count
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
end
return setmetatable(new_t, mt)
end
function safer_lua.Array(...)
local new_t = {__data__ = {}}
local mt = {}
-- `all` will represent the number of both
local Count = 0
mt.__newindex = function(t, k, v) return end
mt.count = var_count
for idx = 1,select('#',...) do
local v = select(idx,...)
local cnt = mt.count(v)
if cnt then
Count = Count + cnt
rawset(new_t.__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)
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)
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)
end
new_t.remove = function(i)
local v = table.remove(new_t.__data__,i)
Count = Count - mt.count(v)
return v
end
new_t.size = function(t)
return Count
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
end
return setmetatable(new_t, mt)
end
function safer_lua.Set(...)
local new_t = {__data__ = {}}
local mt = {}
-- `all` will represent the number of both
local Count = 0
mt.__newindex = function(t, k, v) return end
mt.count = var_count
for idx = 1,select('#',...) do
local v = select(idx,...)
local cnt = mt.count(v)
if cnt then
Count = Count + cnt
rawset(new_t.__data__,v, true)
end
end
new_t.add = function(k)
Count = Count + mt.count(k)
rawset(new_t.__data__,k, true)
end
new_t.del = function(k)
Count = Count - mt.count(k)
rawset(new_t.__data__,k, nil)
end
new_t.has = function(k)
return rawget(new_t.__data__, k) == true
end
new_t.size = function(t)
return Count
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
end
return setmetatable(new_t, mt)
end