Skip to content
Permalink
fd2485af82
Go to file
 
 
Cannot retrieve contributors at this time
220 lines (199 sloc) 5.97 KB
--- table utility
-- @module tabutil
-- @alias tab
local tab = {}
--- print the contents of a table
-- @tparam table t table to print
tab.print = function(t)
for k,v in pairs(t) do print(k .. '\t' .. tostring(v)) end
end
--- return a lexigraphically sorted array of keys for a table
-- @tparam table t table to sort
-- @treturn table sorted table
tab.sort = function(t)
local keys = {}
for k in pairs(t) do table.insert(keys, k) end
table.sort(keys)
return keys
end
--- count the number of entries in a table;
-- unlike table.getn() or #table, nil entries won't break the loop
-- @tparam table t table to count
-- @treturn number count
tab.count = function(t)
local c = 0
for _ in pairs(t) do c = c + 1 end
return c
end
--- search table for element
-- @tparam table t table to check
-- @param e element to look for
-- @treturn boolean t/f is element is present
tab.contains = function(t,e)
for index, value in ipairs(t) do
if value == e then return true end
end
return false
end
--- search table for element, return key
-- @tparam table t table to check
-- @param e element to look for
-- @return key, nil if not found
tab.key = function(t,e)
for index, value in ipairs(t) do
if value == e then return index end
end
return nil
end
--- split multi-line string into table of strings
-- @tparam string str string with line breaks
-- @treturn table table with entries for each line
tab.lines = function(str)
local t = {}
local function helper(line)
table.insert(t, line)
return ""
end
helper((str:gsub("(.-)\r?\n", helper)))
return t
end
--- split string into table with delimiter
-- @tparam string inputstr : string to split
-- @tparam string sep : delimiter
tab.split = function(inputstr, sep)
if sep == nil then
sep = "%s"
end
local t={}
for str in string.gmatch(inputstr, "([^"..sep.."]+)") do
table.insert(t, str)
end
return t
end
--- Save a table to disk.
-- Saves tables, numbers, booleans and strings.
-- Inside table references are saved.
-- Does not save userdata, metatables, functions and indices of these.
-- Based on http://lua-users.org/wiki/SaveTableToFile by ChillCode.
-- @tparam table tbl Table to save.
-- @tparam string filename Location to save to.
-- @return On failure, returns an error msg.
function tab.save(tbl, filename)
local charS, charE = " ", "\n"
local file, err = io.open(filename, "wb")
if err then return err end
-- initiate variables for save procedure
local tables, lookup = { tbl }, { [tbl] = 1 }
file:write("return {"..charE)
for idx, t in ipairs(tables) do
file:write("-- Table: {"..idx.."}"..charE)
file:write("{"..charE)
local thandled = {}
for i, v in ipairs(t) do
thandled[i] = true
local stype = type(v)
-- only handle value
if stype == "table" then
if not lookup[v] then
table.insert(tables, v)
lookup[v] = #tables
end
file:write(charS.."{"..lookup[v].."},"..charE)
elseif stype == "string" then
file:write(charS..string.format("%q", v)..","..charE)
elseif stype == "number" then
file:write(charS..tostring(v)..","..charE)
elseif stype == "boolean" then
file:write(charS..tostring(v)..","..charE)
end
end
for i, v in pairs(t) do
-- escape handled values
if (not thandled[i]) then
local str = ""
local stype = type(i)
-- handle index
if stype == "table" then
if not lookup[i] then
table.insert(tables, i)
lookup[i] = #tables
end
str = charS.."[{"..lookup[i].."}]="
elseif stype == "string" then
str = charS.."["..string.format("%q", i).."]="
elseif stype == "number" then
str = charS.."["..tostring(i).."]="
elseif stype == "boolean" then
str = charS.."["..tostring(i).."]="
end
if str ~= "" then
stype = type(v)
-- handle value
if stype == "table" then
if not lookup[v] then
table.insert(tables, v)
lookup[v] = #tables
end
file:write(str.."{"..lookup[v].."},"..charE)
elseif stype == "string" then
file:write(str..string.format("%q", v)..","..charE)
elseif stype == "number" then
file:write(str..tostring(v)..","..charE)
elseif stype == "boolean" then
file:write(str..tostring(v)..","..charE)
end
end
end
end
file:write("},"..charE)
end
file:write("}")
file:close()
end
--- Load a table that has been saved via the tab.save() function.
-- @tparam string sfile Filename or stringtable to load.
-- @return On success, returns a previously saved table. On failure, returns as second argument an error msg.
function tab.load(sfile)
local ftables,err = loadfile(sfile)
if err then return _, err end
local tables = ftables()
for idx = 1, #tables do
local tolinki = {}
for i, v in pairs(tables[idx]) do
if type(v) == "table" then
tables[idx][i] = tables[v[1]]
end
if type(i) == "table" and tables[i[1]] then
table.insert(tolinki, { i, tables[i[1]] })
end
end
-- link indices
for _, v in ipairs(tolinki) do
tables[idx][v[2]], tables[idx][v[1]] = tables[idx][v[1]], nil
end
end
return tables[1]
end
--- Create a read-only proxy for a given table.
-- @param params params.table is the table to proxy, params.except a list of writable keys
-- @treturn table the proxied read-only table
function tab.readonly(params)
local t = params.table
local exceptions = params.except or {}
local proxy = {}
local mt = {
__index = t,
__newindex = function (_,k,v)
if (tab.contains(exceptions, k)) then
t[k] = v
else
error("'"..k.."', a read-only key, cannot be re-assigned.")
end
end,
__pairs = function (_) return pairs(proxy) end,
__ipairs = function (_) return ipairs(proxy) end,
}
setmetatable(proxy, mt)
return proxy
end
return tab