123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143 |
- -- 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
- --- @class Set
- --- @field nelem integer
- --- @field items string[]
- --- @field tbl table
- local Set = {}
- --- @param items? string[]
- function Set:new(items)
- local obj = {} --- @type Set
- 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
- --- @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
- -- adds the argument Set to this Set
- --- @param other Set
- 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
- self:add(v)
- end
- end
- -- subtracts the argument Set from this Set
- --- @param other Set
- 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
- --- @param it string
- 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
- --- @param it string
- 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
- --- @param it string
- --- @return boolean
- function Set:contains(it)
- return self.items[it] or false
- end
- --- @return integer
- 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
- --- @return string[]
- function Set:to_table()
- -- there might be gaps in @tbl, so we have to be careful and sort first
- local keys = {} --- @type string[]
- for idx, _ in pairs(self.tbl) do
- keys[#keys + 1] = idx
- end
- table.sort(keys)
- local copy = {} --- @type string[]
- for _, idx in ipairs(keys) do
- copy[#copy + 1] = self.tbl[idx]
- end
- return copy
- end
- return Set
|