local function concat_hash(argc)
return function(...)
return table.concat({ ... }, '%%', 1, argc)
end
end
local function idx_hash(idx)
return function(...)
return select(idx, ...)
end
end
local function resolve_hash(hash)
if type(hash) == 'number' then
hash = idx_hash(hash)
elseif type(hash) == 'string' then
local c = hash == 'concat' or hash:match('^concat%-(%d+)')
if c then
hash = concat_hash(tonumber(c))
else
error('invalid value for hash: ' .. hash)
end
end
return hash
end
local create_cache = function(weak)
return setmetatable({}, {
__mode = weak ~= false and 'kv',
})
end
return function(hash, fn, weak)
vim.validate('hash', hash, { 'number', 'string', 'function' })
vim.validate('fn', fn, 'function')
vim.validate('weak', weak, 'boolean', true)
local obj = {
_cache = create_cache(weak),
_hash = resolve_hash(hash),
_weak = weak,
clear = function(self, ...)
if select('#', ...) == 0 then
self._cache = create_cache(self._weak)
return
end
local key = self._hash(...)
self._cache[key] = nil
end,
}
return setmetatable(obj, {
__call = function(self, ...)
local key = self._hash(...)
local cache = self._cache
if cache[key] == nil then
cache[key] = vim.F.pack_len(fn(...))
end
return vim.F.unpack_len(cache[key])
end,
})
end