Module:OrderedDict

From Leaguepedia | League of Legends Esports Wiki
Jump to: navigation, search

Documentation for this module may be created at Module:OrderedDict/doc

local LCS = require('Module:LuaClassSystem')
local util_vars = require("Module:VarsUtil")
local util_sort = require("Module:SortUtil")

local OD = {}
local p = LCS.class()

-----------------------------------
-- ordered dict metatable
-----------------------------------
function OD.__ipairs(tbl)
	local function stateless_iter(tbl, i)
		-- Implement your own index, value selection logic
		i = i + 1
		local key = tbl[i]
		local val = tbl[key]
		if key ~= nil and val ~= nil then return i, key, val end
	end

	-- return iterator function, table, and starting point
	return stateless_iter, tbl, 0
end

-- function OD.__pairs(tbl)
-- 	error('Attempting to call pairs on an ordered dictionary')
-- end

function OD.__newindex(tbl, key, value)
	rawset(tbl, #tbl+1, key)
	rawset(tbl, key, value)
end

function OD.__index(tbl, key)
	if type(key) ~= 'number' then
		return rawget(tbl, key)
	end
	return rawget(tbl, key) -- , rawget(tbl, tbl[key])
end


-----------------------------------
-- class methods
-----------------------------------
function p:init()
	rawset(self, "_dict", {})
	rawset(self, "_hash", {})
	local function __newindex(tbl, key, value)
		tbl._dict[key] = value
	end
	getmetatable(self).__newindex = __newindex
	local function __ipairs(tbl)
		return ipairs(tbl._dict)
	end
	getmetatable(self).__ipairs = __ipairs
	setmetatable(self._dict, OD)
end

function p:concat(sep, f, ...)
	local tbl = {}
	for _, _, v in ipairs(self) do
		tbl[#tbl+1] = f and f(v, ...) or v
	end
	return table.concat(tbl, sep or ',')
end

function p:concatKeys(sep, f, ...)
	local tbl = {}
	for _, k, _ in ipairs(self) do
		tbl[#tbl+1] = f and f(k, ...) or k
	end
	return table.concat(tbl, sep or ',')
end

function p:formatAndConcat(sep, str)
	return self:concat(sep, function(val)
		return str:format(val)
	end)
end

function p:formatAndConcatKeys(sep, str)
	return self:concatKeys(sep, function(key)
		return str:format(key)
	end)
end

function p:get(key)
	return self._dict[key]
end

function p:set(key, val)
	self._dict[key] = val
	self._hash[key] = self._hash[key] or #self._dict
end

function p:mapRows(f, ...)
	for _, _, v in ipairs(self) do
		f(v, ...)
	end
end

function p:mapInPlace(f, ...)
	for i, k, v in ipairs(self) do
		self:set(k, f(i, k, v, ...))
	end
end

function p:removeKey(key)
	if not self._hash[key] then return end
	self._dict[key] = nil
	table.remove(self._dict, self._hash[key])
	for i = self._hash[key], #self._dict do
		self._hash[self:get(i)] = i
	end
	self._hash[key] = nil
end

function p:removeIndex(index)
	if not self._dict[key] then return end
	for i = index, #self._dict do
		self._hash[self:get(i)] = i
	end
	self._hash[index] = nil
	self._dict[self:get(index)] = nil
	table.remove(self._dict, index)
end

function p:toList()
	local ret = {}
	for i, _, v in ipairs(self._dict) do
		ret[i] = v
	end
	return ret
end

function p:toDict()
	local ret = {}
	for i, k, v in ipairs(self._dict) do
		ret[i] = k
		ret[k] = v
	end
	return ret
end

function p:sortByKeys(keys, increasing)
	util_sort.dictByKeys(self._dict, keys, increasing)
	for i, k, _ in ipairs(self._dict) do
		self._hash[k] = i
	end
end

return p