--===#### Set logic ####===--
-- Taken from http://lua-users.org/lists/lua-l/2008-07/msg00646.html
-- deepcompare taken from http://snippets.luacode.org/snippets/Deep_Comparison_of_Two_Values_3
-- Modified by SafPlusPlus with equality test

local function deepcompare(t1,t2,ignore_mt)
    local ty1 = type(t1)
    local ty2 = type(t2)
    if ty1 ~= ty2 then return false end
    -- non-table types can be directly compared
    if ty1 ~= 'table' and ty2 ~= 'table' then return t1 == t2 end
    -- as well as tables which have the metamethod __eq
    local mt = getmetatable(t1)
    if not ignore_mt and mt and mt.__eq then return t1 == t2 end
    for k1,v1 in pairs(t1) do
        local v2 = t2[k1]
        if v2 == nil or not deepcompare(v1,v2) then return false end
    end
    for k2,v2 in pairs(t2) do
        local v1 = t1[k2]
        if v1 == nil or not deepcompare(v1,v2) then return false end
    end
    return true
end

local pairs, setmetatable = pairs, setmetatable
local mt -- metatable
mt = {
  __add = function(s1, s2) -- union
    local s = {}
    for e in pairs(s1) do s[e] = true end
    for e in pairs(s2) do s[e] = true end
    return setmetatable(s, mt)
  end,
  __mul = function(s1, s2) -- intersection
    local s = {}
    for e in pairs(s1) do
      if s2[e] then s[e] = true end
    end
    return setmetatable(s, mt)
  end,
  __sub = function(s1, s2) -- set difference
    local s = {}
    for e in pairs(s1) do
      if not s2[e] then s[e] = true end
    end
    return setmetatable(s, mt)
  end,
  __eq = function(s1, s2) -- set equality
    -- inefficient little equality testing
    return deepcompare(s1,s2,true)
  end
}

local card = function(s) -- #elements
  local n = 0
  for k in pairs(s) do n = n + 1 end
  return n
end

Set = setmetatable({elements = pairs, card = card}, {
  __call = function(_, t) -- new set
    local t = t or {}
    local s = {}
    for _, e in pairs(t) do s[e] = true end
    return setmetatable(s, mt)
  end
})

--===#### end of Set logic ####===--