Files
neovim/test/functional/lua/list_spec.lua
Yi Ming 97de5f145a perf(lua): memoize key_fn results #39568
Problem:
When using `vim.list.unique` or `vim.list.bisect`, if the `key` function is
complex, it can degrade performance, because it is invoked on every comparison

Solution:
The `key` interface convention is designed specifically to address this issue;
performance can be improved by memoizing its results.

Also added the shorthand use of the field name string as the key.
2026-05-05 17:04:11 -04:00

74 lines
2.4 KiB
Lua

-- Test suite for vim.list
local t = require('test.testutil')
local eq = t.eq
describe('vim.list', function()
it('vim.list.unique()', function()
eq({ 1, 2, 3, 4, 5 }, vim.list.unique({ 1, 2, 2, 3, 4, 4, 5 }))
eq({ 1, 2, 3, 4, 5 }, vim.list.unique({ 1, 2, 3, 4, 4, 5, 1, 2, 3, 2, 1, 2, 3, 4, 5 }))
eq({ 1, 2, 3, 4, 5, field = 1 }, vim.list.unique({ 1, 2, 2, 3, 4, 4, 5, field = 1 }))
-- Not properly defined, but test anyway
-- luajit evaluates #t as 7, whereas Lua 5.1 evaluates it as 12
local r = vim.list.unique({ 1, 2, 2, 3, 4, 4, 5, nil, 6, 6, 7, 7 })
if jit then
eq({ 1, 2, 3, 4, 5, nil, nil, nil, 6, 6, 7, 7 }, r)
else
eq({ 1, 2, 3, 4, 5, nil, 6, 7 }, r)
end
eq(
{ { 1 }, { 2 }, { 3 } },
vim.list.unique({ { 1 }, { 1 }, { 2 }, { 2 }, { 3 }, { 3 } }, function(x)
return x[1]
end)
)
eq({ { id = 1 }, { id = 2 } }, vim.list.unique({ { id = 1 }, { id = 2 }, { id = 1 } }, 'id'))
end)
--- Generate a list like { 1, 2, 2, 3, 3, 3, 4, 4, 4, 4, ...}.
---@param num integer
local function gen_list(num)
---@type integer[]
local list = {}
for i = 1, num do
for _ = 1, i do
list[#list + 1] = i
end
end
return list
end
--- Index of the last {num}.
--- Mathematically, a triangular number.
---@param num integer
local function index(num)
return math.floor((math.pow(num, 2) + num) / 2)
end
it("vim.list.bisect(..., { bound = 'lower' })", function()
local num = math.random(100)
local list = gen_list(num)
local target = math.random(num)
eq(vim.list.bisect(list, target, { bound = 'lower' }), index(target - 1) + 1)
eq(vim.list.bisect(list, num + 1, { bound = 'lower' }), index(num) + 1)
local dict_list = { { value = 1 }, { value = 2 }, { value = 2 }, { value = 3 } }
eq(2, vim.list.bisect(dict_list, { value = 2 }, { key = 'value', bound = 'lower' }))
end)
it("vim.list.bisect(..., bound = { 'upper' })", function()
local num = math.random(100)
local list = gen_list(num)
local target = math.random(num)
eq(vim.list.bisect(list, target, { bound = 'upper' }), index(target) + 1)
eq(vim.list.bisect(list, num + 1, { bound = 'upper' }), index(num) + 1)
local dict_list = { { value = 1 }, { value = 2 }, { value = 2 }, { value = 3 } }
eq(4, vim.list.bisect(dict_list, { value = 2 }, { key = 'value', bound = 'upper' }))
end)
end)