aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBruce Hill <bruce@bruce-hill.com>2019-02-02 19:31:40 -0800
committerBruce Hill <bruce@bruce-hill.com>2019-02-02 19:32:54 -0800
commit84f3ae76ab0d7d4d46871155a8c3608e0e710315 (patch)
tree3e4003bff70a55d3e54ef49fea4df345cdf5832c
parent11997f02552468d390c82b812d3800a97e7a8dac (diff)
Added inverse dicts and a few new list methods.
-rw-r--r--containers.lua172
-rw-r--r--containers.moon98
2 files changed, 260 insertions, 10 deletions
diff --git a/containers.lua b/containers.lua
index e706831..cd3e7c0 100644
--- a/containers.lua
+++ b/containers.lua
@@ -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 = { }
diff --git a/containers.moon b/containers.moon
index 6fa9ecb..06fbccc 100644
--- a/containers.moon
+++ b/containers.moon
@@ -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)