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)
|
2023-08-09 02:06:13 -07:00
|
|
|
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
|
2017-03-11 17:02:14 -07:00
|
|
|
function Set:copy()
|
2023-08-09 02:06:13 -07:00
|
|
|
local obj = {nelem = self.nelem, tbl = {}, items = {}} --- @type Set
|
2017-03-11 17:02:14 -07:00
|
|
|
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)
|
2015-11-17 07:49:12 -07:00
|
|
|
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
|