neovim

Neovim text editor
git clone https://git.dasho.dev/neovim.git
Log | Files | Refs | README

_memoize.lua (2027B)


      1 --- Module for private utility functions
      2 
      3 --- @alias vim.func.MemoObj { _hash: (fun(...): any), _weak: boolean?, _cache: table<any> }
      4 
      5 --- @param argc integer?
      6 --- @return fun(...): any
      7 local function concat_hash(argc)
      8  return function(...)
      9    return table.concat({ ... }, '%%', 1, argc)
     10  end
     11 end
     12 
     13 --- @param idx integer
     14 --- @return fun(...): any
     15 local function idx_hash(idx)
     16  return function(...)
     17    return select(idx, ...)
     18  end
     19 end
     20 
     21 --- @param hash integer|string|fun(...): any
     22 --- @return fun(...): any
     23 local function resolve_hash(hash)
     24  if type(hash) == 'number' then
     25    hash = idx_hash(hash)
     26  elseif type(hash) == 'string' then
     27    local c = hash == 'concat' or hash:match('^concat%-(%d+)')
     28    if c then
     29      hash = concat_hash(tonumber(c))
     30    else
     31      error('invalid value for hash: ' .. hash)
     32    end
     33  end
     34  --- @cast hash -integer
     35  return hash
     36 end
     37 
     38 --- @param weak boolean?
     39 --- @return table
     40 local create_cache = function(weak)
     41  return setmetatable({}, {
     42    __mode = weak ~= false and 'kv',
     43  })
     44 end
     45 
     46 --- @generic F: function
     47 --- @param hash integer|string|fun(...): any
     48 --- @param fn F
     49 --- @param weak? boolean
     50 --- @return F
     51 return function(hash, fn, weak)
     52  vim.validate('hash', hash, { 'number', 'string', 'function' })
     53  vim.validate('fn', fn, 'function')
     54  vim.validate('weak', weak, 'boolean', true)
     55 
     56  --- @type vim.func.MemoObj
     57  local obj = {
     58    _cache = create_cache(weak),
     59    _hash = resolve_hash(hash),
     60    _weak = weak,
     61    --- @param self vim.func.MemoObj
     62    clear = function(self, ...)
     63      if select('#', ...) == 0 then
     64        self._cache = create_cache(self._weak)
     65        return
     66      end
     67      local key = self._hash(...)
     68      self._cache[key] = nil
     69    end,
     70  }
     71 
     72  return setmetatable(obj, {
     73    --- @param self vim.func.MemoObj
     74    __call = function(self, ...)
     75      local key = self._hash(...)
     76      local cache = self._cache
     77      if cache[key] == nil then
     78        cache[key] = vim.F.pack_len(fn(...))
     79      end
     80      return vim.F.unpack_len(cache[key])
     81    end,
     82  })
     83 end