Added inverse dicts and a few new list methods.

This commit is contained in:
Bruce Hill 2019-02-02 19:31:40 -08:00
parent 11997f0255
commit 84f3ae76ab
2 changed files with 260 additions and 10 deletions

View File

@ -1,4 +1,4 @@
local List, Dict
local List, Dict, Undict, _undict_mt, _dict_mt
local insert, remove, concat
do
local _obj_0 = table
@ -226,6 +226,23 @@ local _list_mt = {
return _accum_0
end)())
end,
copy = function(self)
return List((function()
local _accum_0 = { }
local _len_0 = 1
for i = 1, #self do
_accum_0[_len_0] = self[i]
_len_0 = _len_0 + 1
end
return _accum_0
end)())
end,
reverse = function(self)
local n = #self
for i = 1, math.floor(n / 2) do
self[i], self[n - i + 1] = self[n - i + 1], self[i]
end
end,
reversed = function(self)
return List((function()
local _accum_0 = { }
@ -236,6 +253,49 @@ local _list_mt = {
end
return _accum_0
end)())
end,
sort = function(self)
return table.sort(self)
end,
sort_by = function(self, fn)
local keys = setmetatable({ }, {
__index = function(self, k)
local key = fn(k)
self[k] = key
return key
end
})
return table.sort(self, function(a, b)
return keys[a] <= keys[b]
end)
end,
sorted = function(self)
local c = self:copy()
c:sort()
return c
end,
sorted_by = function(self, fn)
local c = self:copy()
c:sort_by(fn)
return c
end,
filter_by = function(self, keep)
local deleted = 0
for i = 1, #self do
if not (keep(self[i])) then
deleted = deleted + 1
elseif deleted > 0 then
self[i - deleted] = self[i]
end
end
for i = #self - deleted + 1, #self do
self[i] = nil
end
end,
filtered_by = function(self, keep)
local c = self:copy()
c:filter_by(keep)
return c
end
},
__newindex = function(self, k, v)
@ -262,7 +322,91 @@ List = function(t)
return error("Unsupported List type: " .. type(t))
end
end
local _dict_mt = {
local compliments = setmetatable({ }, {
__mode = 'k'
})
_undict_mt = {
__index = function(self, k)
return not compliments[self][k] and true or nil
end,
__newindex = function(self, k, v)
if k then
compliments[self][k] = nil
else
compliments[self][k] = true
end
end,
__eq = function(self, other)
if not (type(other) == 'table' and getmetatable(other) == getmetatable(self)) then
return false
end
return compliments[self] == compliments[other]
end,
__len = function(self)
return math.huge
end,
__tostring = function(self)
return "~" .. _dict_mt.__tostring(compliments[self])
end,
as_nomsu = function(self)
return "~" .. _dict_mt.as_nomsu(compliments[self])
end,
as_lua = function(self)
return "~" .. __dict_mt.as_lua(compliments[self])
end,
__band = function(self, other)
if getmetatable(other) == _undict_mt then
return Undict(_dict_mt.__bor(compliments[self], compliments[other]))
else
return _dict_mt.__band(other, self)
end
end,
__bor = function(self, other)
if getmetatable(other) == _undict_mt then
return Undict(_dict_mt.__band(compliments[self], compliments[other]))
else
return Undict((function()
local _tbl_0 = { }
for k, v in pairs(compliments[self]) do
if not other[k] then
_tbl_0[k] = v
end
end
return _tbl_0
end)())
end
end,
__bxor = function(self, other)
if getmetatable(other) == _undict_mt then
return _dict_mt.__bxor(compliments[self], compliments[other])
else
return Undict(_dict_mt.__band(other, self))
end
end,
__bnot = function(self)
return Dict((function()
local _tbl_0 = { }
for k, v in pairs(compliments[self]) do
_tbl_0[k] = v
end
return _tbl_0
end)())
end
}
Undict = function(d)
local u = setmetatable({ }, _undict_mt)
compliments[u] = Dict((function()
local _tbl_0 = { }
for k, v in pairs(d) do
if v then
_tbl_0[k] = true
end
end
return _tbl_0
end)())
return u
end
_dict_mt = {
__type = "a Dict",
__eq = function(self, other)
if not (type(other) == 'table' and getmetatable(other) == getmetatable(self)) then
@ -292,7 +436,7 @@ local _dict_mt = {
local _accum_0 = { }
local _len_0 = 1
for k, v in pairs(self) do
_accum_0[_len_0] = "." .. tostring(k) .. " = " .. tostring(v)
_accum_0[_len_0] = v == true and "." .. as_nomsu(k) or "." .. tostring(k) .. " = " .. tostring(v)
_len_0 = _len_0 + 1
end
return _accum_0
@ -303,7 +447,7 @@ local _dict_mt = {
local _accum_0 = { }
local _len_0 = 1
for k, v in pairs(self) do
_accum_0[_len_0] = "." .. tostring(as_nomsu(k)) .. " = " .. tostring(as_nomsu(v))
_accum_0[_len_0] = v == true and "." .. as_nomsu(k) or "." .. tostring(as_nomsu(k)) .. " = " .. tostring(as_nomsu(v))
_len_0 = _len_0 + 1
end
return _accum_0
@ -320,11 +464,22 @@ local _dict_mt = {
return _accum_0
end)(), ", ") .. "}"
end,
as_list = function(self)
return List((function()
local _accum_0 = { }
local _len_0 = 1
for k, v in pairs(self) do
_accum_0[_len_0] = k
_len_0 = _len_0 + 1
end
return _accum_0
end)())
end,
__band = function(self, other)
return Dict((function()
local _tbl_0 = { }
for k, v in pairs(self) do
if other[k] ~= nil then
if other[k] then
_tbl_0[k] = v
end
end
@ -332,6 +487,9 @@ local _dict_mt = {
end)())
end,
__bor = function(self, other)
if getmetatable(other) == _undict_mt then
return _undict_mt.__bor(other, self)
end
local ret = Dict((function()
local _tbl_0 = { }
for k, v in pairs(self) do
@ -347,6 +505,9 @@ local _dict_mt = {
return ret
end,
__bxor = function(self, other)
if getmetatable(other) == _undict_mt then
return _undict_mt.__bxor(other, self)
end
local ret = Dict((function()
local _tbl_0 = { }
for k, v in pairs(self) do
@ -363,6 +524,7 @@ local _dict_mt = {
end
return ret
end,
__bnot = Undict,
__add = function(self, other)
local ret = Dict((function()
local _tbl_0 = { }

View File

@ -1,5 +1,5 @@
-- This file contains container classes, i.e. Lists and Dicts, plus some extended string functionality
local List, Dict
local List, Dict, Undict, _undict_mt, _dict_mt
{:insert,:remove,:concat} = table
as_nomsu = =>
@ -88,8 +88,42 @@ _list_mt =
start = (n+1-start) if start < 0
stop = (n+1-stop) if stop < 0
return List[@[i] for i=start,stop]
copy: => List[@[i] for i=1,#@]
reverse: =>
n = #@
for i=1,math.floor(n/2)
@[i], @[n-i+1] = @[n-i+1], @[i]
reversed: => List[@[i] for i=#@,1,-1]
sort: => table.sort(@)
sort_by: (fn)=>
keys = setmetatable {},
__index: (k)=>
key = fn(k)
@[k] = key
return key
table.sort(@, (a,b)->keys[a] <= keys[b])
sorted: =>
c = @copy!
c\sort!
return c
sorted_by: (fn)=>
c = @copy!
c\sort_by(fn)
return c
filter_by: (keep)=>
deleted = 0
for i=1,#@
unless keep(@[i])
deleted += 1
elseif deleted > 0
@[i-deleted] = @[i]
for i=#@-deleted+1,#@
@[i] = nil
filtered_by: (keep)=>
c = @copy!
c\filter_by(keep)
return c
-- TODO: remove this safety check to get better performance?
__newindex: (k,v)=>
@ -109,6 +143,52 @@ List = (t)->
return l
else error("Unsupported List type: "..type(t))
compliments = setmetatable({}, {__mode:'k'})
_undict_mt =
__type: "an Inverse Dict"
__index: (k)=> not compliments[@][k] and true or nil
__newindex: (k,v)=>
if k
compliments[@][k] = nil
else
compliments[@][k] = true
__eq: (other)=>
unless type(other) == 'table' and getmetatable(other) == getmetatable(@)
return false
return compliments[@] == compliments[other]
__len: => math.huge
__tostring: => "~".._dict_mt.__tostring(compliments[@])
as_nomsu: => "~".._dict_mt.as_nomsu(compliments[@])
as_lua: => "~"..__dict_mt.as_lua(compliments[@])
__band: (other)=>
if getmetatable(other) == _undict_mt
-- ~{x,y} & ~{y,z} == ~{x,y,z} == ~({x,y} | {y,z})
Undict(_dict_mt.__bor(compliments[@], compliments[other]))
else
-- ~{x,y} & {y,z} == {z} == {y,z} & ~{x,y}
_dict_mt.__band(other, @)
__bor: (other)=>
if getmetatable(other) == _undict_mt
-- ~{x,y} | ~{y,z} == ~{y} = ~({x,y} & {y,z})
Undict(_dict_mt.__band(compliments[@], compliments[other]))
else
-- ~{x,y} | {y,z} == ~{z} = ~({y,z} & ~{x,y})
Undict{k,v for k,v in pairs(compliments[@]) when not other[k]}
__bxor: (other)=>
if getmetatable(other) == _undict_mt
-- ~{x,y} ^ ~{y,z} == {x,z} = {x,y} ^ {y,z}
_dict_mt.__bxor(compliments[@], compliments[other])
else
-- ~{x,y} ^ {y,z} == ~{x} = ~({x,y} & ~{y,z})
Undict(_dict_mt.__band(other, @))
__bnot: => Dict{k,v for k,v in pairs(compliments[@])}
Undict = (d)->
u = setmetatable({}, _undict_mt)
compliments[u] = Dict{k,true for k,v in pairs(d) when v}
return u
_dict_mt =
__type: "a Dict"
__eq: (other)=>
@ -124,24 +204,31 @@ _dict_mt =
for _ in pairs(@) do n += 1
return n
__tostring: =>
"{"..concat([".#{k} = #{v}" for k,v in pairs @], ", ").."}"
"{"..concat([v == true and "."..as_nomsu(k) or ".#{k} = #{v}" for k,v in pairs @], ", ").."}"
as_nomsu: =>
"{"..concat([".#{as_nomsu(k)} = #{as_nomsu(v)}" for k,v in pairs @], ", ").."}"
"{"..concat([v == true and "."..as_nomsu(k) or ".#{as_nomsu(k)} = #{as_nomsu(v)}" for k,v in pairs @], ", ").."}"
as_lua: =>
"a_Dict{"..concat(["[ #{as_lua(k)}]= #{as_lua(v)}" for k,v in pairs @], ", ").."}"
as_list: => List[k for k,v in pairs(@)]
__band: (other)=>
Dict{k,v for k,v in pairs(@) when other[k] != nil}
Dict{k,v for k,v in pairs(@) when other[k]}
__bor: (other)=>
if getmetatable(other) == _undict_mt
return _undict_mt.__bor(other, @)
ret = Dict{k,v for k,v in pairs(@)}
for k,v in pairs(other)
if ret[k] == nil then ret[k] = v
return ret
__bxor: (other)=>
if getmetatable(other) == _undict_mt
return _undict_mt.__bxor(other, @)
ret = Dict{k,v for k,v in pairs(@)}
for k,v in pairs(other)
if ret[k] == nil then ret[k] = v
else ret[k] = nil
return ret
__bnot: Undict
__add: (other)=>
ret = Dict{k,v for k,v in pairs(@)}
for k,v in pairs(other)
@ -154,6 +241,7 @@ _dict_mt =
if ret[k] == nil then ret[k] = -v
else ret[k] -= v
return ret
Dict = (t)->
if type(t) == 'table'
return setmetatable(t, _dict_mt)