neovim/test/unit/set.lua

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

143 lines
2.8 KiB
Lua
Raw Normal View History

2014-08-30 07:59:12 -07:00
-- a set class for fast union/diff, can always return a table with the lines
-- in the same relative order in which they were added by calling the
-- to_table method. It does this by keeping two lua tables that mirror each
-- other:
-- 1) index => item
-- 2) item => index
2023-04-03 04:01:23 -07:00
--- @class Set
--- @field nelem integer
--- @field items string[]
--- @field tbl table
2014-08-30 07:59:12 -07:00
local Set = {}
2023-04-03 04:01:23 -07:00
--- @param items? string[]
2014-08-30 07:59:12 -07:00
function Set:new(items)
local obj = {} --- @type Set
2014-08-30 07:59:12 -07:00
setmetatable(obj, self)
self.__index = self
if type(items) == 'table' then
local tempset = Set:new()
tempset:union_table(items)
obj.tbl = tempset:raw_tbl()
obj.items = tempset:raw_items()
obj.nelem = tempset:size()
else
obj.tbl = {}
obj.items = {}
obj.nelem = 0
end
return obj
end
2023-04-03 04:01:23 -07:00
--- @return Set
function Set:copy()
local obj = { nelem = self.nelem, tbl = {}, items = {} } --- @type Set
for k, v in pairs(self.tbl) do
obj.tbl[k] = v
end
for k, v in pairs(self.items) do
obj.items[k] = v
end
setmetatable(obj, Set)
obj.__index = Set
return obj
end
2014-08-30 07:59:12 -07:00
-- adds the argument Set to this Set
2023-04-03 04:01:23 -07:00
--- @param other Set
2014-08-30 07:59:12 -07:00
function Set:union(other)
for e in other:iterator() do
self:add(e)
end
end
-- adds the argument table to this Set
function Set:union_table(t)
for _, v in pairs(t) do
2014-08-30 07:59:12 -07:00
self:add(v)
end
end
-- subtracts the argument Set from this Set
2023-04-03 04:01:23 -07:00
--- @param other Set
2014-08-30 07:59:12 -07:00
function Set:diff(other)
if other:size() > self:size() then
-- this set is smaller than the other set
for e in self:iterator() do
if other:contains(e) then
self:remove(e)
end
end
else
-- this set is larger than the other set
for e in other:iterator() do
if self.items[e] then
self:remove(e)
end
end
end
end
2023-04-03 04:01:23 -07:00
--- @param it string
2014-08-30 07:59:12 -07:00
function Set:add(it)
if not self:contains(it) then
local idx = #self.tbl + 1
self.tbl[idx] = it
self.items[it] = idx
self.nelem = self.nelem + 1
end
end
2023-04-03 04:01:23 -07:00
--- @param it string
2014-08-30 07:59:12 -07:00
function Set:remove(it)
if self:contains(it) then
local idx = self.items[it]
self.tbl[idx] = nil
self.items[it] = nil
self.nelem = self.nelem - 1
end
end
2023-04-03 04:01:23 -07:00
--- @param it string
--- @return boolean
2014-08-30 07:59:12 -07:00
function Set:contains(it)
return self.items[it] or false
end
2023-04-03 04:01:23 -07:00
--- @return integer
2014-08-30 07:59:12 -07:00
function Set:size()
return self.nelem
end
function Set:raw_tbl()
return self.tbl
end
function Set:raw_items()
return self.items
end
function Set:iterator()
return pairs(self.items)
end
2023-04-03 04:01:23 -07:00
--- @return string[]
2014-08-30 07:59:12 -07:00
function Set:to_table()
-- there might be gaps in @tbl, so we have to be careful and sort first
2023-04-03 04:01:23 -07:00
local keys = {} --- @type string[]
for idx, _ in pairs(self.tbl) do
keys[#keys + 1] = idx
2014-08-30 07:59:12 -07:00
end
2023-04-03 04:01:23 -07:00
2014-08-30 07:59:12 -07:00
table.sort(keys)
2023-04-03 04:01:23 -07:00
local copy = {} --- @type string[]
for _, idx in ipairs(keys) do
copy[#copy + 1] = self.tbl[idx]
2014-08-30 07:59:12 -07:00
end
return copy
end
return Set