_memoize.lua 2.0 KB

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