Files
aux-addon-ClassicAPI/libs/green_t.lua
T
Manuel Simon Hirsig 0c20cf0b27 refactoring
2016-09-06 08:18:39 +02:00

185 lines
4.4 KiB
Lua

green_t = module
--setglobal('green_t', green_t and error(nil) or module)
local next, getn, setn, type, setmetatable = next, getn, table.setn, type, setmetatable
local wipe, release, acquire, acquire_auto
-- TODO mandatory operation table mandate + comply/fulfill functions
local pool, pool_size, overflow_pool, auto_release = {}, 0, setmetatable({}, { __mode='k' }), {}
CreateFrame('Frame'):SetScript('OnUpdate', function()
for t in auto_release do release(t) end
wipe(auto_release)
end)
function wipe(t)
setmetatable(t, nil)
for k in t do t[k] = nil end
t.reset, t.reset = nil, 1
setn(t, 0)
end
public.wipe = wipe
public.init = setmetatable({}, {
__metatable = false,
__newindex = function(_, t, init)
wipe(t)
for k, v in init do
t[k] = v
setn(t, getn(init))
end
end
})
function release(t)
wipe(t)
auto_release[t] = nil
if pool_size < 50 then
pool_size = pool_size + 1
pool[pool_size] = t
else
overflow_pool[t] = true
end
end
public.release = release
function public.ret(t)
if getn(t) > 0 then
return tremove(t, 1), ret(t)
else
release(t)
end
end
function acquire()
if pool_size > 0 then
pool_size = pool_size - 1
return pool[pool_size + 1]
end
local t = next(overflow_pool)
if t then
overflow_pool[t] = nil
return t
end
return {}
end
public.t.get = acquire
function acquire_auto()
local t = acquire()
auto_release[t] = true
return t
end
public.tt.get = acquire_auto
public.empty = setmetatable({}, { __newindex=nop })
do
local function set_auto_release(v, enable)
if type(v) ~= 'table' then return end
auto_release[v] = enable and true or nil
end
public.auto = setmetatable({}, {
__metatable = false,
__newindex = function(_, k, v) set_auto_release(k, v) end,
})
public.temp = setmetatable({}, {
__metatable = false,
__sub = function(_, v) set_auto_release(v, false); return v end,
})
public.perm = setmetatable({}, {
__metatable = false,
__sub = function(_, v) set_auto_release(v, true); return v end,
})
end
local function arg_chunk(k, n)
k = k or 1
n = n or 100
local str = k > n and '' or 'a' .. k
for i = k + 1, n do str = str .. ',a' .. i end
return str
end
function public.pseudo_vararg_function(body, upvals)
local upval_chunk = ''
for k in upvals or empty do
upval_chunk = upval_chunk .. format('local %1$s = %1$s;', k)
end
local f = loadstring(format('%s return function(%s) %s end', upval_chunk, arg_chunk(), body)) or error()
setfenv(f, upvals or empty)
return f()
end
do
local body = [[
if arg100 ~= nil then error("Vararg overflow.") end
local n
repeat
]]
for i = 99, 1, -1 do
body = body .. format('if a%1$d ~= nil then n = %1$d; break end;', i)
end
body = body .. [[
until true
local t = acquire_auto()
setn(t, n)
repeat
]]
for i = 1, 99 do
body = body .. format('if %1$d > n then break end; t[%1$d] = a%1$d;', i)
end
body = body .. [[
until true
return f(t)
]]
function public.vararg(f)
return pseudo_vararg_function(body, {f=f, error=error, setn=setn, acquire=acquire_auto, release=release})
end
end
local function insert_chunk(mode)
local body = 'repeat '
if mode == 'k' then
for i = 2, 99 do
body = body .. format('if a%1$d == nil then break end; a1[a%1$d] = true;', i)
end
elseif mode == 'v' then
body = body .. 'if a2 == nil then break end; a1[1] = a2;'
for i = 3, 99 do
body = body .. format('if a%1$d == nil then setn(a1, %d); break end; a1[%d] = a%1$d;', i, i-2, i-1)
end
elseif mode == 'v0' then
body = body .. 'setn(a1, 98);'
for i = 2, 99 do
body = body .. format('a1[%d] = a%d;', i-1, i)
end
elseif mode == 'kv' then
for i = 2, 98, 2 do
body = body .. format('if a%1$d == nil then break end; a1[a%1$d] = a%d;', i, i+1)
end
end
return body .. 'if a100 ~= nil then error("Vararg overflow.") end until true;'
end
do
local function pseudo_table_literal(mode)
local upvals = {setmetatable=setmetatable, setn=setn, error=error}
local mt = {__call = pseudo_vararg_function(insert_chunk(mode) .. 'setmetatable(a1, nil); return a1', upvals)}
return function() return setmetatable(acquire(), mt) end
end
public.S.get = pseudo_table_literal('k')
public.A.get = pseudo_table_literal('v')
public.A0.get = pseudo_table_literal('v0')
public.T.get = pseudo_table_literal('kv')
end
do
local body = ''
for i = 1, 99 do
body = body .. format('if a1 == %d then return %s end;', i, arg_chunk(i+1, 100))
end
public.select = pseudo_vararg_function(body)
end