summaryrefslogtreecommitdiff
path: root/macros/luatex/generic/penlight/pl/Map.lua
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/generic/penlight/pl/Map.lua')
-rw-r--r--macros/luatex/generic/penlight/pl/Map.lua120
1 files changed, 120 insertions, 0 deletions
diff --git a/macros/luatex/generic/penlight/pl/Map.lua b/macros/luatex/generic/penlight/pl/Map.lua
new file mode 100644
index 0000000000..572b22ad0b
--- /dev/null
+++ b/macros/luatex/generic/penlight/pl/Map.lua
@@ -0,0 +1,120 @@
+--- A Map class.
+--
+-- > Map = require 'pl.Map'
+-- > m = Map{one=1,two=2}
+-- > m:update {three=3,four=4,two=20}
+-- > = m == M{one=1,two=20,three=3,four=4}
+-- true
+--
+-- Dependencies: `pl.utils`, `pl.class`, `pl.tablex`, `pl.pretty`
+-- @classmod pl.Map
+
+local tablex = require 'pl.tablex'
+local utils = require 'pl.utils'
+local stdmt = utils.stdmt
+local deepcompare = tablex.deepcompare
+
+local pretty_write = require 'pl.pretty' . write
+local Map = stdmt.Map
+local Set = stdmt.Set
+
+local class = require 'pl.class'
+
+-- the Map class ---------------------
+class(nil,nil,Map)
+
+function Map:_init (t)
+ local mt = getmetatable(t)
+ if mt == Set or mt == Map then
+ self:update(t)
+ else
+ return t -- otherwise assumed to be a map-like table
+ end
+end
+
+
+local function makelist(t)
+ return setmetatable(t, require('pl.List'))
+end
+
+--- list of keys.
+Map.keys = tablex.keys
+
+--- list of values.
+Map.values = tablex.values
+
+--- return an iterator over all key-value pairs.
+function Map:iter ()
+ return pairs(self)
+end
+
+--- return a List of all key-value pairs, sorted by the keys.
+function Map:items()
+ local ls = makelist(tablex.pairmap (function (k,v) return makelist {k,v} end, self))
+ ls:sort(function(t1,t2) return t1[1] < t2[1] end)
+ return ls
+end
+
+--- set a value in the map if it doesn't exist yet.
+-- @param key the key
+-- @param default value to set
+-- @return the value stored in the map (existing value, or the new value)
+function Map:setdefault(key, default)
+ local val = self[key]
+ if val ~= nil then
+ return val
+ end
+ self:set(key,default)
+ return default
+end
+
+--- size of map.
+-- note: this is a relatively expensive operation!
+-- @class function
+-- @name Map:len
+Map.len = tablex.size
+
+--- put a value into the map.
+-- This will remove the key if the value is `nil`
+-- @param key the key
+-- @param val the value
+function Map:set (key,val)
+ self[key] = val
+end
+
+--- get a value from the map.
+-- @param key the key
+-- @return the value, or nil if not found.
+function Map:get (key)
+ return rawget(self,key)
+end
+
+local index_by = tablex.index_by
+
+--- get a list of values indexed by a list of keys.
+-- @param keys a list-like table of keys
+-- @return a new list
+function Map:getvalues (keys)
+ return makelist(index_by(self,keys))
+end
+
+--- update the map using key/value pairs from another table.
+-- @tab table
+-- @function Map:update
+Map.update = tablex.update
+
+--- equality between maps.
+-- @within metamethods
+-- @tparam Map m another map.
+function Map:__eq (m)
+ -- note we explicitly ask deepcompare _not_ to use __eq!
+ return deepcompare(self,m,true)
+end
+
+--- string representation of a map.
+-- @within metamethods
+function Map:__tostring ()
+ return pretty_write(self,'')
+end
+
+return Map