local v={}function v.Append(v,m)for m,u in pairs(m)do v[#v+1]=u end return v end function v.Merge(v,m)local u={}for v,m in pairs(v)do u[v]=m end for v,m in pairs(m)do u[v]=m end return u end function v.MergeLists(v,m)local u={}for v,m in pairs(v)do table.insert(u,m)end for v,m in pairs(m)do table.insert(u,m)end return u end function v.SwapKeyValue(v)local m={}for v,u in pairs(v)do m[u]=v end return m end function v.ToList(v)local m={}for v,u in pairs(v)do table.insert(m,u)end return m end function v.Count(v)local m=0 for v,u in pairs(v)do m=m+1 end return m end function v.Copy(v)local m={}for v,u in pairs(v)do m[v]=u end return m end local function m(v)if type(v)=="\116\097\098\108\101"then local u={}for v,q in pairs(v)do u[m(v)]=m(q)end return setmetatable(u,m(getmetatable(v)))else return v end end v.DeepCopy=m local function u(v,m)for m,q in pairs(m)do if type(v[m])=="\116\097\098\108\101"and type(q)=="\116\097\098\108\101"then v[m]=u(v[m],q)else v[m]=q end end return v end v.DeepOverwrite=u function v.GetIndex(v,m)for v,u in pairs(v)do if m==u then return v end end return nil end local function q(v,m,u)u=u or tostring(v)m=m or 0 for v,d in pairs(v)do local X="\n"..(string.rep("  ",m)..(tostring(v).."\058 "))if type(d)=="\116\097\098\108\101"then u=u..X u=q(d,v+1,u)else u=u..(X..tostring(d))end end return u end v.Stringify=q function v.Contains(v,m)for v,u in pairs(v)do if u==m then return true end end return false end function v.Overwrite(v,m)for m,u in pairs(m)do v[m]=u end return v end function v.ReadOnly(v)return setmetatable(v,{__index=function(v,m)error(("\066\097\100 \105\110\100\101\120 \037\113"):format(tostring(m)),2)end,__newindex=function(v,m,u)error(("\066\097\100 \105\110\100\101\120 \037\113"):format(tostring(m)),2)end})end function v.DeepReadOnly(m)for m,u in pairs(m)do if type(u)=="\116\097\098\108\101"then v.DeepReadOnly(u)end end return v.ReadOnly(m)end return v
--- Provide a variety of utility Table operations
-- @module Table

local lib = {}

--- Concats `target` with `source`
-- @tparam table target Table to append to
-- @tparam table source Table read from
-- @treturn table parameter table
function lib.Append(target, source)
	for _, value in pairs(source) do
		target[#target+1] = value
	end

	return target
end

--- Shallow merges two tables without modifying either
-- @tparam table orig original table
-- @tparam table new new table
-- @treturn table
function lib.Merge(orig, new)
	local tab = {}
	for key, val in pairs(orig) do
		tab[key] = val
	end
	for key, val in pairs(new) do
		tab[key] = val
	end
	return tab
end

--- Shallow merges two lists without modifying either
-- @tparam table orig original table
-- @tparam table new new table
-- @treturn table
function lib.MergeLists(orig, new)
	local tab = {}
	for _, val in pairs(orig) do
		table.insert(tab, val)
	end
	for _, val in pairs(new) do
		table.insert(tab, val)
	end
	return tab
end

--- Swaps keys with vvalues, overwriting additional values if duplicated
-- @tparam table orig original table
-- @treturn table
function lib.SwapKeyValue(orig)
	local tab = {}
	for key, val in pairs(orig) do
		tab[val] = key
	end
	return tab
end

--- Converts a table to a list
-- @tparam table tab Table to convert to a list
-- @treturn list
function lib.ToList(tab)
	local list = {}
	for _, item in pairs(tab) do
		table.insert(list, item)
	end
	return list
end

--- Counts the number of items in `tab`.
-- Useful since `__len` on table in Lua 5.2 returns just the array length.
-- @tparam table tab Table to count
-- @treturn number count
function lib.Count(tab)
	local count = 0
	for _, _ in pairs(tab) do
		count = count + 1
	end
	return count
end

--- Copies a table, but not deep.
-- @tparam table target Table to copy
-- @treturn table New table
function lib.Copy(target)
	local new = {}
	for key, value in pairs(target) do
		new[key] = value
	end
	return new
end

--- Deep copies a table including metatables
-- @function lib.DeepCopy
-- @tparam table table Table to deep copy
-- @treturn table New table
local function DeepCopy(target)
	if type(target) == "table" then
		local new = {}
		for index, value in pairs(target) do
			new[DeepCopy(index)] = DeepCopy(value)
		end
		return setmetatable(new, DeepCopy(getmetatable(target)))
	else
		return target
	end
end
lib.DeepCopy = DeepCopy

--- Overwrites a table's value
-- @function lib.DeepOverwrite
-- @tparam table target Target table
-- @tparam table source Table to read from
-- @treturn table target
local function DeepOverwrite(target, source)
	for index, value in pairs(source) do
		if type(target[index]) == "table" and type(value) == "table" then
			target[index] = DeepOverwrite(target[index], value)
		else
			target[index] = value
		end
	end
	return target
end
lib.DeepOverwrite = DeepOverwrite

--- Gets an index by value, returning `nil` if no index is found.
-- @tparam table haystack to search in
-- @param needle Value to search for
-- @return The index of the value, if found
-- @treturn nil if not found
function lib.GetIndex(haystack, needle)
	for index, item in pairs(haystack) do
		if needle == item then
			return index
		end
	end
	return nil
end

--- Recursively prints the table. Does not handle recursive tables.
-- @function lib.Stringify
-- @tparam table table Table to stringify
-- @tparam[opt=0] number indent Indent level
-- @tparam[opt=""] string output Output string, used recursively
-- @treturn string The table in string form
local function Stringify(table, indent, output)
	output = output or tostring(table)
	indent = indent or 0
	for Index, Value in pairs(table) do
		local FormattedText = "\n" .. string.rep("  ", indent) .. tostring(Index) .. ": "
		if type(Value) == "table" then
			output = output .. FormattedText
			output = Stringify(Value, Index + 1, output)
		else
			output = output .. FormattedText .. tostring(Value)
		end
	end
	return output
end
lib.Stringify = Stringify

--- Returns whether `value` is within `table`
-- @tparam table table to search in for value
-- @param value Value to search for
-- @treturn boolean `true` if within, `false` otherwise
function lib.Contains(table, value)
	for _, item in pairs(table) do
		if item == value then
			return true
		end
	end

	return false
end

--- Overwrites an existing table
-- @tparam table target Table to overwite
-- @tparam table source Source table to read from
-- @treturn table target
function lib.Overwrite(target, source)
	for index, item in pairs(source) do
		target[index] = item
	end

	return target
end

--- Sets a metatable on a table such that it errors when
-- indexing a nil value
-- @tparam table table Table to error on indexing
-- @treturn table table The same table
function lib.ReadOnly(table)
	return setmetatable(table, {
		__index = function(self, index)
			error(("Bad index %q"):format(tostring(index)), 2)
		end;
		__newindex = function(self, index, value)
			error(("Bad index %q"):format(tostring(index)), 2)
		end;
	})
end

--- Recursively sets the table as ReadOnly
-- @tparam table table Table to error on indexing
-- @treturn table table The same table
function lib.DeepReadOnly(table)
	for _, item in pairs(table) do
		if type(item) == "table" then
			lib.DeepReadOnly(item)
		end
	end

	return lib.ReadOnly(table)
end

return lib
