first commit
This commit is contained in:
77
lib/knife/memoize.lua
Normal file
77
lib/knife/memoize.lua
Normal file
@@ -0,0 +1,77 @@
|
||||
local loadstring = _G.loadstring or _G.load
|
||||
local weakKeys = { __mode = 'k' }
|
||||
local cache = setmetatable({}, weakKeys)
|
||||
local resultsKey = {}
|
||||
local nilKey = {}
|
||||
|
||||
local function getMetaCall (callable)
|
||||
local meta = getmetatable(callable)
|
||||
return meta and meta.__call
|
||||
end
|
||||
|
||||
local tupleConstructorCache = {}
|
||||
|
||||
local function buildTupleConstructor (n)
|
||||
if tupleConstructorCache[n] then
|
||||
return tupleConstructorCache[n]
|
||||
end
|
||||
local t = {}
|
||||
for i = 1, n do
|
||||
t[i] = "a" .. i
|
||||
end
|
||||
local args = table.concat(t, ',')
|
||||
local ctor = loadstring('return function(' .. args ..
|
||||
') return function() return ' .. args .. ' end end')()
|
||||
tupleConstructorCache[n] = ctor
|
||||
return ctor
|
||||
end
|
||||
|
||||
local function tuple (...)
|
||||
return buildTupleConstructor(select('#', ...))(...)
|
||||
end
|
||||
|
||||
return function (callable)
|
||||
local metaCall = getMetaCall(callable)
|
||||
|
||||
if type(callable) ~= 'function' and not metaCall then
|
||||
error 'Attempted to memoize a non-callable value.'
|
||||
end
|
||||
|
||||
cache[callable] = setmetatable({}, weakKeys)
|
||||
|
||||
local function run (...)
|
||||
local node = cache[callable]
|
||||
local argc = select('#', ...)
|
||||
for i = 1, argc do
|
||||
local key = select(i, ...)
|
||||
if key == nil then
|
||||
key = nilKey
|
||||
end
|
||||
if not node[key] then
|
||||
node[key] = setmetatable({}, weakKeys)
|
||||
end
|
||||
node = node[key]
|
||||
end
|
||||
|
||||
if not node[resultsKey] then
|
||||
node[resultsKey] = tuple(callable(...))
|
||||
end
|
||||
|
||||
return node[resultsKey]()
|
||||
end
|
||||
|
||||
if metaCall then
|
||||
return function (...)
|
||||
local call = getMetaCall(callable)
|
||||
|
||||
if call ~= metaCall then
|
||||
cache[callable] = setmetatable({}, weakKeys)
|
||||
metaCall = call
|
||||
end
|
||||
|
||||
return run(...)
|
||||
end, cache, resultsKey, nilKey
|
||||
end
|
||||
|
||||
return run, cache, resultsKey, nilKey
|
||||
end
|
||||
Reference in New Issue
Block a user