From ee229c4cb8b72d7d69c7283a9817a601d37e22b7 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 19 Oct 2012 22:11:40 +0200 Subject: update util-tab --- lualibs-util-dim.lua | 2 +- lualibs-util-lua.lua | 234 ++++++++++++++++++++++++++++ lualibs-util-mrg.lua | 2 +- lualibs-util-sto.lua | 172 +++++++++++++++++++++ lualibs-util-tab.lua | 427 +++++++++++++++++++++++++++------------------------ 5 files changed, 635 insertions(+), 202 deletions(-) create mode 100644 lualibs-util-lua.lua create mode 100644 lualibs-util-sto.lua diff --git a/lualibs-util-dim.lua b/lualibs-util-dim.lua index d77bd49..4bae2d0 100644 --- a/lualibs-util-dim.lua +++ b/lualibs-util-dim.lua @@ -1,4 +1,4 @@ -if not modules then modules = { } end modules ['l-dimen'] = { +if not modules then modules = { } end modules ['util-dim'] = { version = 1.001, comment = "support for dimensions", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", diff --git a/lualibs-util-lua.lua b/lualibs-util-lua.lua new file mode 100644 index 0000000..2baeaa8 --- /dev/null +++ b/lualibs-util-lua.lua @@ -0,0 +1,234 @@ +if not modules then modules = { } end modules ['util-lua'] = { + version = 1.001, + comment = "companion to luat-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + comment = "the strip code is written by Peter Cawley", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local rep, sub, byte, dump, format = string.rep, string.sub, string.byte, string.dump, string.format +local loadstring, loadfile, type = loadstring, loadfile, type + +utilities = utilities or {} +utilities.lua = utilities.lua or { } +local luautilities = utilities.lua + +utilities.report = logs and logs.reporter("system") or print -- can be overloaded later + +local tracestripping = false +local forcestupidcompile = true -- use internal bytecode compiler +luautilities.stripcode = true -- support stripping when asked for +luautilities.alwaysstripcode = false -- saves 1 meg on 7 meg compressed format file (2012.08.12) +luautilities.nofstrippedchunks = 0 +luautilities.nofstrippedbytes = 0 + +-- The next function was posted by Peter Cawley on the lua list and strips line +-- number information etc. from the bytecode data blob. We only apply this trick +-- when we store data tables. Stripping makes the compressed format file about +-- 1MB smaller (and uncompressed we save at least 6MB). +-- +-- You can consider this feature an experiment, so it might disappear. There is +-- no noticeable gain in runtime although the memory footprint should be somewhat +-- smaller (and the file system has a bit less to deal with). +-- +-- Begin of borrowed code ... works for Lua 5.1 which LuaTeX currently uses ... + +local function strip_code_pc(dump,name) + local before = #dump + local version, format, endian, int, size, ins, num = byte(dump,5,11) + local subint + if endian == 1 then + subint = function(dump, i, l) + local val = 0 + for n = l, 1, -1 do + val = val * 256 + byte(dump,i + n - 1) + end + return val, i + l + end + else + subint = function(dump, i, l) + local val = 0 + for n = 1, l, 1 do + val = val * 256 + byte(dump,i + n - 1) + end + return val, i + l + end + end + local strip_function + strip_function = function(dump) + local count, offset = subint(dump, 1, size) + local stripped, dirty = rep("\0", size), offset + count + offset = offset + count + int * 2 + 4 + offset = offset + int + subint(dump, offset, int) * ins + count, offset = subint(dump, offset, int) + for n = 1, count do + local t + t, offset = subint(dump, offset, 1) + if t == 1 then + offset = offset + 1 + elseif t == 4 then + offset = offset + size + subint(dump, offset, size) + elseif t == 3 then + offset = offset + num + end + end + count, offset = subint(dump, offset, int) + stripped = stripped .. sub(dump,dirty, offset - 1) + for n = 1, count do + local proto, off = strip_function(sub(dump,offset, -1)) + stripped, offset = stripped .. proto, offset + off - 1 + end + offset = offset + subint(dump, offset, int) * int + int + count, offset = subint(dump, offset, int) + for n = 1, count do + offset = offset + subint(dump, offset, size) + size + int * 2 + end + count, offset = subint(dump, offset, int) + for n = 1, count do + offset = offset + subint(dump, offset, size) + size + end + stripped = stripped .. rep("\0", int * 3) + return stripped, offset + end + dump = sub(dump,1,12) .. strip_function(sub(dump,13,-1)) + local after = #dump + local delta = before-after + if tracestripping then + utilities.report("stripped bytecode: %s, before %s, after %s, delta %s",name or "unknown",before,after,delta) + end + luautilities.nofstrippedchunks = luautilities.nofstrippedchunks + 1 + luautilities.nofstrippedbytes = luautilities.nofstrippedbytes + delta + return dump, delta +end + +-- ... end of borrowed code. + +local function strippedbytecode(code,forcestrip,name) + if (forcestrip and luautilities.stripcode) or luautilities.alwaysstripcode then + return strip_code_pc(code,name) + else + return code, 0 + end +end + +luautilities.stripbytecode = strip_code_pc +luautilities.strippedbytecode = strippedbytecode + +local function fatalerror(name) + utilities.report(format("fatal error in %q",name or "unknown")) +end + +-- quite subtle ... doing this wrong incidentally can give more bytes + + +function luautilities.loadedluacode(fullname,forcestrip,name) + -- quite subtle ... doing this wrong incidentally can give more bytes + name = name or fullname + local code = loadfile(fullname) + if code then + code() + end + if forcestrip and luautilities.stripcode then + if type(forcestrip) == "function" then + forcestrip = forcestrip(fullname) + end + if forcestrip then + local code, n = strip_code_pc(dump(code,name)) + return loadstring(code), n + elseif luautilities.alwaysstripcode then + return loadstring(strip_code_pc(dump(code),name)) + else + return code, 0 + end + elseif luautilities.alwaysstripcode then + return loadstring(strip_code_pc(dump(code),name)) + else + return code, 0 + end +end + +function luautilities.strippedloadstring(code,forcestrip,name) -- not executed + local n = 0 + if (forcestrip and luautilities.stripcode) or luautilities.alwaysstripcode then + code = loadstring(code) + if not code then + fatalerror(name) + end + code, n = strip_code_pc(dump(code),name) + end + return loadstring(code), n +end + +local function stupidcompile(luafile,lucfile,strip) + local code = io.loaddata(luafile) + local n = 0 + if code and code ~= "" then + code = loadstring(code) + if not code then + fatalerror() + end + code = dump(code) + if strip then + code, n = strippedbytecode(code,true,luafile) -- last one is reported + end + if code and code ~= "" then + io.savedata(lucfile,code) + end + end + return n +end + +local luac_normal = "texluac -o %q %q" +local luac_strip = "texluac -s -o %q %q" + +function luautilities.compile(luafile,lucfile,cleanup,strip,fallback) -- defaults: cleanup=false strip=true + utilities.report("lua: compiling %s into %s",luafile,lucfile) + os.remove(lucfile) + local done = false + if strip ~= false then + strip = true + end + if forcestupidcompile then + fallback = true + elseif strip then + done = os.spawn(format(luac_strip, lucfile,luafile)) == 0 + else + done = os.spawn(format(luac_normal,lucfile,luafile)) == 0 + end + if not done and fallback then + local n = stupidcompile(luafile,lucfile,strip) + if n > 0 then + utilities.report("lua: %s dumped into %s (%i bytes stripped)",luafile,lucfile,n) + else + utilities.report("lua: %s dumped into %s (unstripped)",luafile,lucfile) + end + cleanup = false -- better see how bad it is + end + if done and cleanup == true and lfs.isfile(lucfile) and lfs.isfile(luafile) then + utilities.report("lua: removing %s",luafile) + os.remove(luafile) + end + return done +end +--~ local getmetatable, type = getmetatable, type + +--~ local types = { } + +--~ function luautilities.registerdatatype(d,name) +--~ types[getmetatable(d)] = name +--~ end + +--~ function luautilities.datatype(d) +--~ local t = type(d) +--~ if t == "userdata" then +--~ local m = getmetatable(d) +--~ return m and types[m] or "userdata" +--~ else +--~ return t +--~ end +--~ end + +--~ luautilities.registerdatatype(lpeg.P("!"),"lpeg") + +--~ print(luautilities.datatype(lpeg.P("oeps"))) diff --git a/lualibs-util-mrg.lua b/lualibs-util-mrg.lua index d59745b..8d6c5dd 100644 --- a/lualibs-util-mrg.lua +++ b/lualibs-util-mrg.lua @@ -1,4 +1,4 @@ -if not modules then modules = { } end modules ['l-utils'] = { +if not modules then modules = { } end modules ['util-mrg'] = { version = 1.001, comment = "companion to luat-lib.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", diff --git a/lualibs-util-sto.lua b/lualibs-util-sto.lua new file mode 100644 index 0000000..42ee6cf --- /dev/null +++ b/lualibs-util-sto.lua @@ -0,0 +1,172 @@ +if not modules then modules = { } end modules ['util-sto'] = { + version = 1.001, + comment = "companion to luat-lib.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +local setmetatable, getmetatable = setmetatable, getmetatable + +utilities = utilities or { } +utilities.storage = utilities.storage or { } +local storage = utilities.storage + +function storage.mark(t) + if not t then + texio.write_nl("fatal error: storage cannot be marked") + return -- os.exit() + end + local m = getmetatable(t) + if not m then + m = { } + setmetatable(t,m) + end + m.__storage__ = true + return t +end + +function storage.allocate(t) + t = t or { } + local m = getmetatable(t) + if not m then + m = { } + setmetatable(t,m) + end + m.__storage__ = true + return t +end + +function storage.marked(t) + local m = getmetatable(t) + return m and m.__storage__ +end + +function storage.checked(t) + if not t then + texio.write_nl("fatal error: storage has not been allocated") + return -- os.exit() + end + return t +end + +--~ function utilities.storage.delay(parent,name,filename) +--~ local m = getmetatable(parent) +--~ m.__list[name] = filename +--~ end +--~ +--~ function utilities.storage.predefine(parent) +--~ local list = { } +--~ local m = getmetatable(parent) or { +--~ __list = list, +--~ __index = function(t,k) +--~ local l = require(list[k]) +--~ t[k] = l +--~ return l +--~ end +--~ } +--~ setmetatable(parent,m) +--~ end +--~ +--~ bla = { } +--~ utilities.storage.predefine(bla) +--~ utilities.storage.delay(bla,"test","oepsoeps") +--~ local t = bla.test +--~ table.print(t) +--~ print(t.a) + +function storage.setinitializer(data,initialize) + local m = getmetatable(data) or { } + m.__index = function(data,k) + m.__index = nil -- so that we can access the entries during initializing + initialize() + return data[k] + end + setmetatable(data, m) +end + +local keyisvalue = { __index = function(t,k) + t[k] = k + return k +end } + +function storage.sparse(t) + t = t or { } + setmetatable(t,keyisvalue) + return t +end + +-- table namespace ? + +local function f_empty () return "" end -- t,k +local function f_self (t,k) t[k] = k return k end +local function f_ignore() end -- t,k,v + +local t_empty = { __index = f_empty } +local t_self = { __index = f_self } +local t_ignore = { __newindex = f_ignore } + +function table.setmetatableindex(t,f) + local m = getmetatable(t) + if m then + if f == "empty" then + m.__index = f_empty + elseif f == "key" then + m.__index = f_self + else + m.__index = f + end + else + if f == "empty" then + setmetatable(t, t_empty) + elseif f == "key" then + setmetatable(t, t_self) + else + setmetatable(t,{ __index = f }) + end + end + return t +end + +function table.setmetatablenewindex(t,f) + local m = getmetatable(t) + if m then + if f == "ignore" then + m.__newindex = f_ignore + else + m.__newindex = f + end + else + if f == "ignore" then + setmetatable(t, t_ignore) + else + setmetatable(t,{ __newindex = f }) + end + end + return t +end + +function table.setmetatablecall(t,f) + local m = getmetatable(t) + if m then + m.__call = f + else + setmetatable(t,{ __call = f }) + end + return t +end + +function table.setmetatablekey(t,key,value) + local m = getmetatable(t) + if not m then + m = { } + setmetatable(t,m) + end + m[key] = value + return t +end + +function table.getmetatablekey(t,key,value) + local m = getmetatable(t) + return m and m[key] +end diff --git a/lualibs-util-tab.lua b/lualibs-util-tab.lua index 7950a03..7a2da29 100644 --- a/lualibs-util-tab.lua +++ b/lualibs-util-tab.lua @@ -1,4 +1,4 @@ -if not modules then modules = { } end modules ['l-aux'] = { +if not modules then modules = { } end modules ['util-tab'] = { version = 1.001, comment = "companion to luat-lib.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", @@ -6,252 +6,279 @@ if not modules then modules = { } end modules ['l-aux'] = { license = "see context related readme files" } --- for inline, no store split : for s in string.gmatch(str,",* *([^,]+)") do .. end +utilities = utilities or {} +utilities.tables = utilities.tables or { } +local tables = utilities.tables -aux = aux or { } +local format, gmatch, rep, gsub = string.format, string.gmatch, string.rep, string.gsub +local concat, insert, remove = table.concat, table.insert, table.remove +local setmetatable, getmetatable, tonumber, tostring = setmetatable, getmetatable, tonumber, tostring +local type, next, rawset, tonumber, loadstring = type, next, rawset, tonumber, loadstring +local lpegmatch, P, Cs = lpeg.match, lpeg.P, lpeg.Cs -local concat, format, gmatch = table.concat, string.format, string.gmatch -local tostring, type = tostring, type -local lpegmatch = lpeg.match - -local P, R, V = lpeg.P, lpeg.R, lpeg.V - -local escape, left, right = P("\\"), P('{'), P('}') - -lpeg.patterns.balanced = P { - [1] = ((escape * (left+right)) + (1 - (left+right)) + V(2))^0, - [2] = left * V(1) * right -} - -local space = lpeg.P(' ') -local equal = lpeg.P("=") -local comma = lpeg.P(",") -local lbrace = lpeg.P("{") -local rbrace = lpeg.P("}") -local nobrace = 1 - (lbrace+rbrace) -local nested = lpeg.P { lbrace * (nobrace + lpeg.V(1))^0 * rbrace } -local spaces = space^0 - -local value = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0) - -local key = lpeg.C((1-equal-comma)^1) -local pattern_a = (space+comma)^0 * (key * equal * value + key * lpeg.C("")) -local pattern_c = (space+comma)^0 * (key * equal * value) - -local key = lpeg.C((1-space-equal-comma)^1) -local pattern_b = spaces * comma^0 * spaces * (key * ((spaces * equal * spaces * value) + lpeg.C(""))) - --- "a=1, b=2, c=3, d={a{b,c}d}, e=12345, f=xx{a{b,c}d}xx, g={}" : outer {} removes, leading spaces ignored - -local hash = { } - -local function set(key,value) -- using Carg is slower here - hash[key] = value +function tables.definetable(target) -- defines undefined tables + local composed, t, n = nil, { }, 0 + for name in gmatch(target,"([^%.]+)") do + n = n + 1 + if composed then + composed = composed .. "." .. name + else + composed = name + end + t[n] = format("%s = %s or { }",composed,composed) + end + return concat(t,"\n") end -local pattern_a_s = (pattern_a/set)^1 -local pattern_b_s = (pattern_b/set)^1 -local pattern_c_s = (pattern_c/set)^1 - -aux.settings_to_hash_pattern_a = pattern_a_s -aux.settings_to_hash_pattern_b = pattern_b_s -aux.settings_to_hash_pattern_c = pattern_c_s - -function aux.make_settings_to_hash_pattern(set,how) - if how == "strict" then - return (pattern_c/set)^1 - elseif how == "tolerant" then - return (pattern_b/set)^1 - else - return (pattern_a/set)^1 +function tables.accesstable(target,root) + local t = root or _G + for name in gmatch(target,"([^%.]+)") do + t = t[name] + if not t then + return + end end + return t end -function aux.settings_to_hash(str,existing) - if str and str ~= "" then - hash = existing or { } - if moretolerant then - lpegmatch(pattern_b_s,str) - else - lpegmatch(pattern_a_s,str) +function tables.migratetable(target,v,root) + local t = root or _G + local names = string.split(target,".") + for i=1,#names-1 do + local name = names[i] + t[name] = t[name] or { } + t = t[name] + if not t then + return end - return hash - else - return { } end + t[names[#names]] = v end -function aux.settings_to_hash_tolerant(str,existing) - if str and str ~= "" then - hash = existing or { } - lpegmatch(pattern_b_s,str) - return hash - else - return { } +function tables.removevalue(t,value) -- todo: n + if value then + for i=1,#t do + if t[i] == value then + remove(t,i) + -- remove all, so no: return + end + end end end -function aux.settings_to_hash_strict(str,existing) - if str and str ~= "" then - hash = existing or { } - lpegmatch(pattern_c_s,str) - return next(hash) and hash - else - return nil +function tables.insertbeforevalue(t,value,extra) + for i=1,#t do + if t[i] == extra then + remove(t,i) + end + end + for i=1,#t do + if t[i] == value then + insert(t,i,extra) + return + end end + insert(t,1,extra) end -local separator = comma * space^0 -local value = lpeg.P(lbrace * lpeg.C((nobrace + nested)^0) * rbrace) + lpeg.C((nested + (1-comma))^0) -local pattern = lpeg.Ct(value*(separator*value)^0) - --- "aap, {noot}, mies" : outer {} removes, leading spaces ignored - -aux.settings_to_array_pattern = pattern - --- we could use a weak table as cache +function tables.insertaftervalue(t,value,extra) + for i=1,#t do + if t[i] == extra then + remove(t,i) + end + end + for i=1,#t do + if t[i] == value then + insert(t,i+1,extra) + return + end + end + insert(t,#t+1,extra) +end -function aux.settings_to_array(str) - if not str or str == "" then - return { } - else - return lpegmatch(pattern,str) +-- experimental + +local function toxml(t,d,result,step) + for k, v in table.sortedpairs(t) do + if type(v) == "table" then + if type(k) == "number" then + result[#result+1] = format("%s",d,k) + toxml(v,d..step,result,step) + result[#result+1] = format("%s",d,k) + else + result[#result+1] = format("%s<%s>",d,k) + toxml(v,d..step,result,step) + result[#result+1] = format("%s",d,k) + end + elseif type(k) == "number" then + result[#result+1] = format("%s%s",d,k,v,k) + else + result[#result+1] = format("%s<%s>%s",d,k,tostring(v),k) + end end end -local function set(t,v) - t[#t+1] = v +function table.toxml(t,name,nobanner,indent,spaces) + local noroot = name == false + local result = (nobanner or noroot) and { } or { "" } + local indent = rep(" ",indent or 0) + local spaces = rep(" ",spaces or 1) + if noroot then + toxml( t, inndent, result, spaces) + else + toxml( { [name or "root"] = t }, indent, result, spaces) + end + return concat(result,"\n") end -local value = lpeg.P(lpeg.Carg(1)*value) / set -local pattern = value*(separator*value)^0 * lpeg.Carg(1) +-- also experimental -function aux.add_settings_to_array(t,str) - return lpegmatch(pattern,str,nil,t) -end +-- encapsulate(table,utilities.tables) +-- encapsulate(table,utilities.tables,true) +-- encapsulate(table,true) -function aux.hash_to_string(h,separator,yes,no,strict,omit) - if h then - local t, s = { }, table.sortedkeys(h) - omit = omit and table.tohash(omit) - for i=1,#s do - local key = s[i] - if not omit or not omit[key] then - local value = h[key] - if type(value) == "boolean" then - if yes and no then - if value then - t[#t+1] = key .. '=' .. yes - elseif not strict then - t[#t+1] = key .. '=' .. no - end - elseif value or not strict then - t[#t+1] = key .. '=' .. tostring(value) - end +function tables.encapsulate(core,capsule,protect) + if type(capsule) ~= "table" then + protect = true + capsule = { } + end + for key, value in next, core do + if capsule[key] then + print(format("\ninvalid inheritance '%s' in '%s': %s",key,tostring(core))) + os.exit() + else + capsule[key] = value + end + end + if protect then + for key, value in next, core do + core[key] = nil + end + setmetatable(core, { + __index = capsule, + __newindex = function(t,key,value) + if capsule[key] then + print(format("\ninvalid overload '%s' in '%s'",key,tostring(core))) + os.exit() else - t[#t+1] = key .. '=' .. value + rawset(t,key,value) end end - end - return concat(t,separator or ",") - else - return "" + } ) end end -function aux.array_to_string(a,separator) - if a then - return concat(a,separator or ",") +local function serialize(t,r,outer) -- no mixes + r[#r+1] = "{" + local n = #t + if n > 0 then + for i=1,n do + local v = t[i] + local tv = type(v) + if tv == "string" then + r[#r+1] = format("%q,",v) + elseif tv == "number" then + r[#r+1] = format("%s,",v) + elseif tv == "table" then + serialize(v,r) + elseif tv == "boolean" then + r[#r+1] = format("%s,",tostring(v)) + end + end else - return "" + for k, v in next, t do + local tv = type(v) + if tv == "string" then + r[#r+1] = format("[%q]=%q,",k,v) + elseif tv == "number" then + r[#r+1] = format("[%q]=%s,",k,v) + elseif tv == "table" then + r[#r+1] = format("[%q]=",k) + serialize(v,r) + elseif tv == "boolean" then + r[#r+1] = format("[%q]=%s,",k,tostring(v)) + end + end end -end - -function aux.settings_to_set(str,t) - t = t or { } - for s in gmatch(str,"%s*([^,]+)") do - t[s] = true + if outer then + r[#r+1] = "}" + else + r[#r+1] = "}," end - return t + return r end -local value = lbrace * lpeg.C((nobrace + nested)^0) * rbrace -local pattern = lpeg.Ct((space + value)^0) - -function aux.arguments_to_table(str) - return lpegmatch(pattern,str) +function table.fastserialize(t,prefix) + return concat(serialize(t,{ prefix or "return" },true)) end --- temporary here - -function aux.getparameters(self,class,parentclass,settings) - local sc = self[class] - if not sc then - sc = table.clone(self[parent]) - self[class] = sc +function table.deserialize(str) + if not str or str == "" then + return + end + local code = loadstring(str) + if not code then + return end - aux.settings_to_hash(settings,sc) + code = code() + if not code then + return + end + return code end --- temporary here - -local digit = lpeg.R("09") -local period = lpeg.P(".") -local zero = lpeg.P("0") -local trailingzeros = zero^0 * -digit -- suggested by Roberto R -local case_1 = period * trailingzeros / "" -local case_2 = period * (digit - trailingzeros)^1 * (trailingzeros / "") -local number = digit^1 * (case_1 + case_2) -local stripper = lpeg.Cs((number + 1)^0) - ---~ local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100" ---~ collectgarbage("collect") ---~ str = string.rep(sample,10000) ---~ local ts = os.clock() ---~ lpegmatch(stripper,str) ---~ print(#str, os.clock()-ts, lpegmatch(stripper,sample)) - -lpeg.patterns.strip_zeros = stripper - -function aux.strip_zeros(str) - return lpegmatch(stripper,str) +-- inspect(table.fastserialize { a = 1, b = { 4, { 5, 6 } }, c = { d = 7, e = 'f"g\nh' } }) + +function table.load(filename) + if filename then + local t = io.loaddata(filename) + if t and t ~= "" then + t = loadstring(t) + if type(t) == "function" then + t = t() + if type(t) == "table" then + return t + end + end + end + end end -function aux.definetable(target) -- defines undefined tables - local composed, t = nil, { } - for name in gmatch(target,"([^%.]+)") do - if composed then - composed = composed .. "." .. name - else - composed = name +local function slowdrop(t) + local r = { } + local l = { } + for i=1,#t do + local ti = t[i] + local j = 0 + for k, v in next, ti do + j = j + 1 + l[j] = format("%s=%q",k,v) end - t[#t+1] = format("%s = %s or { }",composed,composed) + r[i] = format(" {%s},\n",concat(l)) end - return concat(t,"\n") + return format("return {\n%s}",concat(r)) end -function aux.accesstable(target) - local t = _G - for name in gmatch(target,"([^%.]+)") do - t = t[name] +local function fastdrop(t) + local r = { "return {\n" } + for i=1,#t do + local ti = t[i] + r[#r+1] = " {" + for k, v in next, ti do + r[#r+1] = format("%s=%q",k,v) + end + r[#r+1] = "},\n" end - return t + r[#r+1] = "}" + return concat(r) end --- as we use this a lot ... - ---~ function aux.cachefunction(action,weak) ---~ local cache = { } ---~ if weak then ---~ setmetatable(cache, { __mode = "kv" } ) ---~ end ---~ local function reminder(str) ---~ local found = cache[str] ---~ if not found then ---~ found = action(str) ---~ cache[str] = found ---~ end ---~ return found ---~ end ---~ return reminder, cache ---~ end +function table.drop(t,slow) + if #t == 0 then + return "return { }" + elseif slow == true then + return slowdrop(t) -- less memory + else + return fastdrop(t) -- some 15% faster + end +end -- cgit v1.2.3